aboutsummaryrefslogtreecommitdiff
path: root/core/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/main')
-rw-r--r--core/src/main/kotlin/Analysis/AnalysisEnvironment.kt4
-rw-r--r--core/src/main/kotlin/DokkaBootstrapImpl.kt9
-rw-r--r--core/src/main/kotlin/Formats/GFMFormatService.kt21
-rw-r--r--core/src/main/kotlin/Formats/HtmlFormatService.kt9
-rw-r--r--core/src/main/kotlin/Formats/JekyllFormatService.kt18
-rw-r--r--core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt26
-rw-r--r--core/src/main/kotlin/Formats/MarkdownFormatService.kt15
-rw-r--r--core/src/main/kotlin/Formats/StructuredFormatService.kt55
-rw-r--r--core/src/main/kotlin/Generation/DokkaGenerator.kt76
-rw-r--r--core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt4
-rw-r--r--core/src/main/kotlin/Java/JavadocParser.kt7
-rw-r--r--core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt2
-rw-r--r--core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt2
-rw-r--r--core/src/main/kotlin/Kotlin/DocumentationBuilder.kt227
-rw-r--r--core/src/main/kotlin/Kotlin/KotlinLanguageService.kt62
-rw-r--r--core/src/main/kotlin/Model/DocumentationNode.kt4
-rw-r--r--core/src/main/kotlin/Model/DocumentationReference.kt23
-rw-r--r--core/src/main/kotlin/Utilities/DokkaModules.kt (renamed from core/src/main/kotlin/Utilities/DokkaModule.kt)60
18 files changed, 444 insertions, 180 deletions
diff --git a/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt b/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt
index 3f7f616f..15d0a26b 100644
--- a/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt
+++ b/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.CompilerEnvironment
+import org.jetbrains.kotlin.resolve.MultiTargetPlatform
import org.jetbrains.kotlin.resolve.jvm.JvmAnalyzerFacade
import org.jetbrains.kotlin.resolve.jvm.JvmPlatformParameters
import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM
@@ -133,7 +134,8 @@ class AnalysisEnvironment(val messageCollector: MessageCollector) : Disposable {
info, content ->
JvmPackagePartProvider(environment, content.moduleContentScope)
},
- builtIns = builtIns
+ builtIns = { builtIns },
+ modulePlatforms = { MultiTargetPlatform.Specific("JVM") }
)
resolverForProject.resolverForModule(library) // Required before module to initialize library properly
diff --git a/core/src/main/kotlin/DokkaBootstrapImpl.kt b/core/src/main/kotlin/DokkaBootstrapImpl.kt
index eb2b2a65..8038089f 100644
--- a/core/src/main/kotlin/DokkaBootstrapImpl.kt
+++ b/core/src/main/kotlin/DokkaBootstrapImpl.kt
@@ -10,6 +10,11 @@ fun parseSourceLinkDefinition(srcLink: String): SourceLinkDefinition {
urlAndLine.substringAfter("#", "").let { if (it.isEmpty()) null else "#" + it })
}
+fun parseSourceRoot(sourceRoot: String): SourceRoot {
+ val components = sourceRoot.split("::", limit = 2)
+ return SourceRoot(components.last(), if (components.size == 1) listOf() else components[0].split(','))
+}
+
class DokkaBootstrapImpl : DokkaBootstrap {
class DokkaProxyLogger(val consumer: BiConsumer<String, String>) : DokkaLogger {
@@ -37,6 +42,7 @@ class DokkaBootstrapImpl : DokkaBootstrap {
outputDir: String,
format: String,
includeNonPublic: Boolean,
+ includeRootPackage: Boolean,
reportUndocumented: Boolean,
skipEmptyPackages: Boolean,
skipDeprecated: Boolean,
@@ -46,7 +52,7 @@ class DokkaBootstrapImpl : DokkaBootstrap {
generator = DokkaGenerator(
DokkaProxyLogger(logger),
classpath,
- sources,
+ sources.map(::parseSourceRoot),
samples,
includes,
moduleName,
@@ -54,6 +60,7 @@ class DokkaBootstrapImpl : DokkaBootstrap {
outputDir,
format,
includeNonPublic,
+ includeRootPackage,
reportUndocumented,
skipEmptyPackages,
skipDeprecated,
diff --git a/core/src/main/kotlin/Formats/GFMFormatService.kt b/core/src/main/kotlin/Formats/GFMFormatService.kt
index cfb7fc03..cb31a1d3 100644
--- a/core/src/main/kotlin/Formats/GFMFormatService.kt
+++ b/core/src/main/kotlin/Formats/GFMFormatService.kt
@@ -3,11 +3,12 @@ package org.jetbrains.dokka
import com.google.inject.Inject
open class GFMOutputBuilder(to: StringBuilder,
- location: Location,
- locationService: LocationService,
- languageService: LanguageService,
- extension: String)
- : MarkdownOutputBuilder(to, location, locationService, languageService, extension)
+ location: Location,
+ locationService: LocationService,
+ languageService: LanguageService,
+ extension: String,
+ impliedPlatforms: List<String>)
+ : MarkdownOutputBuilder(to, location, locationService, languageService, extension, impliedPlatforms)
{
override fun appendTable(vararg columns: String, body: () -> Unit) {
to.appendln(columns.joinToString(" | ", "| ", " |"))
@@ -45,12 +46,14 @@ open class GFMOutputBuilder(to: StringBuilder,
open class GFMFormatService(locationService: LocationService,
signatureGenerator: LanguageService,
- linkExtension: String)
-: MarkdownFormatService(locationService, signatureGenerator, linkExtension) {
+ linkExtension: String,
+ impliedPlatforms: List<String>)
+: MarkdownFormatService(locationService, signatureGenerator, linkExtension, impliedPlatforms) {
@Inject constructor(locationService: LocationService,
- signatureGenerator: LanguageService) : this(locationService, signatureGenerator, "md")
+ signatureGenerator: LanguageService,
+ impliedPlatforms: List<String>) : this(locationService, signatureGenerator, "md", impliedPlatforms)
override fun createOutputBuilder(to: StringBuilder, location: Location): FormattedOutputBuilder =
- GFMOutputBuilder(to, location, locationService, languageService, extension)
+ GFMOutputBuilder(to, location, locationService, languageService, extension, impliedPlatforms)
}
diff --git a/core/src/main/kotlin/Formats/HtmlFormatService.kt b/core/src/main/kotlin/Formats/HtmlFormatService.kt
index d73e4e62..6819e652 100644
--- a/core/src/main/kotlin/Formats/HtmlFormatService.kt
+++ b/core/src/main/kotlin/Formats/HtmlFormatService.kt
@@ -2,6 +2,7 @@ package org.jetbrains.dokka
import com.google.inject.Inject
import com.google.inject.name.Named
+import org.jetbrains.dokka.Utilities.impliedPlatformsName
import java.io.File
import java.nio.file.Path
import java.nio.file.Paths
@@ -11,8 +12,9 @@ open class HtmlOutputBuilder(to: StringBuilder,
locationService: LocationService,
languageService: LanguageService,
extension: String,
+ impliedPlatforms: List<String>,
val templateService: HtmlTemplateService)
- : StructuredOutputBuilder(to, location, locationService, languageService, extension)
+ : StructuredOutputBuilder(to, location, locationService, languageService, extension, impliedPlatforms)
{
override fun appendText(text: String) {
to.append(text.htmlEscape())
@@ -95,7 +97,8 @@ open class HtmlOutputBuilder(to: StringBuilder,
open class HtmlFormatService @Inject constructor(@Named("folders") locationService: LocationService,
signatureGenerator: LanguageService,
- val templateService: HtmlTemplateService)
+ val templateService: HtmlTemplateService,
+ @Named(impliedPlatformsName) val impliedPlatforms: List<String>)
: StructuredFormatService(locationService, signatureGenerator, "html"), OutlineFormatService {
override fun enumerateSupportFiles(callback: (String, String) -> Unit) {
@@ -103,7 +106,7 @@ open class HtmlFormatService @Inject constructor(@Named("folders") locationServi
}
override fun createOutputBuilder(to: StringBuilder, location: Location) =
- HtmlOutputBuilder(to, location, locationService, languageService, extension, templateService)
+ HtmlOutputBuilder(to, location, locationService, languageService, extension, impliedPlatforms, templateService)
override fun appendOutline(location: Location, to: StringBuilder, nodes: Iterable<DocumentationNode>) {
templateService.appendHeader(to, "Module Contents", locationService.calcPathToRoot(location))
diff --git a/core/src/main/kotlin/Formats/JekyllFormatService.kt b/core/src/main/kotlin/Formats/JekyllFormatService.kt
index bab73379..d217bf38 100644
--- a/core/src/main/kotlin/Formats/JekyllFormatService.kt
+++ b/core/src/main/kotlin/Formats/JekyllFormatService.kt
@@ -1,13 +1,16 @@
package org.jetbrains.dokka
import com.google.inject.Inject
+import com.google.inject.name.Named
+import org.jetbrains.dokka.Utilities.impliedPlatformsName
open class JekyllOutputBuilder(to: StringBuilder,
location: Location,
locationService: LocationService,
languageService: LanguageService,
- extension: String)
- : MarkdownOutputBuilder(to, location, locationService, languageService, extension)
+ extension: String,
+ impliedPlatforms: List<String>)
+ : MarkdownOutputBuilder(to, location, locationService, languageService, extension, impliedPlatforms)
{
override fun appendNodes(nodes: Iterable<DocumentationNode>) {
to.appendln("---")
@@ -25,14 +28,15 @@ open class JekyllOutputBuilder(to: StringBuilder,
open class JekyllFormatService(locationService: LocationService,
signatureGenerator: LanguageService,
- linkExtension: String)
-: MarkdownFormatService(locationService, signatureGenerator, linkExtension) {
+ linkExtension: String,
+ impliedPlatforms: List<String>)
+: MarkdownFormatService(locationService, signatureGenerator, linkExtension, impliedPlatforms) {
@Inject constructor(locationService: LocationService,
- signatureGenerator: LanguageService): this(locationService, signatureGenerator, "md") {
- }
+ signatureGenerator: LanguageService,
+ @Named(impliedPlatformsName) impliedPlatforms: List<String>): this(locationService, signatureGenerator, "md", impliedPlatforms)
override fun createOutputBuilder(to: StringBuilder, location: Location): FormattedOutputBuilder =
- JekyllOutputBuilder(to, location, locationService, languageService, extension)
+ JekyllOutputBuilder(to, location, locationService, languageService, extension, impliedPlatforms)
}
diff --git a/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt b/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt
index 9a43f9c4..7ebc5f09 100644
--- a/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt
+++ b/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt
@@ -1,14 +1,17 @@
package org.jetbrains.dokka
import com.google.inject.Inject
+import com.google.inject.name.Named
+import org.jetbrains.dokka.Utilities.impliedPlatformsName
open class KotlinWebsiteOutputBuilder(to: StringBuilder,
location: Location,
locationService: LocationService,
languageService: LanguageService,
- extension: String)
- : JekyllOutputBuilder(to, location, locationService, languageService, extension)
+ extension: String,
+ impliedPlatforms: List<String>)
+ : JekyllOutputBuilder(to, location, locationService, languageService, extension, impliedPlatforms)
{
private var needHardLineBreaks = false
private var insideDiv = 0
@@ -145,11 +148,12 @@ open class KotlinWebsiteOutputBuilder(to: StringBuilder,
}
class KotlinWebsiteFormatService @Inject constructor(locationService: LocationService,
- signatureGenerator: LanguageService)
- : JekyllFormatService(locationService, signatureGenerator, "html")
+ signatureGenerator: LanguageService,
+ @Named(impliedPlatformsName) impliedPlatforms: List<String>)
+ : JekyllFormatService(locationService, signatureGenerator, "html", impliedPlatforms)
{
override fun createOutputBuilder(to: StringBuilder, location: Location) =
- KotlinWebsiteOutputBuilder(to, location, locationService, languageService, extension)
+ KotlinWebsiteOutputBuilder(to, location, locationService, languageService, extension, impliedPlatforms)
}
@@ -157,8 +161,9 @@ class KotlinWebsiteRunnableSamplesOutputBuilder(to: StringBuilder,
location: Location,
locationService: LocationService,
languageService: LanguageService,
- extension: String)
- : KotlinWebsiteOutputBuilder(to, location, locationService, languageService, extension) {
+ extension: String,
+ impliedPlatforms: List<String>)
+ : KotlinWebsiteOutputBuilder(to, location, locationService, languageService, extension, impliedPlatforms) {
override fun appendSampleBlockCode(language: String, imports: () -> Unit, body: () -> Unit) {
div(to, "sample", true) {
@@ -173,9 +178,10 @@ class KotlinWebsiteRunnableSamplesOutputBuilder(to: StringBuilder,
}
class KotlinWebsiteRunnableSamplesFormatService @Inject constructor(locationService: LocationService,
- signatureGenerator: LanguageService)
- : JekyllFormatService(locationService, signatureGenerator, "html") {
+ signatureGenerator: LanguageService,
+ @Named(impliedPlatformsName) impliedPlatforms: List<String>)
+ : JekyllFormatService(locationService, signatureGenerator, "html", impliedPlatforms) {
override fun createOutputBuilder(to: StringBuilder, location: Location) =
- KotlinWebsiteRunnableSamplesOutputBuilder(to, location, locationService, languageService, extension)
+ KotlinWebsiteRunnableSamplesOutputBuilder(to, location, locationService, languageService, extension, impliedPlatforms)
}
diff --git a/core/src/main/kotlin/Formats/MarkdownFormatService.kt b/core/src/main/kotlin/Formats/MarkdownFormatService.kt
index fc63b2f2..b9c9c04f 100644
--- a/core/src/main/kotlin/Formats/MarkdownFormatService.kt
+++ b/core/src/main/kotlin/Formats/MarkdownFormatService.kt
@@ -1,6 +1,8 @@
package org.jetbrains.dokka
import com.google.inject.Inject
+import com.google.inject.name.Named
+import org.jetbrains.dokka.Utilities.impliedPlatformsName
import java.util.*
enum class ListKind {
@@ -14,8 +16,9 @@ open class MarkdownOutputBuilder(to: StringBuilder,
location: Location,
locationService: LocationService,
languageService: LanguageService,
- extension: String)
- : StructuredOutputBuilder(to, location, locationService, languageService, extension)
+ extension: String,
+ impliedPlatforms: List<String>)
+ : StructuredOutputBuilder(to, location, locationService, languageService, extension, impliedPlatforms)
{
private val listKindStack = Stack<ListKind>()
protected var inTableCell = false
@@ -211,11 +214,13 @@ open class MarkdownOutputBuilder(to: StringBuilder,
open class MarkdownFormatService(locationService: LocationService,
signatureGenerator: LanguageService,
- linkExtension: String)
+ linkExtension: String,
+ val impliedPlatforms: List<String>)
: StructuredFormatService(locationService, signatureGenerator, "md", linkExtension) {
@Inject constructor(locationService: LocationService,
- signatureGenerator: LanguageService): this(locationService, signatureGenerator, "md")
+ signatureGenerator: LanguageService,
+ @Named(impliedPlatformsName) impliedPlatforms: List<String>): this(locationService, signatureGenerator, "md", impliedPlatforms)
override fun createOutputBuilder(to: StringBuilder, location: Location): FormattedOutputBuilder =
- MarkdownOutputBuilder(to, location, locationService, languageService, extension)
+ MarkdownOutputBuilder(to, location, locationService, languageService, extension, impliedPlatforms)
}
diff --git a/core/src/main/kotlin/Formats/StructuredFormatService.kt b/core/src/main/kotlin/Formats/StructuredFormatService.kt
index 7896bcd8..3cfc96a2 100644
--- a/core/src/main/kotlin/Formats/StructuredFormatService.kt
+++ b/core/src/main/kotlin/Formats/StructuredFormatService.kt
@@ -1,6 +1,7 @@
package org.jetbrains.dokka
import org.jetbrains.dokka.LanguageService.RenderMode
+import org.jetbrains.kotlin.utils.ifEmpty
import java.util.*
data class FormatLink(val text: String, val href: String)
@@ -9,7 +10,8 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
val location: Location,
val locationService: LocationService,
val languageService: LanguageService,
- val extension: String) : FormattedOutputBuilder {
+ val extension: String,
+ val impliedPlatforms: List<String>) : FormattedOutputBuilder {
protected fun wrap(prefix: String, suffix: String, body: () -> Unit) {
to.append(prefix)
@@ -59,6 +61,13 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
abstract fun appendText(text: String)
+ open fun appendSinceKotlin(version: String) {
+ appendParagraph {
+ appendText("Available since Kotlin: ")
+ appendCode { appendText(version) }
+ }
+ }
+
open fun appendSymbol(text: String) {
appendText(text)
}
@@ -284,12 +293,14 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
}
item.appendOverrides()
item.appendDeprecation()
+ item.appendPlatforms()
}
// All items have exactly the same documentation, so we can use any item to render it
val item = items.first()
item.details(NodeKind.OverloadGroupNote).forEach {
appendContent(it.content)
}
+
appendContent(item.content.summary)
item.appendDescription()
}
@@ -334,6 +345,17 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
}
}
+ private fun DocumentationNode.appendPlatforms() {
+ val platforms = platformsToShow.ifEmpty { return }
+ appendParagraph {
+ appendStrong { to.append("Platform and version requirements:") }
+ to.append(" " + platforms.joinToString())
+ }
+ }
+
+ val DocumentationNode.platformsToShow: List<String>
+ get() = platforms.let { if (it.containsAll(impliedPlatforms)) it - impliedPlatforms else it }
+
private fun DocumentationNode.appendDescription() {
if (content.description != ContentEmpty) {
appendContent(content.description)
@@ -384,15 +406,15 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
appendSection("Exceptions", node.members(NodeKind.Exception))
appendSection("Type Aliases", node.members(NodeKind.TypeAlias))
appendSection("Extensions for External Classes", node.members(NodeKind.ExternalClass))
- appendSection("Enum Values", node.members(NodeKind.EnumItem), sortMembers = false)
- appendSection("Constructors", node.members(NodeKind.Constructor))
- appendSection("Properties", node.members(NodeKind.Property))
+ appendSection("Enum Values", node.members(NodeKind.EnumItem), sortMembers = false, omitSamePlatforms = true)
+ appendSection("Constructors", node.members(NodeKind.Constructor), omitSamePlatforms = true)
+ appendSection("Properties", node.members(NodeKind.Property), omitSamePlatforms = true)
appendSection("Inherited Properties", node.inheritedMembers(NodeKind.Property))
- appendSection("Functions", node.members(NodeKind.Function))
+ appendSection("Functions", node.members(NodeKind.Function), omitSamePlatforms = true)
appendSection("Inherited Functions", node.inheritedMembers(NodeKind.Function))
- appendSection("Companion Object Properties", node.members(NodeKind.CompanionObjectProperty))
+ appendSection("Companion Object Properties", node.members(NodeKind.CompanionObjectProperty), omitSamePlatforms = true)
appendSection("Inherited Companion Object Properties", node.inheritedCompanionObjectMembers(NodeKind.Property))
- appendSection("Companion Object Functions", node.members(NodeKind.CompanionObjectFunction))
+ appendSection("Companion Object Functions", node.members(NodeKind.CompanionObjectFunction), omitSamePlatforms = true)
appendSection("Inherited Companion Object Functions", node.inheritedCompanionObjectMembers(NodeKind.Function))
appendSection("Other members", node.members.filter {
it.kind !in setOf(
@@ -431,7 +453,9 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
}
}
- private fun appendSection(caption: String, members: List<DocumentationNode>, sortMembers: Boolean = true) {
+ private fun appendSection(caption: String, members: List<DocumentationNode>,
+ sortMembers: Boolean = true,
+ omitSamePlatforms: Boolean = false) {
if (members.isEmpty()) return
appendHeader(3) { appendText(caption) }
@@ -440,11 +464,12 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
val membersMap = children.groupBy { link(node, it) }
appendTable("Name", "Summary") {
- appendTableBody() {
+ appendTableBody {
for ((memberLocation, members) in membersMap) {
- appendTableRow() {
+ appendTableRow {
appendTableCell {
appendLink(memberLocation)
+ appendPlatforms(members, omitSamePlatforms)
}
appendTableCell {
val breakdownBySummary = members.groupBy { it.summary }
@@ -478,6 +503,16 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
renderedSignatures.last().appendSignature()
}
}
+
+ private fun appendPlatforms(items: List<DocumentationNode>, omitSamePlatforms: Boolean) {
+ val platforms = items.foldRight(items.first().platformsToShow.toSet()) {
+ node, platforms -> platforms.intersect(node.platformsToShow)
+ }
+ if (platforms.isNotEmpty() && (platforms != node.platformsToShow.toSet() || !omitSamePlatforms)) {
+ appendLine()
+ to.append("(${platforms.joinToString()})")
+ }
+ }
}
inner class AllTypesNodeBuilder(val node: DocumentationNode)
diff --git a/core/src/main/kotlin/Generation/DokkaGenerator.kt b/core/src/main/kotlin/Generation/DokkaGenerator.kt
index 360965d5..6b5df7c9 100644
--- a/core/src/main/kotlin/Generation/DokkaGenerator.kt
+++ b/core/src/main/kotlin/Generation/DokkaGenerator.kt
@@ -7,7 +7,8 @@ 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.DokkaModule
+import org.jetbrains.dokka.Utilities.DokkaAnalysisModule
+import org.jetbrains.dokka.Utilities.DokkaOutputModule
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
@@ -15,47 +16,76 @@ 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.config.JVMConfigurationKeys
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.resolve.LazyTopDownAnalyzer
import org.jetbrains.kotlin.resolve.TopDownAnalysisMode
import org.jetbrains.kotlin.utils.PathUtil
import java.io.File
import kotlin.system.measureTimeMillis
+class SourceRoot(path: String, val defaultPlatforms: List<String> = emptyList()) {
+ val path: String = File(path).absolutePath
+}
+
class DokkaGenerator(val logger: DokkaLogger,
val classpath: List<String>,
- val sources: List<String>,
+ val sources: List<SourceRoot>,
val samples: List<String>,
val includes: List<String>,
val moduleName: String,
val options: DocumentationOptions) {
+
+ private val documentationModule = DocumentationModule(moduleName)
+
fun generate() {
- val environment = createAnalysisEnvironment()
+ val sourcesGroupedByPlatform = sources.groupBy { it.defaultPlatforms.firstOrNull() }
+ for ((platform, roots) in sourcesGroupedByPlatform) {
+ appendSourceModule(platform, roots)
+ }
+ documentationModule.prepareForGeneration(options)
+
+ val timeBuild = measureTimeMillis {
+ logger.info("Generating pages... ")
+ val outputInjector = Guice.createInjector(DokkaOutputModule(options, logger))
+ outputInjector.getInstance(Generator::class.java).buildAll(documentationModule)
+ }
+ logger.info("done in ${timeBuild / 1000} secs")
+ }
+
+ private fun appendSourceModule(defaultPlatform: String?, sourceRoots: List<SourceRoot>) {
+ val sourcePaths = sourceRoots.map { it.path }
+ val environment = createAnalysisEnvironment(sourcePaths)
logger.info("Module: $moduleName")
logger.info("Output: ${File(options.outputDir)}")
- logger.info("Sources: ${environment.sources.joinToString()}")
+ logger.info("Sources: ${sourcePaths.joinToString()}")
logger.info("Classpath: ${environment.classpath.joinToString()}")
logger.info("Analysing sources and libraries... ")
val startAnalyse = System.currentTimeMillis()
- val injector = Guice.createInjector(DokkaModule(environment, options, logger))
+ val defaultPlatformAsList = defaultPlatform?.let { listOf(it) }.orEmpty()
+ 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) } }
+ return sourceRoot?.defaultPlatforms ?: defaultPlatformAsList
+ }
+ }
+
+ val injector = Guice.createInjector(
+ DokkaAnalysisModule(environment, options, defaultPlatformsProvider, documentationModule.nodeRefGraph, logger))
- val documentation = buildDocumentationModule(injector, moduleName, { isSample(it) }, includes)
+ buildDocumentationModule(injector, documentationModule, { isNotSample(it) }, includes)
val timeAnalyse = System.currentTimeMillis() - startAnalyse
logger.info("done in ${timeAnalyse / 1000} secs")
- val timeBuild = measureTimeMillis {
- logger.info("Generating pages... ")
- injector.getInstance(Generator::class.java).buildAll(documentation)
- }
- logger.info("done in ${timeBuild / 1000} secs")
-
Disposer.dispose(environment)
}
- fun createAnalysisEnvironment(): AnalysisEnvironment {
+ fun createAnalysisEnvironment(sourcePaths: List<String>): AnalysisEnvironment {
val environment = AnalysisEnvironment(DokkaMessageCollector(logger))
environment.apply {
@@ -65,14 +95,14 @@ class DokkaGenerator(val logger: DokkaLogger,
addClasspath(File(element))
}
- addSources(this@DokkaGenerator.sources)
+ addSources(sourcePaths)
addSources(this@DokkaGenerator.samples)
}
return environment
}
- fun isSample(file: PsiFile): Boolean {
+ fun isNotSample(file: PsiFile): Boolean {
val sourceFile = File(file.virtualFile!!.path)
return samples.none { sample ->
val canonicalSample = File(sample).canonicalPath
@@ -100,9 +130,9 @@ class DokkaMessageCollector(val logger: DokkaLogger): MessageCollector {
}
fun buildDocumentationModule(injector: Injector,
- moduleName: String,
+ documentationModule: DocumentationModule,
filesToDocumentFilter: (PsiFile) -> Boolean = { file -> true },
- includes: List<String> = listOf()): DocumentationModule {
+ includes: List<String> = listOf()) {
val coreEnvironment = injector.getInstance(KotlinCoreEnvironment::class.java)
val fragmentFiles = coreEnvironment.getSourceFiles().filter(filesToDocumentFilter)
@@ -120,7 +150,13 @@ fun buildDocumentationModule(injector: Injector,
for (include in includes) {
packageDocs.parse(include, fragments.firstOrNull())
}
- val documentationModule = DocumentationModule(moduleName, packageDocs.moduleContent)
+ if (documentationModule.content.isEmpty()) {
+ documentationModule.updateContent {
+ for (node in packageDocs.moduleContent.children) {
+ append(node)
+ }
+ }
+ }
with(injector.getInstance(DocumentationBuilder::class.java)) {
documentationModule.appendFragments(fragments, packageDocs.packageContent,
@@ -131,10 +167,6 @@ fun buildDocumentationModule(injector: Injector,
with(injector.getInstance(JavaDocumentationBuilder::class.java)) {
javaFiles.map { appendFile(it, documentationModule, packageDocs.packageContent) }
}
-
- injector.getInstance(NodeReferenceGraph::class.java).resolveReferences()
-
- return documentationModule
}
diff --git a/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt b/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt
index 806e9f92..b2f4aeaf 100644
--- a/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt
+++ b/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt
@@ -44,10 +44,10 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder {
private val refGraph: NodeReferenceGraph
private val docParser: JavaDocumentationParser
- @Inject constructor(options: DocumentationOptions, refGraph: NodeReferenceGraph) {
+ @Inject constructor(options: DocumentationOptions, refGraph: NodeReferenceGraph, logger: DokkaLogger) {
this.options = options
this.refGraph = refGraph
- this.docParser = JavadocParser(refGraph)
+ this.docParser = JavadocParser(refGraph, logger)
}
constructor(options: DocumentationOptions, refGraph: NodeReferenceGraph, docParser: JavaDocumentationParser) {
diff --git a/core/src/main/kotlin/Java/JavadocParser.kt b/core/src/main/kotlin/Java/JavadocParser.kt
index 0fb98230..af45f150 100644
--- a/core/src/main/kotlin/Java/JavadocParser.kt
+++ b/core/src/main/kotlin/Java/JavadocParser.kt
@@ -20,7 +20,8 @@ interface JavaDocumentationParser {
fun parseDocumentation(element: PsiNamedElement): JavadocParseResult
}
-class JavadocParser(private val refGraph: NodeReferenceGraph) : JavaDocumentationParser {
+class JavadocParser(private val refGraph: NodeReferenceGraph,
+ private val logger: DokkaLogger) : JavaDocumentationParser {
override fun parseDocumentation(element: PsiNamedElement): JavadocParseResult {
val docComment = (element as? PsiDocCommentOwner)?.docComment
if (docComment == null) return JavadocParseResult.Empty
@@ -99,7 +100,7 @@ class JavadocParser(private val refGraph: NodeReferenceGraph) : JavaDocumentatio
private fun createLink(element: Element): ContentBlock {
val docref = element.attr("docref")
if (docref != null) {
- return ContentNodeLazyLink(docref, { -> refGraph.lookup(docref)})
+ return ContentNodeLazyLink(docref, { -> refGraph.lookupOrWarn(docref, logger)})
}
val href = element.attr("href")
if (href != null) {
@@ -118,7 +119,7 @@ class JavadocParser(private val refGraph: NodeReferenceGraph) : JavaDocumentatio
val linkSignature = resolveLink(linkElement)
val text = ContentText(linkElement.text)
if (linkSignature != null) {
- val linkNode = ContentNodeLazyLink(tag.valueElement!!.text, { -> refGraph.lookup(linkSignature)})
+ val linkNode = ContentNodeLazyLink(tag.valueElement!!.text, { -> refGraph.lookupOrWarn(linkSignature, logger)})
linkNode.append(text)
seeSection.append(linkNode)
} else {
diff --git a/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt b/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt
index 4c46f7d6..71b636bf 100644
--- a/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt
+++ b/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt
@@ -31,7 +31,7 @@ class DeclarationLinkResolver
if (jdkHref != null) {
return ContentExternalLink(jdkHref)
}
- return ContentNodeLazyLink(href, { -> refGraph.lookup(symbol.signature()) })
+ return ContentNodeLazyLink(href, { -> refGraph.lookupOrWarn(symbol.signature(), logger) })
}
if ("/" in href) {
return ContentExternalLink(href)
diff --git a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt b/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt
index d1f64eeb..06acf2e6 100644
--- a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt
+++ b/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt
@@ -116,7 +116,7 @@ class DescriptorDocumentationParser
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).parseDocumentation(psi as PsiNamedElement)
+ val parseResult = JavadocParser(refGraph, logger).parseDocumentation(psi as PsiNamedElement)
return parseResult.content to { node ->
parseResult.deprecatedContent?.let {
val deprecationNode = DocumentationNode("", it, NodeKind.Modifier)
diff --git a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
index afb95fe6..2ab43fa1 100644
--- a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
+++ b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
@@ -28,16 +28,19 @@ import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
import org.jetbrains.kotlin.types.typeUtil.supertypes
+import com.google.inject.name.Named as GuiceNamed
data class DocumentationOptions(val outputDir: String,
val outputFormat: String,
val includeNonPublic: Boolean = false,
+ val includeRootPackage: Boolean = false,
val reportUndocumented: Boolean = true,
val skipEmptyPackages: Boolean = true,
val skipDeprecated: Boolean = false,
val jdkVersion: Int = 6,
val generateIndexPages: Boolean = true,
- val sourceLinks: List<SourceLinkDefinition>)
+ val sourceLinks: List<SourceLinkDefinition> = emptyList(),
+ val impliedPlatforms: List<String> = emptyList())
private fun isExtensionForExternalClass(extensionFunctionDescriptor: DeclarationDescriptor,
extensionReceiverDescriptor: DeclarationDescriptor,
@@ -57,13 +60,19 @@ interface PackageDocumentationBuilder {
allFqNames: Collection<FqName>)
}
+interface DefaultPlatformsProvider {
+ fun getDefaultPlatforms(descriptor: DeclarationDescriptor): List<String>
+}
+
class DocumentationBuilder
@Inject constructor(val resolutionFacade: DokkaResolutionFacade,
val descriptorDocumentationParser: DescriptorDocumentationParser,
val options: DocumentationOptions,
val refGraph: NodeReferenceGraph,
+ val platformNodeRegistry: PlatformNodeRegistry,
val logger: DokkaLogger,
- val linkResolver: DeclarationLinkResolver) {
+ val linkResolver: DeclarationLinkResolver,
+ val defaultPlatformsProvider: DefaultPlatformsProvider) {
val boringBuiltinClasses = setOf(
"kotlin.Unit", "kotlin.Byte", "kotlin.Short", "kotlin.Int", "kotlin.Long", "kotlin.Char", "kotlin.Boolean",
"kotlin.Float", "kotlin.Double", "kotlin.String", "kotlin.Array", "kotlin.Any")
@@ -156,6 +165,11 @@ class DocumentationBuilder
return appendType(it.abbreviation)
}
+ if (kotlinType.isDynamic()) {
+ append(DocumentationNode("dynamic", Content.Empty, kind), RefKind.Detail)
+ return
+ }
+
val classifierDescriptor = kotlinType.constructor.declarationDescriptor
val name = when (classifierDescriptor) {
is ClassDescriptor -> {
@@ -199,17 +213,34 @@ class DocumentationBuilder
fun DocumentationNode.appendAnnotations(annotated: Annotated) {
annotated.annotations.forEach {
it.build()?.let { annotationNode ->
- val refKind = when {
- it.isDocumented() && annotationNode.isDeprecation() -> RefKind.Deprecation
- it.isDocumented() -> RefKind.Annotation
- it.isHiddenInDocumentation() -> RefKind.HiddenAnnotation
- else -> return@forEach
+ if (annotationNode.isSinceKotlin()) {
+ appendSinceKotlin(annotationNode)
}
- append(annotationNode, refKind)
+ else {
+ val refKind = when {
+ it.isDocumented() ->
+ when {
+ annotationNode.isDeprecation() -> RefKind.Deprecation
+ else -> RefKind.Annotation
+ }
+ it.isHiddenInDocumentation() -> RefKind.HiddenAnnotation
+ else -> return@forEach
+ }
+ append(annotationNode, refKind)
+ }
+
}
}
}
+ fun DocumentationNode.appendSinceKotlin(annotation: DocumentationNode) {
+ var kotlinVersion = annotation.detail(NodeKind.Parameter).detail(NodeKind.Value).name
+ if (kotlinVersion.startsWith('\"') && kotlinVersion.endsWith('\"')) {
+ kotlinVersion = kotlinVersion.substring(1..kotlinVersion.length-2)
+ }
+ append(platformNodeRegistry["Kotlin " + kotlinVersion], RefKind.Platform)
+ }
+
fun DocumentationNode.appendModifiers(descriptor: DeclarationDescriptor) {
val psi = (descriptor as DeclarationDescriptorWithSource).source.getPsi() as? KtModifierListOwner ?: return
KtTokens.MODIFIER_KEYWORDS_ARRAY.filter { it !in knownModifiers }.forEach {
@@ -219,8 +250,16 @@ class DocumentationBuilder
}
}
+ fun DocumentationNode.appendDefaultPlatforms(descriptor: DeclarationDescriptor) {
+ for (platform in defaultPlatformsProvider.getDefaultPlatforms(descriptor)) {
+ append(platformNodeRegistry[platform], RefKind.Platform)
+ }
+ }
+
fun DocumentationNode.isDeprecation() = name == "Deprecated" || name == "deprecated"
+ fun DocumentationNode.isSinceKotlin() = name == "SinceKotlin" && kind == NodeKind.Annotation
+
fun DocumentationNode.appendSourceLink(sourceElement: SourceElement) {
appendSourceLink(sourceElement.getPsi(), options.sourceLinks)
}
@@ -230,11 +269,7 @@ class DocumentationBuilder
}
fun DocumentationNode.appendChild(descriptor: DeclarationDescriptor, kind: RefKind): DocumentationNode? {
- // do not include generated code
- if (descriptor is CallableMemberDescriptor && descriptor.kind != CallableMemberDescriptor.Kind.DECLARATION)
- return null
-
- if (descriptor.isDocumented(options)) {
+ if (!descriptor.isGenerated() && descriptor.isDocumented(options)) {
val node = descriptor.build()
append(node, kind)
return node
@@ -242,21 +277,57 @@ class DocumentationBuilder
return null
}
- fun DocumentationNode.appendMembers(descriptors: Iterable<DeclarationDescriptor>,
- inheritedLinkKind: RefKind = RefKind.InheritedMember): List<DocumentationNode> {
- val nodes = descriptors.map { descriptor ->
- if (descriptor is CallableMemberDescriptor && descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
- val baseDescriptor = descriptor.overriddenDescriptors.firstOrNull()
- if (baseDescriptor != null) {
- link(this, baseDescriptor, inheritedLinkKind)
+ fun DocumentationNode.appendOrUpdateMember(descriptor: DeclarationDescriptor) {
+ if (descriptor.isGenerated() || !descriptor.isDocumented(options)) return
+
+ val existingNode = refGraph.lookup(descriptor.signature())
+ if (existingNode != null) {
+ existingNode.updatePlatforms(descriptor)
+
+ if (descriptor is ClassDescriptor) {
+ val membersToDocument = descriptor.collectMembersToDocument()
+ for ((memberDescriptor, inheritedLinkKind, extraModifier) in membersToDocument) {
+ if (memberDescriptor is ClassDescriptor) {
+ existingNode.appendOrUpdateMember(memberDescriptor) // recurse into nested classes
+ }
+ else {
+ val existingMemberNode = refGraph.lookup(memberDescriptor.signature())
+ if (existingMemberNode != null) {
+ existingMemberNode.updatePlatforms(memberDescriptor)
+ }
+ else {
+ existingNode.appendClassMember(memberDescriptor, inheritedLinkKind, extraModifier)
+ }
+ }
}
- null
- } else {
- val descriptorToUse = if (descriptor is ConstructorDescriptor) descriptor else descriptor.original
- appendChild(descriptorToUse, RefKind.Member)
}
}
- return nodes.filterNotNull()
+ else {
+ appendChild(descriptor, RefKind.Member)
+ }
+ }
+
+ private fun DocumentationNode.updatePlatforms(descriptor: DeclarationDescriptor) {
+ for (platform in defaultPlatformsProvider.getDefaultPlatforms(descriptor) - platforms) {
+ append(platformNodeRegistry[platform], RefKind.Platform)
+ }
+ }
+
+ fun DocumentationNode.appendClassMember(descriptor: DeclarationDescriptor,
+ inheritedLinkKind: RefKind = RefKind.InheritedMember,
+ extraModifier: String?) {
+ if (descriptor is CallableMemberDescriptor && descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
+ val baseDescriptor = descriptor.overriddenDescriptors.firstOrNull()
+ if (baseDescriptor != null) {
+ link(this, baseDescriptor, inheritedLinkKind)
+ }
+ } else {
+ val descriptorToUse = if (descriptor is ConstructorDescriptor) descriptor else descriptor.original
+ val child = appendChild(descriptorToUse, RefKind.Member)
+ if (extraModifier != null) {
+ child?.appendTextNode("static", NodeKind.Modifier)
+ }
+ }
}
fun DocumentationNode.appendInPageChildren(descriptors: Iterable<DeclarationDescriptor>, kind: RefKind) {
@@ -272,6 +343,7 @@ class DocumentationBuilder
val allFqNames = fragments.map { it.fqName }.distinct()
for (packageName in allFqNames) {
+ if (packageName.isRoot && !options.includeRootPackage) continue
val declarations = fragments.filter { it.fqName == packageName }.flatMap { it.getMemberScope().getContributedDescriptors() }
if (options.skipEmptyPackages && declarations.none { it.isDocumented(options) }) continue
@@ -282,9 +354,6 @@ class DocumentationBuilder
}
propagateExtensionFunctionsToSubclasses(fragments)
- if (options.generateIndexPages) {
- generateAllTypesNode()
- }
}
private fun propagateExtensionFunctionsToSubclasses(fragments: Collection<PackageFragmentDescriptor>) {
@@ -297,13 +366,15 @@ class DocumentationBuilder
.filter { it.extensionReceiverParameter != null }
val extensionFunctionsByName = allExtensionFunctions.groupBy { it.name }
- allExtensionFunctions.forEach { extensionFunction ->
+ for (extensionFunction in allExtensionFunctions) {
+ if (extensionFunction.dispatchReceiverParameter != null) continue
val possiblyShadowingFunctions = extensionFunctionsByName[extensionFunction.name]
?.filter { fn -> fn.canShadow(extensionFunction) }
?: emptyList()
- val classDescriptor = extensionFunction.getExtensionClassDescriptor() ?: return@forEach
- val subclasses = classHierarchy[classDescriptor] ?: return@forEach
+ if (extensionFunction.extensionReceiverParameter?.type?.isDynamic() == true) continue
+ val classDescriptor = extensionFunction.getExtensionClassDescriptor() ?: continue
+ val subclasses = classHierarchy[classDescriptor] ?: continue
subclasses.forEach { subclass ->
if (subclass.isExtensionApplicable(extensionFunction) &&
possiblyShadowingFunctions.none { subclass.isExtensionApplicable(it) }) {
@@ -357,19 +428,6 @@ class DocumentationBuilder
return false
}
- private fun DocumentationNode.generateAllTypesNode() {
- val allTypes = members(NodeKind.Package)
- .flatMap { it.members.filter { it.kind in NodeKind.classLike || it.kind == NodeKind.ExternalClass } }
- .sortedBy { if (it.kind == NodeKind.ExternalClass) it.name.substringAfterLast('.') else it.name }
-
- val allTypesNode = DocumentationNode("alltypes", Content.Empty, NodeKind.AllTypes)
- for (typeNode in allTypes) {
- allTypesNode.addReferenceTo(typeNode, RefKind.Member)
- }
-
- append(allTypesNode, RefKind.Member)
- }
-
fun DeclarationDescriptor.build(): DocumentationNode = when (this) {
is ClassDescriptor -> build()
is ConstructorDescriptor -> build()
@@ -392,6 +450,7 @@ class DocumentationBuilder
node.appendType(underlyingType, NodeKind.TypeAliasUnderlyingType)
node.appendSourceLink(source)
+ node.appendDefaultPlatforms(this)
register(this, node)
return node
@@ -413,28 +472,48 @@ class DocumentationBuilder
}
if (getKind() != ClassKind.OBJECT && getKind() != ClassKind.ENUM_ENTRY) {
node.appendInPageChildren(typeConstructor.parameters, RefKind.Detail)
- val constructorsToDocument = if (getKind() == ClassKind.ENUM_CLASS)
+ }
+ for ((descriptor, inheritedLinkKind, extraModifier) in collectMembersToDocument()) {
+ node.appendClassMember(descriptor, inheritedLinkKind, extraModifier)
+ }
+ node.appendAnnotations(this)
+ node.appendModifiers(this)
+ node.appendSourceLink(source)
+ node.appendDefaultPlatforms(this)
+ register(this, node)
+ return node
+ }
+
+ data class ClassMember(val descriptor: DeclarationDescriptor,
+ val inheritedLinkKind: RefKind = RefKind.InheritedMember,
+ val extraModifier: String? = null)
+
+ 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
- node.appendMembers(constructorsToDocument)
- }
- val members = defaultType.memberScope.getContributedDescriptors().filter { it != companionObjectDescriptor }
- node.appendMembers(members)
- node.appendMembers(staticScope.getContributedDescriptors()).forEach {
- it.appendTextNode("static", NodeKind.Modifier)
+ 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) {
val descriptors = companionObjectDescriptor.defaultType.memberScope.getContributedDescriptors()
val descriptorsToDocument = descriptors.filter { it !is CallableDescriptor || !it.isInheritedFromAny() }
- node.appendMembers(descriptorsToDocument, RefKind.InheritedCompanionObjectMember)
+ descriptorsToDocument.mapTo(result) {
+ ClassMember(it, inheritedLinkKind = RefKind.InheritedCompanionObjectMember)
+ }
}
- node.appendAnnotations(this)
- node.appendModifiers(this)
- node.appendSourceLink(source)
- register(this, node)
- return node
+ return result
}
fun CallableDescriptor.isInheritedFromAny(): Boolean {
@@ -449,6 +528,7 @@ class DocumentationBuilder
fun ConstructorDescriptor.build(): DocumentationNode {
val node = nodeForDescriptor(this, NodeKind.Constructor)
node.appendInPageChildren(valueParameters, RefKind.Detail)
+ node.appendDefaultPlatforms(this)
register(this, node)
return node
}
@@ -477,6 +557,7 @@ class DocumentationBuilder
node.appendModifiers(this)
node.appendSourceLink(source)
node.appendSignature(this)
+ node.appendDefaultPlatforms(this)
overriddenDescriptors.forEach {
addOverrideLink(it, this)
@@ -523,6 +604,7 @@ class DocumentationBuilder
overriddenDescriptors.forEach {
addOverrideLink(it, this)
}
+ node.appendDefaultPlatforms(this)
register(this, node)
return node
@@ -596,9 +678,10 @@ class DocumentationBuilder
receiverClass = upperBoundClass
}
}
- link(receiverClass,
- containingDeclaration,
- RefKind.Extension)
+
+ if ((containingDeclaration as? FunctionDescriptor)?.dispatchReceiverParameter == null) {
+ link(receiverClass, containingDeclaration, RefKind.Extension)
+ }
val node = DocumentationNode(name.asString(), Content.Empty, NodeKind.Receiver)
node.appendType(type)
@@ -646,6 +729,8 @@ fun DeclarationDescriptor.isDocumented(options: DocumentationOptions): Boolean {
(!options.skipDeprecated || !isDeprecated())
}
+private fun DeclarationDescriptor.isGenerated() = this is CallableMemberDescriptor && kind != CallableMemberDescriptor.Kind.DECLARATION
+
class KotlinPackageDocumentationBuilder : PackageDocumentationBuilder {
override fun buildPackageDocumentation(documentationBuilder: DocumentationBuilder,
packageName: FqName,
@@ -657,7 +742,7 @@ class KotlinPackageDocumentationBuilder : PackageDocumentationBuilder {
with(documentationBuilder) {
if (descriptor.isDocumented(options)) {
val parent = packageNode.getParentForPackageMember(descriptor, externalClassNodes, allFqNames)
- parent.appendChild(descriptor, RefKind.Member)
+ parent.appendOrUpdateMember(descriptor)
}
}
}
@@ -819,3 +904,23 @@ fun DeclarationDescriptor.sourceLocation(): String? {
}
return null
}
+
+fun DocumentationModule.prepareForGeneration(options: DocumentationOptions) {
+ if (options.generateIndexPages) {
+ generateAllTypesNode()
+ }
+ nodeRefGraph.resolveReferences()
+}
+
+fun DocumentationNode.generateAllTypesNode() {
+ val allTypes = members(NodeKind.Package)
+ .flatMap { it.members.filter { it.kind in NodeKind.classLike || it.kind == NodeKind.ExternalClass } }
+ .sortedBy { if (it.kind == NodeKind.ExternalClass) it.name.substringAfterLast('.') else it.name }
+
+ val allTypesNode = DocumentationNode("alltypes", Content.Empty, NodeKind.AllTypes)
+ for (typeNode in allTypes) {
+ allTypesNode.addReferenceTo(typeNode, RefKind.Member)
+ }
+
+ append(allTypesNode, RefKind.Member)
+}
diff --git a/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt b/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt
index 75a8a948..e54772b3 100644
--- a/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt
+++ b/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt
@@ -151,26 +151,47 @@ class KotlinLanguageService : LanguageService {
}
}
- private fun ContentBlock.renderType(node: DocumentationNode, renderMode: RenderMode) {
+ private fun ContentBlock.renderFunctionalType(node: DocumentationNode, renderMode: RenderMode) {
var typeArguments = node.details(NodeKind.Type)
- if (node.name == "Function${typeArguments.count() - 1}") {
- // 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)
+
+ 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
+ }
+ if (node.isFunctionalType()) {
+ renderFunctionalType(node, renderMode)
return
}
if (renderMode == RenderMode.FULL) {
@@ -178,7 +199,8 @@ class KotlinLanguageService : LanguageService {
}
renderModifiersForNode(node, renderMode, true)
renderLinked(node) { identifier(it.name, IdentifierKind.TypeName) }
- if (typeArguments.any()) {
+ val typeArguments = node.details(NodeKind.Type)
+ if (typeArguments.isNotEmpty()) {
symbol("<")
renderList(typeArguments, noWrap = true) {
renderType(it, renderMode)
diff --git a/core/src/main/kotlin/Model/DocumentationNode.kt b/core/src/main/kotlin/Model/DocumentationNode.kt
index def0f626..caacac14 100644
--- a/core/src/main/kotlin/Model/DocumentationNode.kt
+++ b/core/src/main/kotlin/Model/DocumentationNode.kt
@@ -48,6 +48,7 @@ enum class NodeKind {
Signature,
ExternalLink,
+ Platform,
AllTypes,
@@ -97,6 +98,8 @@ open class DocumentationNode(val name: String,
get() = references(RefKind.Annotation).map { it.to }
val deprecation: DocumentationNode?
get() = references(RefKind.Deprecation).singleOrNull()?.to
+ val platforms: List<String>
+ get() = references(RefKind.Platform).map { it.to.name }
// TODO: Should we allow node mutation? Model merge will copy by ref, so references are transparent, which could nice
fun addReferenceTo(to: DocumentationNode, kind: RefKind) {
@@ -135,6 +138,7 @@ open class DocumentationNode(val name: String,
class DocumentationModule(name: String, content: Content = Content.Empty)
: DocumentationNode(name, content, NodeKind.Module) {
+ val nodeRefGraph = NodeReferenceGraph()
}
val DocumentationNode.path: List<DocumentationNode>
diff --git a/core/src/main/kotlin/Model/DocumentationReference.kt b/core/src/main/kotlin/Model/DocumentationReference.kt
index 0165b567..a968f400 100644
--- a/core/src/main/kotlin/Model/DocumentationReference.kt
+++ b/core/src/main/kotlin/Model/DocumentationReference.kt
@@ -1,6 +1,5 @@
package org.jetbrains.dokka
-import com.google.inject.Inject
import com.google.inject.Singleton
enum class RefKind {
@@ -18,7 +17,8 @@ enum class RefKind {
Annotation,
HiddenAnnotation,
Deprecation,
- TopLevelPage
+ TopLevelPage,
+ Platform
}
data class DocumentationReference(val from: DocumentationNode, val to: DocumentationNode, val kind: RefKind) {
@@ -36,9 +36,7 @@ class PendingDocumentationReference(val lazyNodeFrom: () -> DocumentationNode?,
}
}
-@Singleton
-class NodeReferenceGraph
- @Inject constructor(val logger: DokkaLogger) {
+class NodeReferenceGraph() {
private val nodeMap = hashMapOf<String, DocumentationNode>()
val references = arrayListOf<PendingDocumentationReference>()
@@ -58,7 +56,9 @@ class NodeReferenceGraph
references.add(PendingDocumentationReference({ -> nodeMap[fromSignature]}, { -> nodeMap[toSignature]}, kind))
}
- fun lookup(signature: String): DocumentationNode? {
+ fun lookup(signature: String) = nodeMap[signature]
+
+ fun lookupOrWarn(signature: String, logger: DokkaLogger): DocumentationNode? {
val result = nodeMap[signature]
if (result == null) {
logger.warn("Can't find node by signature $signature")
@@ -70,3 +70,14 @@ class NodeReferenceGraph
references.forEach { it.resolve() }
}
}
+
+@Singleton
+class PlatformNodeRegistry {
+ private val platformNodes = hashMapOf<String, DocumentationNode>()
+
+ operator fun get(platform: String): DocumentationNode {
+ return platformNodes.getOrPut(platform) {
+ DocumentationNode(platform, Content.Empty, NodeKind.Platform)
+ }
+ }
+}
diff --git a/core/src/main/kotlin/Utilities/DokkaModule.kt b/core/src/main/kotlin/Utilities/DokkaModules.kt
index e1ae829a..5982d7dd 100644
--- a/core/src/main/kotlin/Utilities/DokkaModule.kt
+++ b/core/src/main/kotlin/Utilities/DokkaModules.kt
@@ -3,6 +3,7 @@ package org.jetbrains.dokka.Utilities
import com.google.inject.Binder
import com.google.inject.Module
import com.google.inject.Provider
+import com.google.inject.TypeLiteral
import com.google.inject.name.Names
import org.jetbrains.dokka.*
import org.jetbrains.dokka.Formats.FormatDescriptor
@@ -10,10 +11,47 @@ import org.jetbrains.dokka.Samples.SampleProcessingService
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import java.io.File
-class DokkaModule(val environment: AnalysisEnvironment,
- val options: DocumentationOptions,
- val logger: DokkaLogger) : Module {
+const val impliedPlatformsName = "impliedPlatforms"
+
+class DokkaAnalysisModule(val environment: AnalysisEnvironment,
+ val options: DocumentationOptions,
+ val defaultPlatformsProvider: DefaultPlatformsProvider,
+ val nodeReferenceGraph: NodeReferenceGraph,
+ val logger: DokkaLogger) : Module {
+ override fun configure(binder: Binder) {
+ val descriptor = ServiceLocator.lookup<FormatDescriptor>("format", options.outputFormat)
+
+ binder.registerCategory<LanguageService>("language")
+ binder.bind<PackageDocumentationBuilder>().to(descriptor.packageDocumentationBuilderClass.java)
+ binder.bind<JavaDocumentationBuilder>().to(descriptor.javaDocumentationBuilderClass.java)
+ binder.bind<SampleProcessingService>().to(descriptor.sampleProcessingService.java)
+
+ val coreEnvironment = environment.createCoreEnvironment()
+ binder.bind<KotlinCoreEnvironment>().toInstance(coreEnvironment)
+
+ val dokkaResolutionFacade = environment.createResolutionFacade(coreEnvironment)
+ binder.bind<DokkaResolutionFacade>().toInstance(dokkaResolutionFacade)
+
+ binder.bind<DocumentationOptions>().toInstance(options)
+ binder.bind<DokkaLogger>().toInstance(logger)
+
+ binder.bind<DefaultPlatformsProvider>().toInstance(defaultPlatformsProvider)
+
+ binder.bind<NodeReferenceGraph>().toInstance(nodeReferenceGraph)
+ }
+}
+
+object StringListType : TypeLiteral<@JvmSuppressWildcards List<String>>()
+
+class DokkaOutputModule(val options: DocumentationOptions,
+ val logger: DokkaLogger) : Module {
override fun configure(binder: Binder) {
+ binder.bind(LanguageService::class.java).to(KotlinLanguageService::class.java)
+
+ binder.bind(HtmlTemplateService::class.java).toProvider(object : Provider<HtmlTemplateService> {
+ override fun get(): HtmlTemplateService = HtmlTemplateService.default("style.css")
+ })
+
binder.bind(File::class.java).annotatedWith(Names.named("outputDir")).toInstance(File(options.outputDir))
binder.bindNameAnnotated<LocationService, SingleFolderLocationService>("singleFolder")
@@ -24,13 +62,7 @@ class DokkaModule(val environment: AnalysisEnvironment,
// defaults
binder.bind(LocationService::class.java).to(FoldersLocationService::class.java)
binder.bind(FileLocationService::class.java).to(FoldersLocationService::class.java)
- binder.bind(LanguageService::class.java).to(KotlinLanguageService::class.java)
-
- binder.bind(HtmlTemplateService::class.java).toProvider(object : Provider<HtmlTemplateService> {
- override fun get(): HtmlTemplateService = HtmlTemplateService.default("style.css")
- })
- binder.registerCategory<LanguageService>("language")
binder.registerCategory<OutlineFormatService>("outline")
binder.registerCategory<FormatService>("format")
binder.registerCategory<Generator>("generator")
@@ -43,20 +75,12 @@ class DokkaModule(val environment: AnalysisEnvironment,
descriptor.formatServiceClass?.let { clazz ->
binder.bind(FormatService::class.java).to(clazz.java)
}
- binder.bind<PackageDocumentationBuilder>().to(descriptor.packageDocumentationBuilderClass.java)
- binder.bind<JavaDocumentationBuilder>().to(descriptor.javaDocumentationBuilderClass.java)
- binder.bind<SampleProcessingService>().to(descriptor.sampleProcessingService.java)
binder.bind<Generator>().to(descriptor.generatorServiceClass.java)
- val coreEnvironment = environment.createCoreEnvironment()
- binder.bind<KotlinCoreEnvironment>().toInstance(coreEnvironment)
-
- val dokkaResolutionFacade = environment.createResolutionFacade(coreEnvironment)
- binder.bind<DokkaResolutionFacade>().toInstance(dokkaResolutionFacade)
-
binder.bind<DocumentationOptions>().toInstance(options)
binder.bind<DokkaLogger>().toInstance(logger)
+ binder.bind(StringListType).annotatedWith(Names.named(impliedPlatformsName)).toInstance(options.impliedPlatforms)
}
}