Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dokka K2 analysis #3094

Merged
merged 30 commits into from
Aug 28, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
1f4db2b
Support K2 Analysis Api
vmishenev Jul 17, 2023
6a676f8
Introduce TypeTranslator
vmishenev Jul 22, 2023
d849de8
Support samles, modules docs, external documentables, FullClassHierar…
vmishenev Jul 24, 2023
d19addc
Parse JavaDoc
vmishenev Jul 25, 2023
8245aea
Support TypeAliased
vmishenev Jul 25, 2023
b5d6d83
Refactor
vmishenev Jul 26, 2023
450aba9
Use `KtModule`
vmishenev Jul 26, 2023
43d7626
Move k2 dependencies to toml
vmishenev Jul 26, 2023
c46fd4b
Reuse tests for symbols
vmishenev Jul 26, 2023
af46f51
Format
vmishenev Jul 26, 2023
61ffac9
Fix tests of other plugins
vmishenev Jul 26, 2023
29dfeea
Reset JDK home
vmishenev Jul 26, 2023
7104e87
Add some minor docs
vmishenev Jul 26, 2023
bc7ba34
Add disposer
vmishenev Jul 28, 2023
718b7e4
Fix API
vmishenev Jul 28, 2023
44d9df7
Fix analysis disposing
vmishenev Aug 11, 2023
78bdf0b
Fix some review comments
vmishenev Aug 11, 2023
654d252
Rebase
vmishenev Aug 11, 2023
a646328
Use `KtSyntheticJavaPropertySymbol` instead of
vmishenev Aug 11, 2023
6488f86
Mute Java tests or using JDK
vmishenev Aug 11, 2023
b47a0c0
Refactor to extract function
vmishenev Aug 12, 2023
9b79b24
Support synthetic KDoc for enum members
vmishenev Aug 14, 2023
aa26380
Resolve KDoc links via Analysis API
vmishenev Aug 16, 2023
61e0309
Make some transitive dependencies `runtimeOnly`
vmishenev Aug 18, 2023
9e65b29
Fix review comments
vmishenev Aug 18, 2023
853083a
Exclude `analysis-kotlin-descriptors` from `baseTestUtils`
vmishenev Aug 18, 2023
5a227fe
Move `plugin` project
vmishenev Aug 19, 2023
8da7ce2
Extract a convention plugin for testing
vmishenev Aug 20, 2023
83d6ad4
Polish code
vmishenev Aug 24, 2023
de2426c
Mute extra tests
vmishenev Aug 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Use KtModule
  • Loading branch information
vmishenev committed Aug 11, 2023
commit 450aba9e1ac58a495f03a8146d894b86a7793685
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,8 @@ internal fun ModuleAndPackageDocumentationParsingContext(
if(kotlinAnalysis == null || sourceSet == null) {
MarkdownParser(externalDri = { null }, sourceLocation)
} else {
// TODO research another ways to get AnalysisSession
val analysisContext = kotlinAnalysis[sourceSet]
val someKtFile = getPsiFilesFromPaths<KtFile>(
analysisContext.project,
getSourceFilePaths(sourceSet.sourceRoots.map { it.canonicalPath })
).firstOrNull()

if (someKtFile == null)
MarkdownParser(externalDri = { null }, sourceLocation)
else
analyze(someKtFile) {
analyze(analysisContext.mainModule) {
val contextSymbol = when (fragment.classifier) {
Module -> getPackageSymbolIfPackageExists(FqName.topLevel(Name.identifier("")))
vmishenev marked this conversation as resolved.
Show resolved Hide resolved
Package -> getPackageSymbolIfPackageExists(FqName(fragment.name))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ private class ContextModuleAndPackageDocumentationReader(
): SourceSetDependent<DocumentationNode> {
return sourceSets.associateWithNotNull { sourceSet ->
val fragments = documentationFragments[sourceSet].orEmpty().filter(predicate)
kotlinAnalysis[sourceSet] // to throw exception for unknown sourceSet
kotlinAnalysis[sourceSet] // test: to throw exception for unknown sourceSet
val documentations = fragments.map { fragment ->
parseModuleAndPackageDocumentation(
context = ModuleAndPackageDocumentationParsingContext(context.logger, kotlinAnalysis, sourceSet),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import org.jetbrains.dokka.InternalDokkaApi
import org.jetbrains.dokka.model.SourceSetDependent
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.kotlin.analysis.api.standalone.StandaloneAnalysisAPISession
import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule
import java.io.Closeable
import java.io.File

Expand Down Expand Up @@ -62,7 +63,14 @@ internal fun createAnalysisContext(
sourceRoots: Set<File>,
sourceSet: DokkaConfiguration.DokkaSourceSet
): AnalysisContext {
return AnalysisContextImpl(createAnalysisSession(classpath, sourceRoots, sourceSet.analysisPlatform))
val analysis= createAnalysisSession(
classpath = classpath,
sourceRoots = sourceRoots,
analysisPlatform = sourceSet.analysisPlatform,
languageVersion = sourceSet.languageVersion,
apiVersion = sourceSet.apiVersion
)
return AnalysisContextImpl(analysis.first, analysis.second,)
}


Expand Down Expand Up @@ -102,9 +110,10 @@ internal open class EnvironmentKotlinAnalysis(

interface AnalysisContext: Closeable {
val project: Project
val mainModule: KtSourceModule
}

class AnalysisContextImpl(private val analysisSession: StandaloneAnalysisAPISession) : AnalysisContext {
class AnalysisContextImpl(private val analysisSession: StandaloneAnalysisAPISession, override val mainModule: KtSourceModule) : AnalysisContext {
override val project: Project
get() = analysisSession.project

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ import org.jetbrains.kotlin.analysis.api.impl.base.util.LibraryUtils
import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionProvider
import org.jetbrains.kotlin.analysis.api.standalone.StandaloneAnalysisAPISession
import org.jetbrains.kotlin.analysis.api.standalone.buildStandaloneAnalysisAPISession
import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule
import org.jetbrains.kotlin.analysis.project.structure.builder.KtModuleBuilder
import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtLibraryModule
import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtSdkModule
import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtSourceModule
import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.platform.CommonPlatforms
import org.jetbrains.kotlin.platform.js.JsPlatforms
Expand Down Expand Up @@ -138,12 +140,29 @@ fun getJdkHomeFromSystemProperty(): File? {
return File("/home/Vadim.Mishenev/.jdks/adopt-openjdk-11.0.11")
}

internal fun getLanguageVersionSettings(languageVersionString: String?, apiVersionString: String?): LanguageVersionSettingsImpl {
val languageVersion = LanguageVersion.fromVersionString(languageVersionString) ?: LanguageVersion.LATEST_STABLE
val apiVersion =
apiVersionString?.let { ApiVersion.parse(it) } ?: ApiVersion.createByLanguageVersion(languageVersion)
return LanguageVersionSettingsImpl(
languageVersion = languageVersion,
apiVersion = apiVersion, analysisFlags = hashMapOf(
// special flag for Dokka
// force to resolve light classes (lazily by default)
AnalysisFlags.eagerResolveOfLightClasses to true
)
)
}

fun createAnalysisSession(
classpath: List<File>,
sourceRoots: Set<File>,
analysisPlatform: Platform
): StandaloneAnalysisAPISession {
analysisPlatform: Platform,
languageVersion: String?,
apiVersion: String?
): Pair<StandaloneAnalysisAPISession, KtSourceModule> {

var sourceModule: KtSourceModule? = null
val analysisSession = buildStandaloneAnalysisAPISession(withPsiDeclarationFromBinaryModuleProvider = false) {
val project = project
val targetPlatform = analysisPlatform.toTargetPlatform()
Expand Down Expand Up @@ -176,32 +195,33 @@ fun createAnalysisSession(
)
}
}
sourceModule = buildKtSourceModule {
this.languageVersionSettings = getLanguageVersionSettings(languageVersion, apiVersion)

buildKtModuleProvider {
//val fs = StandardFileSystems.local()
//val psiManager = PsiManager.getInstance(project)
// TODO: We should handle (virtual) file changes announced via LSP with the VFS
/*val ktFiles = sources
.flatMap { Files.walk(it).toList() }
.mapNotNull { fs.findFileByPath(it.toString()) }
.mapNotNull { psiManager.findFile(it) }
.map { it as KtFile }*/
val sourcePaths = sourceRoots.map { it.absolutePath }
val (ktFilePath, javaFilePath) = getSourceFilePaths(sourcePaths).partition { it.endsWith(KotlinFileType.EXTENSION) }
val javaFiles: List<PsiFileSystemItem> = getPsiFilesFromPaths(project, javaFilePath)
val ktFiles: List<KtFile> = getPsiFilesFromPaths(project, getSourceFilePaths(ktFilePath))
addSourceRoots(ktFiles + javaFiles)
contentScope = TopDownAnalyzerFacadeForJVM.newModuleSearchScope(project, ktFiles)
platform = targetPlatform
moduleName = "<module>"
this.project = project
addModule(buildKtSourceModule {
//this.languageVersionSettings = it
addModuleDependencies(moduleName)
}

//val fs = StandardFileSystems.local()
//val psiManager = PsiManager.getInstance(project)
// TODO: We should handle (virtual) file changes announced via LSP with the VFS
/*val ktFiles = sources
.flatMap { Files.walk(it).toList() }
.mapNotNull { fs.findFileByPath(it.toString()) }
.mapNotNull { psiManager.findFile(it) }
.map { it as KtFile }*/
val sourcePaths = sourceRoots.map { it.absolutePath }
val (ktFilePath, javaFilePath) = getSourceFilePaths(sourcePaths).partition { it.endsWith(KotlinFileType.EXTENSION) }
val javaFiles: List<PsiFileSystemItem> = getPsiFilesFromPaths(project, javaFilePath)
val ktFiles: List<KtFile> = getPsiFilesFromPaths(project, getSourceFilePaths(ktFilePath))
addSourceRoots(ktFiles + javaFiles)
contentScope = TopDownAnalyzerFacadeForJVM.newModuleSearchScope(project, ktFiles)
platform = targetPlatform
moduleName = "<module>"
this.project = project
addModuleDependencies(moduleName)
})
buildKtModuleProvider {
platform = targetPlatform
this.project = project
addModule(sourceModule!!)
}
}
// TODO remove further
Expand All @@ -210,5 +230,5 @@ fun createAnalysisSession(
KtResolveExtensionProvider.EP_NAME.name,
KtResolveExtensionProvider::class.java
)
return analysisSession
return Pair(analysisSession, sourceModule ?: throw IllegalStateException())
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,7 @@ internal abstract class SamplesTransformerImpl(val context: DokkaContext) : Page
kotlinAnalysis: KotlinAnalysis
): ContentNode {
val analysisContext = kotlinAnalysis[sourceSet]
// TODO research another ways to get AnalysisSession
val someKtFile = getPsiFilesFromPaths<KtFile>(
analysisContext.project,
getSourceFilePaths(sourceSet.samples.map { it.canonicalPath })
).first()
// TODO Potential bug
val psiElement = analyze(someKtFile) {
val psiElement = analyze(analysisContext.mainModule) {
val lastDotIndex = fqName.lastIndexOf('.')

val functionName = if (lastDotIndex == -1) fqName else fqName.substring(lastDotIndex + 1, fqName.length)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,13 @@ internal class SymbolExternalDocumentablesProvider(val context: DokkaContext) :

// TODO research another ways to get AnalysisSession
val analysisContext = kotlinAnalysis[sourceSet]
val someKtFile = getPsiFilesFromPaths<KtFile>(
analysisContext.project,
getSourceFilePaths(sourceSet.sourceRoots.map { it.canonicalPath })
).first()
analyze(someKtFile) {
val symbol = getClassOrObjectSymbolByClassId(classId) as? KtNamedClassOrObjectSymbol?: return null
return analyze(analysisContext.mainModule) {
val symbol = getClassOrObjectSymbolByClassId(classId) as? KtNamedClassOrObjectSymbol?: return@analyze null
val translator = DokkaSymbolVisitor(sourceSet, sourceSet.displayName, analysisContext, logger = context.logger)

val parentDRI = symbol.getContainingSymbol()?.let { getDRIFromSymbol(it) } ?: /* top level */ DRI(dri.packageName)
with(translator) {
return visitNamedClassOrObjectSymbol(symbol, parentDRI)
return@analyze visitNamedClassOrObjectSymbol(symbol, parentDRI)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,28 +142,27 @@ internal class DokkaSymbolVisitor(
getSourceFilePaths(sourceSet.sourceRoots.map { it.canonicalPath })
)
val processedPackages: MutableSet<FqName> = mutableSetOf()
val packageSymbols: List<DPackage> = ktFiles
.mapNotNull {
analyze(it) {
return analyze(analysisContext.mainModule) {
val packageSymbols: List<DPackage> = ktFiles
.mapNotNull {
if (processedPackages.contains(it.packageFqName))
return@analyze null
return@mapNotNull null
processedPackages.add(it.packageFqName)
getPackageSymbolIfPackageExists(it.packageFqName)?.let { it1 ->
visitPackageSymbol(
it1
)
}
}
}

return DModule(
name = moduleName,
packages = packageSymbols,
documentation = emptyMap(),
expectPresentInSet = null,
sourceSets = setOf(sourceSet)
)


DModule(
name = moduleName,
packages = packageSymbols,
documentation = emptyMap(),
expectPresentInSet = null,
sourceSets = setOf(sourceSet)
)
}
}

private fun KtAnalysisSession.visitPackageSymbol(packageSymbol: KtPackageSymbol): DPackage {
Expand Down