From 08f40e2a13006882e8f8425f111b8527e7bbcb0f Mon Sep 17 00:00:00 2001 From: "sebastian.sellmair" Date: Wed, 24 Jun 2020 09:14:37 +0200 Subject: Remove kotlin source analysis from :core to :kotlin-analysis (thanks to Afzal Najam) --- kotlin-analysis/build.gradle.kts | 27 + kotlin-analysis/dependencies/build.gradle.kts | 67 +++ .../dokka/analysis/AnalysisEnvironment.kt | 636 +++++++++++++++++++++ .../jetbrains/dokka/analysis/CallableFactory.kt | 31 + .../dokka/analysis/CoreKotlinCacheService.kt | 42 ++ .../dokka/analysis/CoreProjectFileIndex.kt | 515 +++++++++++++++++ .../org/jetbrains/dokka/analysis/DRIFactory.kt | 38 ++ .../jetbrains/dokka/analysis/DRITargetFactory.kt | 44 ++ .../org/jetbrains/dokka/analysis/Documentable.kt | 14 + .../dokka/analysis/EnvironmentAndFacade.kt | 59 ++ .../dokka/analysis/JavaResolveExtension.kt | 128 +++++ .../org/jetbrains/dokka/analysis/KotlinAnalysis.kt | 46 ++ .../dokka/analysis/TypeReferenceFactory.kt | 51 ++ 13 files changed, 1698 insertions(+) create mode 100644 kotlin-analysis/build.gradle.kts create mode 100644 kotlin-analysis/dependencies/build.gradle.kts create mode 100644 kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/AnalysisEnvironment.kt create mode 100644 kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/CallableFactory.kt create mode 100644 kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/CoreKotlinCacheService.kt create mode 100644 kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/CoreProjectFileIndex.kt create mode 100644 kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRIFactory.kt create mode 100644 kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRITargetFactory.kt create mode 100644 kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/Documentable.kt create mode 100644 kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/EnvironmentAndFacade.kt create mode 100644 kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/JavaResolveExtension.kt create mode 100644 kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/KotlinAnalysis.kt create mode 100644 kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/TypeReferenceFactory.kt (limited to 'kotlin-analysis') diff --git a/kotlin-analysis/build.gradle.kts b/kotlin-analysis/build.gradle.kts new file mode 100644 index 00000000..67480f82 --- /dev/null +++ b/kotlin-analysis/build.gradle.kts @@ -0,0 +1,27 @@ +import org.jetbrains.configureBintrayPublication + +plugins { + id("com.github.johnrengelman.shadow") + `maven-publish` + id("com.jfrog.bintray") +} + +dependencies { + compileOnly(project(":core")) + + val kotlin_version: String by project + api("org.jetbrains.kotlin:kotlin-compiler:$kotlin_version") + + api(project(":kotlin-analysis:dependencies", configuration = "shadow")) +} + +publishing { + publications { + register("analysis") { + artifactId = "dokka-analysis" + from(components["java"]) + } + } +} + +configureBintrayPublication("analysis") diff --git a/kotlin-analysis/dependencies/build.gradle.kts b/kotlin-analysis/dependencies/build.gradle.kts new file mode 100644 index 00000000..5bba6422 --- /dev/null +++ b/kotlin-analysis/dependencies/build.gradle.kts @@ -0,0 +1,67 @@ +import org.jetbrains.configureBintrayPublication + + +plugins { + id("com.github.johnrengelman.shadow") + `maven-publish` + id("com.jfrog.bintray") +} + +repositories { + maven(url = "https://www.jetbrains.com/intellij-repository/snapshots") + maven(url = "https://www.jetbrains.com/intellij-repository/releases") + maven(url = "https://kotlin.bintray.com/kotlin-plugin") +} + +val intellijCore: Configuration by configurations.creating + +fun intellijCoreAnalysis() = zipTree(intellijCore.singleFile).matching { + include("intellij-core-analysis.jar") +} + +dependencies { + val kotlin_plugin_version: String by project + api("org.jetbrains.kotlin:ide-common-ij193:$kotlin_plugin_version") + api("org.jetbrains.kotlin:kotlin-plugin-ij193:$kotlin_plugin_version") { + //TODO: parametrize ij version after 1.3.70 + isTransitive = false + } + + val idea_version: String by project + intellijCore("com.jetbrains.intellij.idea:intellij-core:$idea_version") + implementation(intellijCoreAnalysis()) + + implementation("org.jetbrains:markdown:0.1.41") { + because("it's published only on bintray") + } +} + +tasks { + shadowJar { + val dokka_version: String by project + archiveFileName.set("dokka-kotlin-analysis-dependencies-$dokka_version.jar") + archiveClassifier.set("") + + exclude("colorScheme/**") + exclude("fileTemplates/**") + exclude("inspectionDescriptions/**") + exclude("intentionDescriptions/**") + exclude("tips/**") + exclude("messages/**") + exclude("src/**") + exclude("**/*.kotlin_metadata") + exclude("**/*.kotlin_builtins") + } +} + + +publishing { + publications { + register("kotlin-analysis-dependencies") { + artifactId = "kotlin-analysis-dependencies" + project.shadow.component(this) + } + } +} + +configureBintrayPublication("kotlin-analysis-dependencies") diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/AnalysisEnvironment.kt b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/AnalysisEnvironment.kt new file mode 100644 index 00000000..7836bde9 --- /dev/null +++ b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/AnalysisEnvironment.kt @@ -0,0 +1,636 @@ +package org.jetbrains.dokka.analysis + +import com.google.common.collect.ImmutableMap +import com.intellij.core.CoreApplicationEnvironment +import com.intellij.core.CoreModuleManager +import com.intellij.mock.MockComponentManager +import com.intellij.openapi.Disposable +import com.intellij.openapi.extensions.Extensions +import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.OrderEnumerationHandler +import com.intellij.openapi.roots.ProjectFileIndex +import com.intellij.openapi.roots.ProjectRootManager +import com.intellij.openapi.util.Disposer +import com.intellij.openapi.vfs.StandardFileSystems +import com.intellij.psi.PsiElement +import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.dokka.Platform +import org.jetbrains.kotlin.analyzer.* +import org.jetbrains.kotlin.analyzer.common.CommonAnalysisParameters +import org.jetbrains.kotlin.analyzer.common.CommonPlatformAnalyzerServices +import org.jetbrains.kotlin.analyzer.common.CommonResolverForModuleFactory +import org.jetbrains.kotlin.builtins.DefaultBuiltIns +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.builtins.jvm.JvmBuiltIns +import org.jetbrains.kotlin.caches.resolve.* +import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys +import org.jetbrains.kotlin.cli.common.config.ContentRoot +import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot +import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot +import org.jetbrains.kotlin.cli.common.messages.MessageCollector +import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles +import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider +import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment +import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM +import org.jetbrains.kotlin.cli.jvm.config.* +import org.jetbrains.kotlin.cli.jvm.index.JavaRoot +import org.jetbrains.kotlin.config.* +import org.jetbrains.kotlin.container.getService +import org.jetbrains.kotlin.container.tryGetService +import org.jetbrains.kotlin.context.ProjectContext +import org.jetbrains.kotlin.context.withModule +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl +import org.jetbrains.kotlin.ide.konan.analyzer.NativeResolverForModuleFactory +import org.jetbrains.kotlin.js.config.JSConfigurationKeys +import org.jetbrains.kotlin.js.resolve.JsPlatformAnalyzerServices +import org.jetbrains.kotlin.library.impl.createKotlinLibrary +import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.platform.CommonPlatforms +import org.jetbrains.kotlin.platform.TargetPlatform +import org.jetbrains.kotlin.platform.js.JsPlatforms +import org.jetbrains.kotlin.platform.jvm.JvmPlatforms +import org.jetbrains.kotlin.platform.jvm.JvmPlatforms.unspecifiedJvmPlatform +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.resolve.CompilerEnvironment +import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices +import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics +import org.jetbrains.kotlin.resolve.jvm.JvmPlatformParameters +import org.jetbrains.kotlin.resolve.jvm.JvmResolverForModuleFactory +import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices +import org.jetbrains.kotlin.resolve.konan.platform.NativePlatformAnalyzerServices +import org.jetbrains.kotlin.resolve.lazy.ResolveSession +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice +import org.jetbrains.kotlin.util.slicedMap.WritableSlice +import org.jetbrains.kotlin.idea.resolve.ResolutionFacade +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +import org.jetbrains.kotlin.descriptors.konan.KlibModuleOrigin +import org.jetbrains.kotlin.extensions.ApplicationExtensionDescriptor +import org.jetbrains.kotlin.ide.konan.NativePlatformKindResolution +import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass +import org.jetbrains.kotlin.platform.IdePlatformKind +import org.jetbrains.kotlin.platform.impl.CommonIdePlatformKind +import org.jetbrains.kotlin.platform.impl.JsIdePlatformKind +import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind +import org.jetbrains.kotlin.platform.impl.NativeIdePlatformKind +import org.jetbrains.kotlin.platform.konan.NativePlatforms +import java.io.File + +const val JAR_SEPARATOR = "!/" +const val KLIB_EXTENSION = "klib" + +/** + * Kotlin as a service entry point + * + * Configures environment, analyses files and provides facilities to perform code processing without emitting bytecode + * + * $messageCollector: required by compiler infrastructure and will receive all compiler messages + * $body: optional and can be used to configure environment without creating local variable + */ +class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPlatform: Platform) : Disposable { + val configuration = CompilerConfiguration() + + init { + configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector) + } + + fun createCoreEnvironment(): KotlinCoreEnvironment { + System.setProperty("idea.io.use.nio2", "true") + + val configFiles = when (analysisPlatform) { + Platform.jvm, Platform.common -> EnvironmentConfigFiles.JVM_CONFIG_FILES + Platform.native -> EnvironmentConfigFiles.NATIVE_CONFIG_FILES + Platform.js -> EnvironmentConfigFiles.JS_CONFIG_FILES + } + + val environment = KotlinCoreEnvironment.createForProduction(this, configuration, configFiles) + val projectComponentManager = environment.project as MockComponentManager + + val projectFileIndex = CoreProjectFileIndex( + environment.project, + environment.configuration.getList(CLIConfigurationKeys.CONTENT_ROOTS) + ) + + val moduleManager = object : CoreModuleManager(environment.project, this) { + override fun getModules(): Array = arrayOf(projectFileIndex.module) + } + + CoreApplicationEnvironment.registerComponentInstance( + projectComponentManager.picoContainer, + ModuleManager::class.java, moduleManager + ) + + CoreApplicationEnvironment.registerExtensionPoint( + Extensions.getRootArea(), + OrderEnumerationHandler.EP_NAME, OrderEnumerationHandler.Factory::class.java + ) + + projectComponentManager.registerService( + ProjectFileIndex::class.java, + projectFileIndex + ) + + projectComponentManager.registerService( + ProjectRootManager::class.java, + CoreProjectRootManager(projectFileIndex) + ) + + registerExtensionPoint( + ApplicationExtensionDescriptor("org.jetbrains.kotlin.idePlatformKind", IdePlatformKind::class.java), + listOf( + CommonIdePlatformKind, + JvmIdePlatformKind, + JsIdePlatformKind, + NativeIdePlatformKind + ) + ) + + registerExtensionPoint( + IdePlatformKindResolution, + listOf( + CommonPlatformKindResolution(), + JvmPlatformKindResolution(), + JsPlatformKindResolution(), + NativePlatformKindResolution() + ) + ) + + return environment + } + + private fun createSourceModuleSearchScope(project: Project, sourceFiles: List): GlobalSearchScope = + when (analysisPlatform) { + Platform.jvm -> TopDownAnalyzerFacadeForJVM.newModuleSearchScope(project, sourceFiles) + Platform.js, Platform.common, Platform.native -> GlobalSearchScope.filesScope( + project, + sourceFiles.map { it.virtualFile }.toSet() + ) + } + + fun createResolutionFacade(environment: KotlinCoreEnvironment): Pair { + val projectContext = ProjectContext(environment.project, "Dokka") + val sourceFiles = environment.getSourceFiles() + + + val targetPlatform = when (analysisPlatform) { + Platform.js -> JsPlatforms.defaultJsPlatform + Platform.common -> CommonPlatforms.defaultCommonPlatform + Platform.native -> NativePlatforms.unspecifiedNativePlatform + Platform.jvm -> JvmPlatforms.defaultJvmPlatform + } + + val nativeLibraries = classpath.filter { it.extension == KLIB_EXTENSION } + .map { createNativeLibraryModuleInfo(it) } + + val library = object : LibraryModuleInfo { + override val analyzerServices: PlatformDependentAnalyzerServices = + analysisPlatform.analyzerServices() + override val name: Name = Name.special("") + override val platform: TargetPlatform = targetPlatform + override fun dependencies(): List = listOf(this) + override fun getLibraryRoots(): Collection = + classpath.filterNot { it.extension == KLIB_EXTENSION }.map { it.absolutePath } + } + + val module = object : ModuleInfo { + override val analyzerServices: PlatformDependentAnalyzerServices = + analysisPlatform.analyzerServices() + override val name: Name = Name.special("") + override val platform: TargetPlatform = targetPlatform + override fun dependencies(): List = listOf(this, library) + nativeLibraries + } + + val sourcesScope = createSourceModuleSearchScope(environment.project, sourceFiles) + val modulesContent: (ModuleInfo) -> ModuleContent = { + when (it) { + library -> ModuleContent(it, emptyList(), GlobalSearchScope.notScope(sourcesScope)) + module -> ModuleContent(it, emptyList(), GlobalSearchScope.allScope(environment.project)) + in nativeLibraries -> ModuleContent(it, emptyList(), GlobalSearchScope.notScope(sourcesScope)) + else -> throw IllegalArgumentException("Unexpected module info") + } + } + + var builtIns: JvmBuiltIns? = null + + val resolverForProject = when (analysisPlatform) { + Platform.jvm -> { + builtIns = JvmBuiltIns( + projectContext.storageManager, + JvmBuiltIns.Kind.FROM_CLASS_LOADER + ) // TODO we should use FROM_DEPENDENCIES + createJvmResolverForProject( + projectContext, + module, + library, + modulesContent, + sourcesScope, + builtIns + ) + } + Platform.common -> createCommonResolverForProject( + projectContext, + module, + library, + modulesContent, + environment + ) + Platform.js -> createJsResolverForProject(projectContext, module, library, modulesContent) + Platform.native -> createNativeResolverForProject(projectContext, module, library, modulesContent) + + } + val libraryModuleDescriptor = resolverForProject.descriptorForModule(library) + val moduleDescriptor = resolverForProject.descriptorForModule(module) + builtIns?.initialize(moduleDescriptor, true) + + val resolverForLibrary = + resolverForProject.resolverForModule(library) // Required before module to initialize library properly + val resolverForModule = resolverForProject.resolverForModule(module) + val libraryResolutionFacade = + DokkaResolutionFacade( + environment.project, + libraryModuleDescriptor, + resolverForLibrary + ) + val created = + DokkaResolutionFacade( + environment.project, + moduleDescriptor, + resolverForModule + ) + val projectComponentManager = environment.project as MockComponentManager + projectComponentManager.registerService(KotlinCacheService::class.java, + CoreKotlinCacheService(created) + ) + + return created to libraryResolutionFacade + } + + private fun Platform.analyzerServices() = when (this) { + Platform.js -> JsPlatformAnalyzerServices + Platform.common -> CommonPlatformAnalyzerServices + Platform.native -> NativePlatformAnalyzerServices + Platform.jvm -> JvmPlatformAnalyzerServices + } + + private fun createNativeLibraryModuleInfo(libraryFile: File): LibraryModuleInfo { + val kotlinLibrary = createKotlinLibrary(org.jetbrains.kotlin.konan.file.File(libraryFile.absolutePath), "",false) + return object : LibraryModuleInfo { + override val analyzerServices: PlatformDependentAnalyzerServices = + analysisPlatform.analyzerServices() + override val name: Name = Name.special("") + override val platform: TargetPlatform = NativePlatforms.unspecifiedNativePlatform + override fun dependencies(): List = listOf(this) + override fun getLibraryRoots(): Collection = listOf(libraryFile.absolutePath) + override val capabilities: Map, Any?> + get() = super.capabilities + (KlibModuleOrigin.CAPABILITY to kotlinLibrary) + } + } + + private fun createCommonResolverForProject( + projectContext: ProjectContext, + module: ModuleInfo, + library: LibraryModuleInfo, + modulesContent: (ModuleInfo) -> ModuleContent, + environment: KotlinCoreEnvironment + ): ResolverForProject { + return object : AbstractResolverForProject( + "Dokka", + projectContext, + modules = listOf(module, library) + ) { + override fun sdkDependency(module: ModuleInfo): ModuleInfo? = null + + override fun modulesContent(module: ModuleInfo): ModuleContent = modulesContent(module) + + override fun builtInsForModule(module: ModuleInfo): KotlinBuiltIns = DefaultBuiltIns.Instance + + override fun createResolverForModule( + descriptor: ModuleDescriptor, + moduleInfo: ModuleInfo + ): ResolverForModule = + CommonResolverForModuleFactory( + CommonAnalysisParameters { content -> + environment.createPackagePartProvider(content.moduleContentScope) + }, + CompilerEnvironment, + unspecifiedJvmPlatform, + true + ).createResolverForModule( + descriptor as ModuleDescriptorImpl, + projectContext.withModule(descriptor), + modulesContent(moduleInfo), + this, + LanguageVersionSettingsImpl.DEFAULT + ) + } + } + + private fun createJsResolverForProject( + projectContext: ProjectContext, + module: ModuleInfo, + library: LibraryModuleInfo, + modulesContent: (ModuleInfo) -> ModuleContent + ): ResolverForProject { + return object : AbstractResolverForProject( + "Dokka", + projectContext, + modules = listOf(module, library) + ) { + override fun modulesContent(module: ModuleInfo): ModuleContent = modulesContent(module) + override fun createResolverForModule( + descriptor: ModuleDescriptor, + moduleInfo: ModuleInfo + ): ResolverForModule = JsResolverForModuleFactory( + CompilerEnvironment + ).createResolverForModule( + descriptor as ModuleDescriptorImpl, + projectContext.withModule(descriptor), + modulesContent(moduleInfo), + this, + LanguageVersionSettingsImpl.DEFAULT + ) + + override fun builtInsForModule(module: ModuleInfo): KotlinBuiltIns = DefaultBuiltIns.Instance + + override fun sdkDependency(module: ModuleInfo): ModuleInfo? = null + } + } + + private fun createNativeResolverForProject( + projectContext: ProjectContext, + module: ModuleInfo, + library: LibraryModuleInfo, + modulesContent: (ModuleInfo) -> ModuleContent + ): ResolverForProject { + return object : AbstractResolverForProject( + "Dokka", + projectContext, + modules = module.dependencies() + ) { + override fun modulesContent(module: ModuleInfo): ModuleContent = modulesContent(module) + override fun createResolverForModule( + descriptor: ModuleDescriptor, + moduleInfo: ModuleInfo + ): ResolverForModule { + + return NativeResolverForModuleFactory( + PlatformAnalysisParameters.Empty, + CompilerEnvironment, + NativePlatforms.unspecifiedNativePlatform + ).createResolverForModule( + descriptor as ModuleDescriptorImpl, + projectContext.withModule(descriptor), + modulesContent(moduleInfo), + this, + LanguageVersionSettingsImpl.DEFAULT + ) + } + + override fun builtInsForModule(module: ModuleInfo): KotlinBuiltIns = DefaultBuiltIns.Instance + + override fun sdkDependency(module: ModuleInfo): ModuleInfo? = null + } + } + + private fun createJvmResolverForProject( + projectContext: ProjectContext, + module: ModuleInfo, + library: LibraryModuleInfo, + modulesContent: (ModuleInfo) -> ModuleContent, + sourcesScope: GlobalSearchScope, + builtIns: KotlinBuiltIns + ): ResolverForProject { + val javaRoots = classpath + .mapNotNull { + val rootFile = when (it.extension) { + "jar" -> StandardFileSystems.jar().findFileByPath("${it.absolutePath}$JAR_SEPARATOR") + else -> StandardFileSystems.local().findFileByPath(it.absolutePath) + } + rootFile?.let { JavaRoot(it, JavaRoot.RootType.BINARY) } + } + + return object : AbstractResolverForProject( + "Dokka", + projectContext, + modules = listOf(module, library) + ) { + override fun modulesContent(module: ModuleInfo): ModuleContent = + when (module) { + library -> ModuleContent(module, emptyList(), GlobalSearchScope.notScope(sourcesScope)) + module -> ModuleContent(module, emptyList(), sourcesScope) + else -> throw IllegalArgumentException("Unexpected module info") + } + + override fun builtInsForModule(module: ModuleInfo): KotlinBuiltIns = builtIns + + override fun createResolverForModule( + descriptor: ModuleDescriptor, + moduleInfo: ModuleInfo + ): ResolverForModule = JvmResolverForModuleFactory( + JvmPlatformParameters({ content -> + JvmPackagePartProvider( + configuration.languageVersionSettings, + content.moduleContentScope + ) + .apply { + addRoots(javaRoots, messageCollector) + } + }, { + val file = (it as? BinaryJavaClass)?.virtualFile ?: (it as JavaClassImpl).psi.containingFile.virtualFile + if (file in sourcesScope) + module + else + library + }), + CompilerEnvironment, + unspecifiedJvmPlatform + ).createResolverForModule( + descriptor as ModuleDescriptorImpl, + projectContext.withModule(descriptor), + modulesContent(moduleInfo), + this, + LanguageVersionSettingsImpl.DEFAULT + ) + + override fun sdkDependency(module: ModuleInfo): ModuleInfo? = null + } + } + + fun loadLanguageVersionSettings(languageVersionString: String?, apiVersionString: String?) { + val languageVersion = LanguageVersion.fromVersionString(languageVersionString) ?: LanguageVersion.LATEST_STABLE + val apiVersion = + apiVersionString?.let { ApiVersion.parse(it) } ?: ApiVersion.createByLanguageVersion(languageVersion) + configuration.languageVersionSettings = LanguageVersionSettingsImpl(languageVersion, apiVersion) + } + + /** + * Classpath for this environment. + */ + val classpath: List + get() = configuration.jvmClasspathRoots + + /** + * Adds list of paths to classpath. + * $paths: collection of files to add + */ + fun addClasspath(paths: List) { + if (analysisPlatform == Platform.js) { + configuration.addAll(JSConfigurationKeys.LIBRARIES, paths.map { it.absolutePath }) + } + configuration.addJvmClasspathRoots(paths) + } + + /** + * Adds path to classpath. + * $path: path to add + */ + fun addClasspath(path: File) { + if (analysisPlatform == Platform.js) { + configuration.add(JSConfigurationKeys.LIBRARIES, path.absolutePath) + } + configuration.addJvmClasspathRoot(path) + } + + /** + * List of source roots for this environment. + */ + val sources: List + get() = configuration.get(CLIConfigurationKeys.CONTENT_ROOTS) + ?.filterIsInstance() + ?.map { it.path } ?: emptyList() + + /** + * Adds list of paths to source roots. + * $list: collection of files to add + */ + fun addSources(list: List) { + list.forEach { + configuration.addKotlinSourceRoot(it) + val file = File(it) + if (file.isDirectory || file.extension == ".java") { + configuration.addJavaSourceRoot(file) + } + } + } + + fun addRoots(list: List) { + configuration.addAll(CLIConfigurationKeys.CONTENT_ROOTS, list) + } + + /** + * Disposes the environment and frees all associated resources. + */ + override fun dispose() { + Disposer.dispose(this) + } + + companion object { + private fun registerExtensionPoint( + appExtension: ApplicationExtensionDescriptor, + instances: List + ) { + if (Extensions.getRootArea().hasExtensionPoint(appExtension.extensionPointName)) + return + + appExtension.registerExtensionPoint() + instances.forEach(appExtension::registerExtension) + } + } +} + +fun contentRootFromPath(path: String): ContentRoot { + val file = File(path) + return if (file.extension == "java") JavaSourceRoot(file, null) else KotlinSourceRoot(path, false) +} + + +class DokkaResolutionFacade( + override val project: Project, + override val moduleDescriptor: ModuleDescriptor, + val resolverForModule: ResolverForModule +) : ResolutionFacade { + override fun analyzeWithAllCompilerChecks(elements: Collection): AnalysisResult { + throw UnsupportedOperationException() + } + + override fun tryGetFrontendService(element: PsiElement, serviceClass: Class): T? { + return resolverForModule.componentProvider.tryGetService(serviceClass) + } + + override fun resolveToDescriptor( + declaration: KtDeclaration, + bodyResolveMode: BodyResolveMode + ): DeclarationDescriptor { + return resolveSession.resolveToDescriptor(declaration) + } + + override fun analyze(elements: Collection, bodyResolveMode: BodyResolveMode): BindingContext { + throw UnsupportedOperationException() + } + + val resolveSession: ResolveSession get() = getFrontendService(ResolveSession::class.java) + + override fun analyze(element: KtElement, bodyResolveMode: BodyResolveMode): BindingContext { + if (element is KtDeclaration) { + val descriptor = resolveToDescriptor(element) + return object : BindingContext { + override fun getKeys(p0: WritableSlice?): Collection { + throw UnsupportedOperationException() + } + + override fun getType(p0: KtExpression): KotlinType? { + throw UnsupportedOperationException() + } + + override fun get(slice: ReadOnlySlice?, key: K): V? { + if (key != element) { + throw UnsupportedOperationException() + } + return when { + slice == BindingContext.DECLARATION_TO_DESCRIPTOR -> descriptor as V + slice == BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER && (element as KtParameter).hasValOrVar() -> descriptor as V + else -> null + } + } + + override fun getDiagnostics(): Diagnostics { + throw UnsupportedOperationException() + } + + override fun addOwnDataTo(p0: BindingTrace, p1: Boolean) { + throw UnsupportedOperationException() + } + + override fun getSliceContents(p0: ReadOnlySlice): ImmutableMap { + throw UnsupportedOperationException() + } + + } + } + throw UnsupportedOperationException() + } + + override fun getFrontendService(element: PsiElement, serviceClass: Class): T { + throw UnsupportedOperationException() + } + + override fun getFrontendService(serviceClass: Class): T { + return resolverForModule.componentProvider.getService(serviceClass) + } + + override fun getFrontendService(moduleDescriptor: ModuleDescriptor, serviceClass: Class): T { + return resolverForModule.componentProvider.getService(serviceClass) + } + + override fun getIdeService(serviceClass: Class): T { + throw UnsupportedOperationException() + } + +} diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/CallableFactory.kt b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/CallableFactory.kt new file mode 100644 index 00000000..ebfe20a5 --- /dev/null +++ b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/CallableFactory.kt @@ -0,0 +1,31 @@ +package org.jetbrains.dokka.analysis + +import com.intellij.psi.PsiField +import com.intellij.psi.PsiMethod +import org.jetbrains.dokka.links.Callable +import org.jetbrains.dokka.links.JavaClassReference +import org.jetbrains.dokka.links.TypeReference +import org.jetbrains.kotlin.descriptors.CallableDescriptor + +fun Callable.Companion.from(descriptor: CallableDescriptor) = with(descriptor) { + Callable( + name.asString(), + extensionReceiverParameter?.let { TypeReference.from(it) }, + valueParameters.mapNotNull { TypeReference.from(it) } + ) +} + +fun Callable.Companion.from(psi: PsiMethod) = with(psi) { + Callable( + name, + null, + parameterList.parameters.map { param -> JavaClassReference(param.type.canonicalText) }) +} + +fun Callable.Companion.from(psi: PsiField): Callable { + return Callable( + name = psi.name, + receiver = null, + params = emptyList() + ) +} diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/CoreKotlinCacheService.kt b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/CoreKotlinCacheService.kt new file mode 100644 index 00000000..68415875 --- /dev/null +++ b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/CoreKotlinCacheService.kt @@ -0,0 +1,42 @@ +package org.jetbrains.dokka.analysis + +import com.intellij.psi.PsiFile +import org.jetbrains.dokka.analysis.DokkaResolutionFacade +import org.jetbrains.kotlin.analyzer.ModuleInfo +import org.jetbrains.kotlin.caches.resolve.KotlinCacheService +import org.jetbrains.kotlin.idea.resolve.ResolutionFacade +import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.resolve.diagnostics.KotlinSuppressCache + + +class CoreKotlinCacheService(private val resolutionFacade: DokkaResolutionFacade) : KotlinCacheService { + override fun getResolutionFacade(elements: List): ResolutionFacade { + return resolutionFacade + } + + override fun getResolutionFacade( + elements: List, + platform: org.jetbrains.kotlin.platform.TargetPlatform + ): ResolutionFacade { + return resolutionFacade + } + + override fun getResolutionFacadeByFile( + file: PsiFile, + platform: org.jetbrains.kotlin.platform.TargetPlatform + ): ResolutionFacade? { + return resolutionFacade + } + + override fun getResolutionFacadeByModuleInfo( + moduleInfo: ModuleInfo, + platform: org.jetbrains.kotlin.platform.TargetPlatform + ): ResolutionFacade? { + return resolutionFacade + } + + override fun getSuppressionCache(): KotlinSuppressCache { + throw UnsupportedOperationException() + } + +} diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/CoreProjectFileIndex.kt b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/CoreProjectFileIndex.kt new file mode 100644 index 00000000..d0e0bb4f --- /dev/null +++ b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/CoreProjectFileIndex.kt @@ -0,0 +1,515 @@ +package org.jetbrains.dokka.analysis + +import com.intellij.openapi.Disposable +import com.intellij.openapi.components.BaseComponent +import com.intellij.openapi.extensions.ExtensionPointName +import com.intellij.openapi.module.Module +import com.intellij.openapi.project.Project +import com.intellij.openapi.projectRoots.Sdk +import com.intellij.openapi.projectRoots.SdkAdditionalData +import com.intellij.openapi.projectRoots.SdkModificator +import com.intellij.openapi.projectRoots.SdkTypeId +import com.intellij.openapi.roots.* +import com.intellij.openapi.roots.impl.ProjectOrderEnumerator +import com.intellij.openapi.util.Condition +import com.intellij.openapi.util.Key +import com.intellij.openapi.util.UserDataHolderBase +import com.intellij.openapi.vfs.StandardFileSystems +import com.intellij.openapi.vfs.VfsUtilCore.getVirtualFileForJar +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.VirtualFileFilter +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.util.messages.MessageBus +import org.jetbrains.jps.model.module.JpsModuleSourceRootType +import org.jetbrains.kotlin.cli.common.config.ContentRoot +import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot +import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot +import org.jetbrains.kotlin.cli.jvm.config.JvmContentRoot +import org.picocontainer.PicoContainer +import java.io.File + +/** + * Workaround for the lack of ability to create a ProjectFileIndex implementation using only + * classes from projectModel-{api,impl}. + */ +class CoreProjectFileIndex(private val project: Project, contentRoots: List) : ProjectFileIndex, ModuleFileIndex { + override fun iterateContent(p0: ContentIterator, p1: VirtualFileFilter?): Boolean { + throw UnsupportedOperationException() + } + + override fun iterateContentUnderDirectory(p0: VirtualFile, p1: ContentIterator, p2: VirtualFileFilter?): Boolean { + throw UnsupportedOperationException() + } + + override fun isInLibrary(p0: VirtualFile): Boolean { + throw UnsupportedOperationException() + } + + val sourceRoots = contentRoots.filter { it !is JvmClasspathRoot } + val classpathRoots = contentRoots.filterIsInstance() + + val module: Module = object : UserDataHolderBase(), Module { + override fun isDisposed(): Boolean { + throw UnsupportedOperationException() + } + + override fun getName(): String = "" + + override fun getModuleWithLibrariesScope(): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun getModuleWithDependentsScope(): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun getModuleWithDependenciesScope(): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun getModuleWithDependenciesAndLibrariesScope(p0: Boolean): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun getModuleTestsWithDependentsScope(): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun getModuleScope(): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun getModuleRuntimeScope(p0: Boolean): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun getExtensions(p0: ExtensionPointName): Array { + throw UnsupportedOperationException() + } + + override fun getComponent(interfaceClass: Class): T? { + if (interfaceClass == ModuleRootManager::class.java) { + return moduleRootManager as T + } + throw UnsupportedOperationException() + } + + override fun getDisposed(): Condition<*> { + throw UnsupportedOperationException() + } + + override fun getPicoContainer(): PicoContainer { + throw UnsupportedOperationException() + } + + override fun getMessageBus(): MessageBus { + throw UnsupportedOperationException() + } + + override fun dispose() { + throw UnsupportedOperationException() + } + } + + private val sdk: Sdk = object : Sdk, RootProvider { + override fun getFiles(rootType: OrderRootType): Array = classpathRoots + .mapNotNull { StandardFileSystems.local().findFileByPath(it.file.path) } + .toTypedArray() + + override fun addRootSetChangedListener(p0: RootProvider.RootSetChangedListener) { + throw UnsupportedOperationException() + } + + override fun addRootSetChangedListener(p0: RootProvider.RootSetChangedListener, p1: Disposable) { + throw UnsupportedOperationException() + } + + override fun getUrls(p0: OrderRootType): Array { + throw UnsupportedOperationException() + } + + override fun removeRootSetChangedListener(p0: RootProvider.RootSetChangedListener) { + throw UnsupportedOperationException() + } + + override fun getSdkModificator(): SdkModificator { + throw UnsupportedOperationException() + } + + override fun getName(): String = "" + + override fun getRootProvider(): RootProvider = this + + override fun getHomePath(): String? { + throw UnsupportedOperationException() + } + + override fun getVersionString(): String? { + throw UnsupportedOperationException() + } + + override fun getSdkAdditionalData(): SdkAdditionalData? { + throw UnsupportedOperationException() + } + + override fun clone(): Any { + throw UnsupportedOperationException() + } + + override fun getSdkType(): SdkTypeId { + throw UnsupportedOperationException() + } + + override fun getHomeDirectory(): VirtualFile? { + throw UnsupportedOperationException() + } + + override fun getUserData(p0: Key): T? { + throw UnsupportedOperationException() + } + + override fun putUserData(p0: Key, p1: T?) { + throw UnsupportedOperationException() + } + } + + private val moduleSourceOrderEntry = object : ModuleSourceOrderEntry { + override fun getFiles(p0: OrderRootType): Array { + throw UnsupportedOperationException() + } + + override fun getUrls(p0: OrderRootType): Array { + throw UnsupportedOperationException() + } + + override fun accept(p0: RootPolicy, p1: R?): R { + throw UnsupportedOperationException() + } + + + override fun getPresentableName(): String { + throw UnsupportedOperationException() + } + + override fun getOwnerModule(): Module = module + + + override fun isValid(): Boolean { + throw UnsupportedOperationException() + } + + override fun compareTo(other: OrderEntry?): Int { + throw UnsupportedOperationException() + } + + override fun getRootModel(): ModuleRootModel = moduleRootManager + + override fun isSynthetic(): Boolean { + throw UnsupportedOperationException() + } + } + + private val sdkOrderEntry = object : JdkOrderEntry { + override fun getFiles(p0: OrderRootType): Array { + throw UnsupportedOperationException() + } + + override fun getUrls(p0: OrderRootType): Array { + throw UnsupportedOperationException() + } + + override fun accept(p0: RootPolicy, p1: R?): R { + throw UnsupportedOperationException() + } + + override fun getJdkName(): String? { + throw UnsupportedOperationException() + } + + override fun getJdk(): Sdk = sdk + + override fun getPresentableName(): String { + throw UnsupportedOperationException() + } + + override fun getOwnerModule(): Module { + throw UnsupportedOperationException() + } + + override fun isValid(): Boolean { + throw UnsupportedOperationException() + } + + override fun getRootFiles(p0: OrderRootType): Array { + throw UnsupportedOperationException() + } + + override fun getRootUrls(p0: OrderRootType): Array { + throw UnsupportedOperationException() + } + + override fun compareTo(other: OrderEntry?): Int { + throw UnsupportedOperationException() + } + + override fun isSynthetic(): Boolean { + throw UnsupportedOperationException() + } + + } + + inner class MyModuleRootManager : ModuleRootManager() { + override fun getExternalSource(): ProjectModelExternalSource? { + throw UnsupportedOperationException() + } + + override fun getExcludeRoots(): Array { + throw UnsupportedOperationException() + } + + override fun getContentEntries(): Array { + throw UnsupportedOperationException() + } + + override fun getExcludeRootUrls(): Array { + throw UnsupportedOperationException() + } + + override fun processOrder(p0: RootPolicy, p1: R): R { + throw UnsupportedOperationException() + } + + override fun getSourceRoots(p0: Boolean): Array { + throw UnsupportedOperationException() + } + + override fun getSourceRoots(): Array { + throw UnsupportedOperationException() + } + + override fun getSourceRoots(p0: JpsModuleSourceRootType<*>): MutableList { + throw UnsupportedOperationException() + } + + override fun getSourceRoots(p0: MutableSet>): MutableList { + throw UnsupportedOperationException() + } + + override fun getContentRoots(): Array { + throw UnsupportedOperationException() + } + + override fun orderEntries(): OrderEnumerator = + ProjectOrderEnumerator(project, null).using(object : RootModelProvider { + override fun getModules(): Array = arrayOf(module) + + override fun getRootModel(p0: Module): ModuleRootModel = this@MyModuleRootManager + }) + + override fun getModuleExtension(p0: Class): T { + throw UnsupportedOperationException() + } + + override fun getDependencyModuleNames(): Array { + throw UnsupportedOperationException() + } + + override fun getModule(): Module = this@CoreProjectFileIndex.module + + override fun isSdkInherited(): Boolean { + throw UnsupportedOperationException() + } + + override fun getOrderEntries(): Array = arrayOf(moduleSourceOrderEntry, sdkOrderEntry) + + override fun getSourceRootUrls(): Array { + throw UnsupportedOperationException() + } + + override fun getSourceRootUrls(p0: Boolean): Array { + throw UnsupportedOperationException() + } + + override fun getSdk(): Sdk? { + throw UnsupportedOperationException() + } + + override fun getContentRootUrls(): Array { + throw UnsupportedOperationException() + } + + override fun getModuleDependencies(): Array { + throw UnsupportedOperationException() + } + + override fun getModuleDependencies(p0: Boolean): Array { + throw UnsupportedOperationException() + } + + override fun getModifiableModel(): ModifiableRootModel { + throw UnsupportedOperationException() + } + + override fun isDependsOn(p0: Module): Boolean { + throw UnsupportedOperationException() + } + + override fun getFileIndex(): ModuleFileIndex { + return this@CoreProjectFileIndex + } + + override fun getDependencies(): Array { + throw UnsupportedOperationException() + } + + override fun getDependencies(p0: Boolean): Array { + throw UnsupportedOperationException() + } + } + + val moduleRootManager = MyModuleRootManager() + + override fun getContentRootForFile(p0: VirtualFile): VirtualFile? { + throw UnsupportedOperationException() + } + + override fun getContentRootForFile(p0: VirtualFile, p1: Boolean): VirtualFile? { + throw UnsupportedOperationException() + } + + override fun getPackageNameByDirectory(p0: VirtualFile): String? { + throw UnsupportedOperationException() + } + + override fun isInLibrarySource(file: VirtualFile): Boolean = false + + override fun getClassRootForFile(file: VirtualFile): VirtualFile? = + classpathRoots.firstOrNull { it.contains(file) }?.let { StandardFileSystems.local().findFileByPath(it.file.path) } + + override fun getOrderEntriesForFile(file: VirtualFile): List = + if (classpathRoots.contains(file)) listOf(sdkOrderEntry) else emptyList() + + override fun isInLibraryClasses(file: VirtualFile): Boolean = classpathRoots.contains(file) + + override fun isExcluded(p0: VirtualFile): Boolean { + throw UnsupportedOperationException() + } + + override fun getSourceRootForFile(p0: VirtualFile): VirtualFile? { + throw UnsupportedOperationException() + } + + override fun isUnderIgnored(p0: VirtualFile): Boolean { + throw UnsupportedOperationException() + } + + override fun isLibraryClassFile(p0: VirtualFile): Boolean { + throw UnsupportedOperationException() + } + + override fun getModuleForFile(file: VirtualFile): Module? = + if (sourceRoots.contains(file)) module else null + + private fun List.contains(file: VirtualFile): Boolean = any { it.contains(file) } + + override fun getModuleForFile(p0: VirtualFile, p1: Boolean): Module? { + throw UnsupportedOperationException() + } + + override fun isInSource(p0: VirtualFile): Boolean { + throw UnsupportedOperationException() + } + + override fun isIgnored(p0: VirtualFile): Boolean { + throw UnsupportedOperationException() + } + + override fun isContentSourceFile(p0: VirtualFile): Boolean { + throw UnsupportedOperationException() + } + + override fun isInSourceContent(file: VirtualFile): Boolean = sourceRoots.contains(file) + + override fun iterateContent(p0: ContentIterator): Boolean { + throw UnsupportedOperationException() + } + + override fun isInContent(p0: VirtualFile): Boolean { + throw UnsupportedOperationException() + } + + override fun iterateContentUnderDirectory(p0: VirtualFile, p1: ContentIterator): Boolean { + throw UnsupportedOperationException() + } + + override fun isInTestSourceContent(file: VirtualFile): Boolean = false + + override fun isUnderSourceRootOfType(p0: VirtualFile, p1: MutableSet>): Boolean { + throw UnsupportedOperationException() + } + + override fun getOrderEntryForFile(p0: VirtualFile): OrderEntry? { + throw UnsupportedOperationException() + } +} + +class CoreProjectRootManager(val projectFileIndex: CoreProjectFileIndex) : ProjectRootManager() { + override fun orderEntries(): OrderEnumerator { + throw UnsupportedOperationException() + } + + override fun orderEntries(p0: MutableCollection): OrderEnumerator { + throw UnsupportedOperationException() + } + + override fun getContentRootsFromAllModules(): Array { + throw UnsupportedOperationException() + } + + override fun setProjectSdk(p0: Sdk?) { + throw UnsupportedOperationException() + } + + override fun setProjectSdkName(p0: String) { + throw UnsupportedOperationException() + } + + override fun getModuleSourceRoots(p0: MutableSet>): MutableList { + throw UnsupportedOperationException() + } + + override fun getContentSourceRoots(): Array { + throw UnsupportedOperationException() + } + + override fun getFileIndex(): ProjectFileIndex = projectFileIndex + + override fun getProjectSdkName(): String? { + throw UnsupportedOperationException() + } + + override fun getProjectSdk(): Sdk? { + throw UnsupportedOperationException() + } + + override fun getContentRoots(): Array { + throw UnsupportedOperationException() + } + + override fun getContentRootUrls(): MutableList { + throw UnsupportedOperationException() + } + +} + +fun ContentRoot.contains(file: VirtualFile) = when (this) { + is JvmContentRoot -> { + val path = if (file.fileSystem.protocol == StandardFileSystems.JAR_PROTOCOL) + getVirtualFileForJar(file)?.path ?: file.path + else + file.path + File(path).startsWith(this.file.absoluteFile) + } + is KotlinSourceRoot -> File(file.path).startsWith(File(this.path).absoluteFile) + else -> false +} diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRIFactory.kt b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRIFactory.kt new file mode 100644 index 00000000..513817f3 --- /dev/null +++ b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRIFactory.kt @@ -0,0 +1,38 @@ +package org.jetbrains.dokka.analysis + +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiField +import com.intellij.psi.PsiMethod +import org.jetbrains.dokka.links.Callable +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.links.DriTarget +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf +import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull + +fun DRI.Companion.from(descriptor: DeclarationDescriptor) = descriptor.parentsWithSelf.run { + val callable = firstIsInstanceOrNull() + DRI( + firstIsInstanceOrNull()?.fqName?.asString(), + (filterIsInstance() + filterIsInstance()).toList() + .takeIf { it.isNotEmpty() } + ?.asReversed() + ?.joinToString(separator = ".") { it.name.asString() }, + callable?.let { Callable.from(it) }, + DriTarget.from(descriptor) + ) +} + +fun DRI.Companion.from(psi: PsiElement) = psi.parentsWithSelf.run { + val psiMethod = firstIsInstanceOrNull() + val psiField = firstIsInstanceOrNull() + val classes = filterIsInstance().toList() + DRI( + classes.lastOrNull()?.qualifiedName?.substringBeforeLast('.', ""), + classes.toList().takeIf { it.isNotEmpty() }?.asReversed()?.mapNotNull { it.name }?.joinToString("."), + psiMethod?.let { Callable.from(it) } ?: psiField?.let { Callable.from(it) }, + DriTarget.from(psi) + ) +} diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRITargetFactory.kt b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRITargetFactory.kt new file mode 100644 index 00000000..031a5a32 --- /dev/null +++ b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRITargetFactory.kt @@ -0,0 +1,44 @@ +package org.jetbrains.dokka.analysis + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiMethod +import com.intellij.psi.PsiParameter +import com.intellij.psi.PsiTypeParameter +import org.jetbrains.dokka.links.DriTarget +import org.jetbrains.dokka.links.PointingToCallableParameters +import org.jetbrains.dokka.links.PointingToDeclaration +import org.jetbrains.dokka.links.PointingToGenericParameters +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.ParameterDescriptor +import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf +import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull + +fun DriTarget.Companion.from(descriptor: DeclarationDescriptor): DriTarget = descriptor.parentsWithSelf.run { + return when (descriptor) { + is TypeParameterDescriptor -> PointingToGenericParameters(descriptor.index) + else -> { + val callable = firstIsInstanceOrNull() + val params = + callable?.let { listOfNotNull(it.extensionReceiverParameter) + it.valueParameters }.orEmpty() + val parameterDescriptor = firstIsInstanceOrNull() + + parameterDescriptor?.let { PointingToCallableParameters(params.indexOf(it)) } + ?: PointingToDeclaration + } + } +} + + +fun DriTarget.Companion.from(psi: PsiElement): DriTarget = psi.parentsWithSelf.run { + return when (psi) { + is PsiTypeParameter -> PointingToGenericParameters(psi.index) + else -> firstIsInstanceOrNull()?.let { + val callable = firstIsInstanceOrNull() + val params = (callable?.parameterList?.parameters).orEmpty() + PointingToCallableParameters(params.indexOf(it)) + } ?: PointingToDeclaration + } +} diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/Documentable.kt b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/Documentable.kt new file mode 100644 index 00000000..0c55fed4 --- /dev/null +++ b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/Documentable.kt @@ -0,0 +1,14 @@ +package org.jetbrains.dokka.analysis + +import com.intellij.psi.PsiNamedElement +import org.jetbrains.dokka.model.DocumentableSource +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.load.kotlin.toSourceElement + +class DescriptorDocumentableSource(val descriptor: DeclarationDescriptor) : DocumentableSource { + override val path = descriptor.toSourceElement.containingFile.toString() +} + +class PsiDocumentableSource(val psi: PsiNamedElement) : DocumentableSource { + override val path = psi.containingFile.virtualFile.path +} diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/EnvironmentAndFacade.kt b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/EnvironmentAndFacade.kt new file mode 100644 index 00000000..9d15123a --- /dev/null +++ b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/EnvironmentAndFacade.kt @@ -0,0 +1,59 @@ +package org.jetbrains.dokka.analysis + +import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.dokka.Platform +import org.jetbrains.dokka.utilities.DokkaLogger +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.utils.PathUtil +import java.io.File + +internal fun createEnvironmentAndFacade( + logger: DokkaLogger, + configuration: DokkaConfiguration, + pass: DokkaConfiguration.PassConfiguration +): EnvironmentAndFacade = + AnalysisEnvironment(DokkaMessageCollector(logger), pass.analysisPlatform).run { + if (analysisPlatform == Platform.jvm) { + addClasspath(PathUtil.getJdkClassesRootsFromCurrentJre()) + } + pass.classpath.forEach { addClasspath(File(it)) } + + addSources( + (pass.sourceRoots + configuration.passesConfigurations.filter { it.sourceSetID in pass.dependentSourceSets } + .flatMap { it.sourceRoots }) + .map { it.path } + ) + + loadLanguageVersionSettings(pass.languageVersion, pass.apiVersion) + + val environment = createCoreEnvironment() + val (facade, _) = createResolutionFacade(environment) + EnvironmentAndFacade(environment, facade) + } + +class DokkaMessageCollector(private 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.info(MessageRenderer.PLAIN_FULL_PATHS.render(severity, message, location)) + } + + override fun hasErrors() = seenErrors +} + +// It is not data class due to ill-defined equals +class EnvironmentAndFacade(val environment: KotlinCoreEnvironment, val facade: DokkaResolutionFacade) { + operator fun component1() = environment + operator fun component2() = facade +} diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/JavaResolveExtension.kt b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/JavaResolveExtension.kt new file mode 100644 index 00000000..ab6bec9c --- /dev/null +++ b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/JavaResolveExtension.kt @@ -0,0 +1,128 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:JvmName("JavaResolutionUtils") + +package org.jetbrains.dokka.analysis + +import com.intellij.psi.* +import org.jetbrains.kotlin.asJava.unwrapped +import org.jetbrains.kotlin.caches.resolve.KotlinCacheService +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.idea.resolve.ResolutionFacade +import org.jetbrains.kotlin.incremental.components.NoLookupLocation +import org.jetbrains.kotlin.load.java.sources.JavaSourceElement +import org.jetbrains.kotlin.load.java.structure.* +import org.jetbrains.kotlin.load.java.structure.impl.* +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.platform.jvm.JvmPlatforms +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver +import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter +import org.jetbrains.kotlin.resolve.scopes.MemberScope + +// TODO: Remove that file + +@JvmOverloads +fun PsiMethod.getJavaMethodDescriptor(resolutionFacade: ResolutionFacade = javaResolutionFacade()): DeclarationDescriptor? { + val method = originalElement as? PsiMethod ?: return null + if (method.containingClass == null || !Name.isValidIdentifier(method.name)) return null + val resolver = method.getJavaDescriptorResolver(resolutionFacade) + return when { + method.isConstructor -> resolver?.resolveConstructor(JavaConstructorImpl(method)) + else -> resolver?.resolveMethod(JavaMethodImpl(method)) + } +} + +@JvmOverloads +fun PsiClass.getJavaClassDescriptor(resolutionFacade: ResolutionFacade = javaResolutionFacade()): ClassDescriptor? { + val psiClass = originalElement as? PsiClass ?: return null + return psiClass.getJavaDescriptorResolver(resolutionFacade)?.resolveClass(JavaClassImpl(psiClass)) +} + +@JvmOverloads +fun PsiField.getJavaFieldDescriptor(resolutionFacade: ResolutionFacade = javaResolutionFacade()): PropertyDescriptor? { + val field = originalElement as? PsiField ?: return null + return field.getJavaDescriptorResolver(resolutionFacade)?.resolveField(JavaFieldImpl(field)) +} + +@JvmOverloads +fun PsiMember.getJavaMemberDescriptor(resolutionFacade: ResolutionFacade = javaResolutionFacade()): DeclarationDescriptor? { + return when (this) { + is PsiEnumConstant -> containingClass?.getJavaClassDescriptor(resolutionFacade) + is PsiClass -> getJavaClassDescriptor(resolutionFacade) + is PsiMethod -> getJavaMethodDescriptor(resolutionFacade) + is PsiField -> getJavaFieldDescriptor(resolutionFacade) + else -> null + } +} + +@JvmOverloads +fun PsiMember.getJavaOrKotlinMemberDescriptor(resolutionFacade: ResolutionFacade = javaResolutionFacade()): DeclarationDescriptor? { + val callable = unwrapped + return when (callable) { + is PsiMember -> getJavaMemberDescriptor(resolutionFacade) + is KtDeclaration -> { + val descriptor = resolutionFacade.resolveToDescriptor(callable) + if (descriptor is ClassDescriptor && this is PsiMethod) descriptor.unsubstitutedPrimaryConstructor else descriptor + } + else -> null + } +} + +private fun PsiElement.getJavaDescriptorResolver(resolutionFacade: ResolutionFacade): JavaDescriptorResolver? { + return resolutionFacade.tryGetFrontendService(this, JavaDescriptorResolver::class.java) +} + +private fun JavaDescriptorResolver.resolveMethod(method: JavaMethod): DeclarationDescriptor? { + return getContainingScope(method) + ?.getContributedDescriptors(nameFilter = { true }, kindFilter = DescriptorKindFilter.CALLABLES) + ?.filterIsInstance() + ?.findByJavaElement(method) +} + +private fun JavaDescriptorResolver.resolveConstructor(constructor: JavaConstructor): ConstructorDescriptor? { + return resolveClass(constructor.containingClass)?.constructors?.findByJavaElement(constructor) +} + +private fun JavaDescriptorResolver.resolveField(field: JavaField): PropertyDescriptor? { + return getContainingScope(field)?.getContributedVariables(field.name, NoLookupLocation.FROM_IDE)?.findByJavaElement(field) +} + +private fun JavaDescriptorResolver.getContainingScope(member: JavaMember): MemberScope? { + val containingClass = resolveClass(member.containingClass) + return if (member.isStatic) + containingClass?.staticScope + else + containingClass?.defaultType?.memberScope +} + +private fun Collection.findByJavaElement(javaElement: JavaElement): T? { + return firstOrNull { member -> + val memberJavaElement = (member.original.source as? JavaSourceElement)?.javaElement + when { + memberJavaElement == javaElement -> + true + memberJavaElement is JavaElementImpl<*> && javaElement is JavaElementImpl<*> -> + memberJavaElement.psi.isEquivalentTo(javaElement.psi) + else -> + false + } + } +} + +fun PsiElement.javaResolutionFacade() = + KotlinCacheService.getInstance(project).getResolutionFacadeByFile(this.originalElement.containingFile, JvmPlatforms.defaultJvmPlatform)!! diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/KotlinAnalysis.kt b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/KotlinAnalysis.kt new file mode 100644 index 00000000..cd07b2a3 --- /dev/null +++ b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/KotlinAnalysis.kt @@ -0,0 +1,46 @@ +@file:Suppress("FunctionName") + +package org.jetbrains.dokka.analysis + +import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.dokka.model.SourceSetCache +import org.jetbrains.dokka.model.SourceSetData +import org.jetbrains.dokka.model.SourceSetDependent +import org.jetbrains.dokka.plugability.DokkaContext + +fun KotlinAnalysis(context: DokkaContext): KotlinAnalysis { + val environments = context.configuration.passesConfigurations + .associate { passConfiguration -> + context.sourceSetCache.getSourceSet(passConfiguration) to createEnvironmentAndFacade( + logger = context.logger, + configuration = context.configuration, + pass = passConfiguration + ) + } + + return KotlinAnalysisImpl(context.sourceSetCache, environments) +} + +interface KotlinAnalysis : SourceSetDependent { + override fun get(key: SourceSetData): EnvironmentAndFacade + operator fun get(sourceSetID: String): EnvironmentAndFacade + operator fun get(passConfiguration: DokkaConfiguration.PassConfiguration): EnvironmentAndFacade +} + +internal class KotlinAnalysisImpl( + private val sourceSetCache: SourceSetCache, + private val environments: SourceSetDependent +) : KotlinAnalysis, SourceSetDependent by environments { + + override fun get(key: SourceSetData): EnvironmentAndFacade { + return environments[key] ?: throw IllegalStateException("Missing EnvironmentAndFacade for sourceSet $key") + } + + override fun get(sourceSetID: String): EnvironmentAndFacade { + return environments.entries.first { (sourceSet, _) -> sourceSet.sourceSetID == sourceSetID }.value + } + + override fun get(passConfiguration: DokkaConfiguration.PassConfiguration): EnvironmentAndFacade { + return get(sourceSetCache.getSourceSet(passConfiguration)) + } +} diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/TypeReferenceFactory.kt b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/TypeReferenceFactory.kt new file mode 100644 index 00000000..e07672d4 --- /dev/null +++ b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/TypeReferenceFactory.kt @@ -0,0 +1,51 @@ +package org.jetbrains.dokka.analysis + +import com.intellij.psi.PsiClass +import org.jetbrains.dokka.links.* +import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor +import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe +import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.TypeProjection + +fun TypeReference.Companion.from(d: ReceiverParameterDescriptor): TypeReference? = + when (d.value) { + is ExtensionReceiver -> fromPossiblyNullable(d.type) + else -> run { + println("Unknown value type for $d") + null + } + } + +fun TypeReference.Companion.from(d: ValueParameterDescriptor): TypeReference? = + fromPossiblyNullable(d.type) + +fun TypeReference.Companion.from(p: PsiClass) = TypeReference + +private fun TypeReference.Companion.fromPossiblyNullable(t: KotlinType, self: KotlinType? = null): TypeReference = + from(t, self).let { if (t.isMarkedNullable) Nullable(it) else it } + +private fun TypeReference.Companion.from(t: KotlinType, self: KotlinType? = null): TypeReference = + if (self is KotlinType && self.constructor == t.constructor && self.arguments == t.arguments) + SelfType + else when (val d = t.constructor.declarationDescriptor) { + is TypeParameterDescriptor -> TypeParam( + d.upperBounds.map { fromPossiblyNullable(it, self ?: t) } + ) + else -> TypeConstructor( + t.constructorName.orEmpty(), + t.arguments.map { fromProjection(it, self) } + ) + } + +private fun TypeReference.Companion.fromProjection(t: TypeProjection, r: KotlinType? = null): TypeReference = + if (t.isStarProjection) { + StarProjection + } else { + fromPossiblyNullable(t.type, r) + } + +private val KotlinType.constructorName + get() = constructor.declarationDescriptor?.fqNameSafe?.asString() -- cgit From 8cb6efc97f8fa321381c95cc5f85a3ce7bc13c3f Mon Sep 17 00:00:00 2001 From: Kamil Doległo Date: Fri, 19 Jun 2020 14:08:49 +0200 Subject: Remove SourceSetDataCache, rename PassConfiguration to DokkaSourceSet and use it instead of SourceSetData --- core/src/main/kotlin/DokkaBootstrapImpl.kt | 6 +- core/src/main/kotlin/DokkaGenerator.kt | 25 ++-- core/src/main/kotlin/configuration.kt | 4 +- core/src/main/kotlin/defaultConfiguration.kt | 6 +- core/src/main/kotlin/model/Documentable.kt | 59 +++++---- core/src/main/kotlin/model/SourceSetData.kt | 38 ------ .../main/kotlin/model/documentableProperties.kt | 12 +- core/src/main/kotlin/model/documentableUtils.kt | 12 +- core/src/main/kotlin/pages/ContentNodes.kt | 35 ++--- core/src/main/kotlin/plugability/DokkaContext.kt | 8 +- .../sources/SourceToDocumentableTranslator.kt | 4 +- .../dokka/analysis/EnvironmentAndFacade.kt | 10 +- .../org/jetbrains/dokka/analysis/KotlinAnalysis.kt | 24 ++-- .../kotlin/allModulePage/MultimodulePageCreator.kt | 10 +- .../src/main/kotlin/renderers/DefaultRenderer.kt | 28 ++-- .../src/main/kotlin/renderers/html/HtmlRenderer.kt | 60 +++++---- .../main/kotlin/renderers/html/NavigationPage.kt | 8 +- .../kotlin/renderers/html/htmlPreprocessors.kt | 2 +- .../resolvers/local/DefaultLocationProvider.kt | 16 +-- .../kotlin/resolvers/local/LocationProvider.kt | 4 +- .../resolvers/local/MultimoduleLocationProvider.kt | 6 +- .../main/kotlin/signatures/JvmSignatureUtils.kt | 12 +- .../kotlin/signatures/KotlinSignatureProvider.kt | 16 ++- .../DeprecatedDocumentableFilterTransformer.kt | 10 +- .../DocumentableVisibilityFilterTransformer.kt | 36 +++-- .../EmptyPackagesFilterTransformer.kt | 8 +- .../InheritorsExtractorTransformer.kt | 7 +- .../ModuleAndPackageDocumentationTransformer.kt | 9 +- .../documentables/ReportUndocumentedTransformer.kt | 38 ++---- .../pages/comments/CommentsToContentConverter.kt | 4 +- .../pages/comments/DocTagToContentConverter.kt | 4 +- .../pages/samples/SamplesTransformer.kt | 13 +- .../pages/sourcelinks/SourceLinksTransformer.kt | 18 +-- .../DefaultDescriptorToDocumentableTranslator.kt | 19 +-- .../documentables/DefaultPageCreator.kt | 147 +++++++++++++++------ .../documentables/PageContentBuilder.kt | 76 +++++------ .../psi/DefaultPsiToDocumentableTranslator.kt | 9 +- .../kotlin/content/params/ContentForParamsTest.kt | 14 +- .../base/src/test/kotlin/model/InheritorsTest.kt | 6 +- .../test/kotlin/renderers/RenderingOnlyTestBase.kt | 9 +- .../test/kotlin/renderers/html/DivergentTest.kt | 32 ++++- .../renderers/html/SourceSetDependentHintTest.kt | 26 +++- .../test/kotlin/renderers/html/defaultSourceSet.kt | 30 +++++ plugins/gfm/src/main/kotlin/GfmPlugin.kt | 19 +-- .../main/kotlin/javadoc/JavadocLocationProvider.kt | 35 ++--- .../src/main/kotlin/javadoc/JavadocPageCreator.kt | 19 +-- .../main/kotlin/javadoc/KorteJavadocRenderer.kt | 10 +- .../kotlin/javadoc/pages/JavadocContentNodes.kt | 22 +-- .../main/kotlin/javadoc/pages/JavadocPageNodes.kt | 2 +- runners/cli/src/main/kotlin/cli/main.kt | 24 ++-- .../jetbrains/dokka/gradle/DokkaCollectorTask.kt | 2 +- .../kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt | 22 +-- .../dokka/gradle/configurationImplementations.kt | 98 +++++++++----- .../main/kotlin/org/jetbrains/dokka/gradle/main.kt | 2 +- runners/maven-plugin/src/main/kotlin/DokkaMojo.kt | 9 +- .../src/main/kotlin/testApi/context/MockContext.kt | 6 +- .../testApi/testRunner/DokkaTestGenerator.kt | 8 +- .../main/kotlin/testApi/testRunner/TestRunner.kt | 22 ++- 58 files changed, 656 insertions(+), 564 deletions(-) delete mode 100644 core/src/main/kotlin/model/SourceSetData.kt create mode 100644 plugins/base/src/test/kotlin/renderers/html/defaultSourceSet.kt (limited to 'kotlin-analysis') diff --git a/core/src/main/kotlin/DokkaBootstrapImpl.kt b/core/src/main/kotlin/DokkaBootstrapImpl.kt index 94792303..bd632546 100644 --- a/core/src/main/kotlin/DokkaBootstrapImpl.kt +++ b/core/src/main/kotlin/DokkaBootstrapImpl.kt @@ -84,7 +84,7 @@ class DokkaBootstrapImpl : DokkaBootstrap { fun configure(logger: DokkaLogger, configuration: DokkaConfigurationImpl) = with(configuration) { - fun defaultLinks(config: PassConfigurationImpl): List { + fun defaultLinks(config: DokkaSourceSetImpl): List { val links = mutableListOf() if (!config.noJdkLink) links += DokkaConfiguration.ExternalDocumentationLink @@ -100,8 +100,8 @@ class DokkaBootstrapImpl : DokkaBootstrap { val configurationWithLinks = configuration.copy( - passesConfigurations = - passesConfigurations.map { + sourceSets = + sourceSets.map { val links: List = it.externalDocumentationLinks + defaultLinks(it) it.copy(externalDocumentationLinks = links) diff --git a/core/src/main/kotlin/DokkaGenerator.kt b/core/src/main/kotlin/DokkaGenerator.kt index b88c6223..ce8d229a 100644 --- a/core/src/main/kotlin/DokkaGenerator.kt +++ b/core/src/main/kotlin/DokkaGenerator.kt @@ -1,8 +1,7 @@ package org.jetbrains.dokka import org.jetbrains.dokka.model.DModule -import org.jetbrains.dokka.model.SourceSetCache -import org.jetbrains.dokka.model.SourceSetData +import org.jetbrains.dokka.DokkaConfiguration.* import org.jetbrains.dokka.pages.RootPageNode import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.DokkaPlugin @@ -18,13 +17,11 @@ class DokkaGenerator( private val logger: DokkaLogger ) { fun generate() = timed { - val sourceSetsCache = SourceSetCache() - report("Initializing plugins") - val context = initializePlugins(configuration, logger, sourceSetsCache) + val context = initializePlugins(configuration, logger) report("Creating documentation models") - val modulesFromPlatforms = createDocumentationModels(context, sourceSetsCache) + val modulesFromPlatforms = createDocumentationModels(context) report("Transforming documentation model before merging") val transformedDocumentationBeforeMerge = transformDocumentationModelBeforeMerge(modulesFromPlatforms, context) @@ -48,9 +45,8 @@ class DokkaGenerator( }.dump("\n\n === TIME MEASUREMENT ===\n") fun generateAllModulesPage() = timed { - val sourceSetsCache = SourceSetCache() report("Initializing plugins") - val context = initializePlugins(configuration, logger, sourceSetsCache) + val context = initializePlugins(configuration, logger) report("Creating all modules page") val pages = createAllModulePage(context) @@ -66,15 +62,12 @@ class DokkaGenerator( fun initializePlugins( configuration: DokkaConfiguration, logger: DokkaLogger, - sourceSetsCache: SourceSetCache, pluginOverrides: List = emptyList() - ) = DokkaContext.create(configuration, logger, sourceSetsCache, pluginOverrides) + ) = DokkaContext.create(configuration, logger, pluginOverrides) fun createDocumentationModels( - context: DokkaContext, - sourceSetsCache: SourceSetCache - ) = context.configuration.passesConfigurations - .map { passConfiguration -> sourceSetsCache.getSourceSet(passConfiguration) } + context: DokkaContext + ) = context.configuration.sourceSets .flatMap { passConfiguration -> translateSources(passConfiguration, context) } fun transformDocumentationModelBeforeMerge( @@ -133,9 +126,9 @@ class DokkaGenerator( } } - private fun translateSources(platformData: SourceSetData, context: DokkaContext) = + private fun translateSources(sourceSet: DokkaSourceSet, context: DokkaContext) = context[CoreExtensions.sourceToDocumentableTranslator].map { - it.invoke(platformData, context) + it.invoke(sourceSet, context) } } diff --git a/core/src/main/kotlin/configuration.kt b/core/src/main/kotlin/configuration.kt index b016f83d..463d2342 100644 --- a/core/src/main/kotlin/configuration.kt +++ b/core/src/main/kotlin/configuration.kt @@ -49,12 +49,12 @@ interface DokkaConfiguration { val cacheRoot: String? val offlineMode: Boolean val failOnWarning: Boolean - val passesConfigurations: List + val sourceSets: List val modules: List val pluginsClasspath: List val pluginsConfiguration: Map - interface PassConfiguration { + interface DokkaSourceSet { val moduleName: String val displayName: String val sourceSetID: String diff --git a/core/src/main/kotlin/defaultConfiguration.kt b/core/src/main/kotlin/defaultConfiguration.kt index 4e83d3c3..d3ac9df2 100644 --- a/core/src/main/kotlin/defaultConfiguration.kt +++ b/core/src/main/kotlin/defaultConfiguration.kt @@ -8,14 +8,14 @@ data class DokkaConfigurationImpl( override val format: String, override val cacheRoot: String?, override val offlineMode: Boolean, - override val passesConfigurations: List, + override val sourceSets: List, override val pluginsClasspath: List, override val pluginsConfiguration: Map, override val modules: List, override val failOnWarning: Boolean ) : DokkaConfiguration -data class PassConfigurationImpl( +data class DokkaSourceSetImpl( override val moduleName: String, override val displayName: String, override val sourceSetID: String, @@ -39,7 +39,7 @@ data class PassConfigurationImpl( override val noJdkLink: Boolean, override val suppressedFiles: List, override val analysisPlatform: Platform -) : DokkaConfiguration.PassConfiguration +) : DokkaConfiguration.DokkaSourceSet data class DokkaModuleDescriptionImpl( override val name: String, diff --git a/core/src/main/kotlin/model/Documentable.kt b/core/src/main/kotlin/model/Documentable.kt index 768bddc5..35278302 100644 --- a/core/src/main/kotlin/model/Documentable.kt +++ b/core/src/main/kotlin/model/Documentable.kt @@ -1,5 +1,6 @@ package org.jetbrains.dokka.model +import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.doc.DocumentationNode import org.jetbrains.dokka.model.properties.PropertyContainer @@ -11,8 +12,8 @@ abstract class Documentable { abstract val dri: DRI abstract val children: List abstract val documentation: SourceSetDependent - abstract val sourceSets: Set - abstract val expectPresentInSet: SourceSetData? + abstract val sourceSets: Set + abstract val expectPresentInSet: DokkaSourceSet? override fun toString(): String = "${javaClass.simpleName}($dri)" @@ -23,7 +24,7 @@ abstract class Documentable { override fun hashCode() = dri.hashCode() } -typealias SourceSetDependent = Map +typealias SourceSetDependent = Map interface WithExpectActual { val sources: SourceSetDependent @@ -88,8 +89,8 @@ data class DModule( override val name: String, val packages: List, override val documentation: SourceSetDependent, - override val expectPresentInSet: SourceSetData? = null, - override val sourceSets: Set, + override val expectPresentInSet: DokkaSourceSet? = null, + override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), WithExtraProperties { override val dri: DRI = DRI.topLevel @@ -106,8 +107,8 @@ data class DPackage( override val classlikes: List, val typealiases: List, override val documentation: SourceSetDependent, - override val expectPresentInSet: SourceSetData? = null, - override val sourceSets: Set, + override val expectPresentInSet: DokkaSourceSet? = null, + override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), WithScope, WithExtraProperties { override val name = dri.packageName.orEmpty() @@ -130,9 +131,9 @@ data class DClass( override val generics: List, override val supertypes: SourceSetDependent>, override val documentation: SourceSetDependent, - override val expectPresentInSet: SourceSetData?, + override val expectPresentInSet: DokkaSourceSet?, override val modifier: SourceSetDependent, - override val sourceSets: Set, + override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : DClasslike(), WithAbstraction, WithCompanion, WithConstructors, WithGenerics, WithSupertypes, WithExtraProperties { @@ -148,7 +149,7 @@ data class DEnum( override val name: String, val entries: List, override val documentation: SourceSetDependent, - override val expectPresentInSet: SourceSetData?, + override val expectPresentInSet: DokkaSourceSet?, override val sources: SourceSetDependent, override val functions: List, override val properties: List, @@ -157,7 +158,7 @@ data class DEnum( override val companion: DObject?, override val constructors: List, override val supertypes: SourceSetDependent>, - override val sourceSets: Set, + override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : DClasslike(), WithCompanion, WithConstructors, WithSupertypes, WithExtraProperties { override val children: List @@ -170,11 +171,11 @@ data class DEnumEntry( override val dri: DRI, override val name: String, override val documentation: SourceSetDependent, - override val expectPresentInSet: SourceSetData?, + override val expectPresentInSet: DokkaSourceSet?, override val functions: List, override val properties: List, override val classlikes: List, - override val sourceSets: Set, + override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), WithScope, WithExtraProperties { override val children: List @@ -189,14 +190,14 @@ data class DFunction( val isConstructor: Boolean, val parameters: List, override val documentation: SourceSetDependent, - override val expectPresentInSet: SourceSetData?, + override val expectPresentInSet: DokkaSourceSet?, override val sources: SourceSetDependent, override val visibility: SourceSetDependent, override val type: Bound, override val generics: List, override val receiver: DParameter?, override val modifier: SourceSetDependent, - override val sourceSets: Set, + override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), Callable, WithGenerics, WithExtraProperties { override val children: List @@ -209,7 +210,7 @@ data class DInterface( override val dri: DRI, override val name: String, override val documentation: SourceSetDependent, - override val expectPresentInSet: SourceSetData?, + override val expectPresentInSet: DokkaSourceSet?, override val sources: SourceSetDependent, override val functions: List, override val properties: List, @@ -218,7 +219,7 @@ data class DInterface( override val companion: DObject?, override val generics: List, override val supertypes: SourceSetDependent>, - override val sourceSets: Set, + override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : DClasslike(), WithCompanion, WithGenerics, WithSupertypes, WithExtraProperties { override val children: List @@ -231,14 +232,14 @@ data class DObject( override val name: String?, override val dri: DRI, override val documentation: SourceSetDependent, - override val expectPresentInSet: SourceSetData?, + override val expectPresentInSet: DokkaSourceSet?, override val sources: SourceSetDependent, override val functions: List, override val properties: List, override val classlikes: List, override val visibility: SourceSetDependent, override val supertypes: SourceSetDependent>, - override val sourceSets: Set, + override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : DClasslike(), WithSupertypes, WithExtraProperties { override val children: List @@ -251,7 +252,7 @@ data class DAnnotation( override val name: String, override val dri: DRI, override val documentation: SourceSetDependent, - override val expectPresentInSet: SourceSetData?, + override val expectPresentInSet: DokkaSourceSet?, override val sources: SourceSetDependent, override val functions: List, override val properties: List, @@ -260,7 +261,7 @@ data class DAnnotation( override val companion: DObject?, override val constructors: List, override val generics: List, - override val sourceSets: Set, + override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : DClasslike(), WithCompanion, WithConstructors, WithExtraProperties, WithGenerics { override val children: List @@ -273,7 +274,7 @@ data class DProperty( override val dri: DRI, override val name: String, override val documentation: SourceSetDependent, - override val expectPresentInSet: SourceSetData?, + override val expectPresentInSet: DokkaSourceSet?, override val sources: SourceSetDependent, override val visibility: SourceSetDependent, override val type: Bound, @@ -281,7 +282,7 @@ data class DProperty( val setter: DFunction?, val getter: DFunction?, override val modifier: SourceSetDependent, - override val sourceSets: Set, + override val sourceSets: Set, override val generics: List, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), Callable, WithExtraProperties, WithGenerics { @@ -296,9 +297,9 @@ data class DParameter( override val dri: DRI, override val name: String?, override val documentation: SourceSetDependent, - override val expectPresentInSet: SourceSetData?, + override val expectPresentInSet: DokkaSourceSet?, val type: Bound, - override val sourceSets: Set, + override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), WithExtraProperties { override val children: List @@ -311,9 +312,9 @@ data class DTypeParameter( override val dri: DRI, override val name: String, override val documentation: SourceSetDependent, - override val expectPresentInSet: SourceSetData?, + override val expectPresentInSet: DokkaSourceSet?, val bounds: List, - override val sourceSets: Set, + override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), WithExtraProperties { override val children: List @@ -329,8 +330,8 @@ data class DTypeAlias( val underlyingType: SourceSetDependent, override val visibility: SourceSetDependent, override val documentation: SourceSetDependent, - override val expectPresentInSet: SourceSetData?, - override val sourceSets: Set, + override val expectPresentInSet: DokkaSourceSet?, + override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), WithType, WithVisibility, WithExtraProperties { override val children: List diff --git a/core/src/main/kotlin/model/SourceSetData.kt b/core/src/main/kotlin/model/SourceSetData.kt deleted file mode 100644 index 3e38cc7b..00000000 --- a/core/src/main/kotlin/model/SourceSetData.kt +++ /dev/null @@ -1,38 +0,0 @@ -package org.jetbrains.dokka.model - -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.Platform -import org.jetbrains.dokka.plugability.DokkaContext - -data class SourceSetData( - val moduleName: String, - val sourceSetID: String, - val displayName: String, - val platform: Platform, - val sourceRoots: List = emptyList(), - val dependentSourceSets: List = emptyList() -) - -class SourceSetCache { - private val sourceSets = HashMap() - - val allSourceSets: List - get() = sourceSets.values.toList() - - fun getSourceSet(pass: DokkaConfiguration.PassConfiguration) = - sourceSets.getOrPut(pass.sourceSetID, - { - SourceSetData( - pass.moduleName, - pass.sourceSetID, - pass.displayName, - pass.analysisPlatform, - pass.sourceRoots, - pass.dependentSourceSets - ) - } - ) -} - -fun DokkaContext.sourceSet(pass: DokkaConfiguration.PassConfiguration): SourceSetData = - sourceSetCache.getSourceSet(pass) \ No newline at end of file diff --git a/core/src/main/kotlin/model/documentableProperties.kt b/core/src/main/kotlin/model/documentableProperties.kt index 2aec199c..cd6a9335 100644 --- a/core/src/main/kotlin/model/documentableProperties.kt +++ b/core/src/main/kotlin/model/documentableProperties.kt @@ -1,26 +1,26 @@ package org.jetbrains.dokka.model +import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.properties.ExtraProperty import org.jetbrains.dokka.model.properties.MergeStrategy -data class InheritedFunction(val inheritedFrom: SourceSetDependent): ExtraProperty { +data class InheritedFunction(val inheritedFrom: SourceSetDependent) : ExtraProperty { companion object : ExtraProperty.Key { override fun mergeStrategyFor(left: InheritedFunction, right: InheritedFunction) = MergeStrategy.Replace( InheritedFunction(left.inheritedFrom + right.inheritedFrom) ) } - fun isInherited(sourceSetDependent: SourceSetData): Boolean = inheritedFrom[sourceSetDependent] != null + fun isInherited(sourceSetDependent: DokkaSourceSet): Boolean = inheritedFrom[sourceSetDependent] != null override val key: ExtraProperty.Key = InheritedFunction } -data class ImplementedInterfaces(val interfaces: SourceSetDependent>): ExtraProperty { +data class ImplementedInterfaces(val interfaces: SourceSetDependent>) : ExtraProperty { companion object : ExtraProperty.Key { - override fun mergeStrategyFor(left: ImplementedInterfaces, right: ImplementedInterfaces) = MergeStrategy.Replace( - ImplementedInterfaces(left.interfaces + right.interfaces) - ) + override fun mergeStrategyFor(left: ImplementedInterfaces, right: ImplementedInterfaces) = + MergeStrategy.Replace(ImplementedInterfaces(left.interfaces + right.interfaces)) } override val key: ExtraProperty.Key = ImplementedInterfaces diff --git a/core/src/main/kotlin/model/documentableUtils.kt b/core/src/main/kotlin/model/documentableUtils.kt index 2d4ade15..7057a62c 100644 --- a/core/src/main/kotlin/model/documentableUtils.kt +++ b/core/src/main/kotlin/model/documentableUtils.kt @@ -1,12 +1,14 @@ package org.jetbrains.dokka.model -fun SourceSetDependent.filtered(platformDataList: Set) = filter { it.key in platformDataList } -fun SourceSetData?.filtered(platformDataList: Set) = takeIf { this in platformDataList } +import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet -fun DTypeParameter.filter(filteredData: Set) = - if (filteredData.containsAll(sourceSets)) this +fun SourceSetDependent.filtered(sourceSets: Set) = filter { it.key in sourceSets } +fun DokkaSourceSet?.filtered(sourceSets: Set) = takeIf { this in sourceSets } + +fun DTypeParameter.filter(filteredSet: Set) = + if (filteredSet.containsAll(sourceSets)) this else { - val intersection = filteredData.intersect(sourceSets) + val intersection = filteredSet.intersect(sourceSets) if (intersection.isEmpty()) null else DTypeParameter( dri, diff --git a/core/src/main/kotlin/pages/ContentNodes.kt b/core/src/main/kotlin/pages/ContentNodes.kt index 1b9c937d..dc23a082 100644 --- a/core/src/main/kotlin/pages/ContentNodes.kt +++ b/core/src/main/kotlin/pages/ContentNodes.kt @@ -1,7 +1,7 @@ package org.jetbrains.dokka.pages +import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.model.SourceSetData import org.jetbrains.dokka.model.properties.PropertyContainer import org.jetbrains.dokka.model.properties.WithExtraProperties @@ -11,7 +11,7 @@ data class DCI(val dri: Set, val kind: Kind) { interface ContentNode : WithExtraProperties { val dci: DCI - val sourceSets: Set + val sourceSets: Set val style: Set