Skip to content

Commit

Permalink
Do not generate source links for synthetic elements (#2547)
Browse files Browse the repository at this point in the history
Fixes #2544
  • Loading branch information
IgnatBeresnev committed Jun 30, 2022
1 parent 623b0e7 commit 76334ec
Show file tree
Hide file tree
Showing 4 changed files with 516 additions and 21 deletions.
Expand Up @@ -68,7 +68,7 @@ abstract class AbstractTest<M : TestMethods, T : TestBuilder<M>, D : DokkaTestGe
block: T.() -> Unit
) {
val testMethods = testBuilder().apply(block).build()
val testDirPath = getTempDir(cleanupOutput).root.toPath()
val testDirPath = getTempDir(cleanupOutput).root.toPath().toAbsolutePath()
val fileMap = query.toFileMap()
fileMap.materializeFiles(testDirPath.toAbsolutePath())
if (!cleanupOutput)
Expand All @@ -85,7 +85,7 @@ abstract class AbstractTest<M : TestMethods, T : TestBuilder<M>, D : DokkaTestGe
}.toSet(),
sourceLinks = sourceSet.sourceLinks.map { link ->
link.copy(
localDirectory = testDirPath.toFile().resolve(link.localDirectory).canonicalPath
localDirectory = testDirPath.toFile().resolve(link.localDirectory).absolutePath
)
}.toSet()
)
Expand Down
Expand Up @@ -24,36 +24,47 @@ import java.io.File

class SourceLinksTransformer(val context: DokkaContext) : PageTransformer {

private val builder : PageContentBuilder = PageContentBuilder(
private val builder : PageContentBuilder = PageContentBuilder(
context.plugin<DokkaBase>().querySingle { commentsToContentConverter },
context.plugin<DokkaBase>().querySingle { signatureProvider },
context.logger
)

override fun invoke(input: RootPageNode) =
input.transformContentPagesTree { node ->
override fun invoke(input: RootPageNode): RootPageNode {
val sourceLinks = getSourceLinksFromConfiguration()
if (sourceLinks.isEmpty()) {
return input
}
return input.transformContentPagesTree { node ->
when (node) {
is WithDocumentables ->
node.documentables.filterIsInstance<WithSources>().flatMap { resolveSources(it) }
.takeIf { it.isNotEmpty() }
?.let { node.addSourcesContent(it) }
?: node
node.documentables
.filterIsInstance<WithSources>()
.flatMap { resolveSources(sourceLinks, it) }
.takeIf { it.isNotEmpty() }
?.let { node.addSourcesContent(it) }
?: node
else -> node
}
}
}

private fun getSourceLinks() = context.configuration.sourceSets
.flatMap { it.sourceLinks.map { sl -> SourceLink(sl, it) } }
private fun getSourceLinksFromConfiguration(): List<SourceLink> {
return context.configuration.sourceSets
.flatMap { it.sourceLinks.map { sl -> SourceLink(sl, it) } }
}

private fun resolveSources(documentable: WithSources) = documentable.sources
.mapNotNull { entry ->
getSourceLinks().find { File(entry.value.path).startsWith(it.path) && it.sourceSetData == entry.key }?.let {
Pair(
entry.key,
entry.value.toLink(it)
)
}
private fun resolveSources(
sourceLinks: List<SourceLink>, documentable: WithSources
): List<Pair<DokkaSourceSet, String>> {
return documentable.sources.mapNotNull { (sourceSet, documentableSource) ->
val sourceLink = sourceLinks.find { sourceLink ->
File(documentableSource.path).startsWith(sourceLink.path) && sourceLink.sourceSetData == sourceSet
} ?: return@mapNotNull null

sourceSet to documentableSource.toLink(sourceLink)
}
}

private fun ContentPage.addSourcesContent(sources: List<Pair<DokkaSourceSet, String>>) = builder
.buildSourcesContent(this, sources)
Expand Down Expand Up @@ -89,8 +100,8 @@ class SourceLinksTransformer(val context: DokkaContext) : PageTransformer {
}

private fun DocumentableSource.toLink(sourceLink: SourceLink): String {
val sourcePath = File(this.path).canonicalPath.replace("\\", "/")
val sourceLinkPath = File(sourceLink.path).canonicalPath.replace("\\", "/")
val sourcePath = File(this.path).invariantSeparatorsPath
val sourceLinkPath = File(sourceLink.path).invariantSeparatorsPath

val lineNumber = when (this) {
is DescriptorDocumentableSource -> this.descriptor
Expand Down Expand Up @@ -134,6 +145,9 @@ class SourceLinksTransformer(val context: DokkaContext) : PageTransformer {
}

private fun PsiElement.lineNumber(): Int? {
// synthetic and some light methods might return null
val textRange = textRange ?: return null

val doc = PsiDocumentManager.getInstance(project).getDocument(containingFile)
// IJ uses 0-based line-numbers; external source browsers use 1-based
return doc?.getLineNumber(textRange.startOffset)?.plus(1)
Expand Down
60 changes: 60 additions & 0 deletions plugins/base/src/test/kotlin/enums/JavaEnumsTest.kt
@@ -0,0 +1,60 @@
package enums

import org.jetbrains.dokka.SourceLinkDefinitionImpl
import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest
import org.junit.jupiter.api.Test
import signatures.renderedContent
import utils.TestOutputWriterPlugin
import java.net.URL
import kotlin.test.assertEquals

class JavaEnumsTest : BaseAbstractTest() {

// Shouldn't try to give source links to synthetic methods (values, valueOf) if any are present
// https://github.com/Kotlin/dokka/issues/2544
@Test
fun `java enum with configured source links should not fail build due to any synthetic methods`() {
val configuration = dokkaConfiguration {
sourceSets {
sourceSet {
sourceRoots = listOf("src/")
sourceLinks = listOf(
SourceLinkDefinitionImpl(
localDirectory = "src/main/java",
remoteUrl = URL("https://github.com/user/repo/tree/master/src/main/java"),
remoteLineSuffix = "#L"
)
)
}
}
}

val writerPlugin = TestOutputWriterPlugin()

testInline(
"""
|/src/main/java/basic/JavaEnum.java
|package testpackage
|
|public enum JavaEnum {
| ONE, TWO, THREE
|}
""".trimMargin(),
configuration,
pluginOverrides = listOf(writerPlugin)
) {
renderingStage = { _, _ ->
val enumPage = writerPlugin.writer.renderedContent("root/testpackage/-java-enum/index.html")
val sourceLink = enumPage.select("div[data-togglable=Sources]")
.select("a[href]")
.attr("href")


assertEquals(
"https://github.com/user/repo/tree/master/src/main/java/basic/JavaEnum.java#L3",
sourceLink
)
}
}
}
}

0 comments on commit 76334ec

Please sign in to comment.