From d37cf2f32840779706154a3cddbb2239cd80fd84 Mon Sep 17 00:00:00 2001 From: Błażej Kardyś Date: Wed, 27 Nov 2019 17:45:33 +0100 Subject: Cleaning package naming --- .../main/kotlin/Analysis/AnalysisEnvironment.kt | 455 ----------------- .../main/kotlin/Analysis/CoreKotlinCacheService.kt | 30 -- .../main/kotlin/Analysis/CoreProjectFileIndex.kt | 568 --------------------- .../main/kotlin/Analysis/DokkaAnalyzerFacades.kt | 164 ------ .../main/kotlin/Analysis/JavaResolveExtension.kt | 131 ----- core/src/main/kotlin/DokkaBootstrapImpl.kt | 1 + core/src/main/kotlin/DokkaGenerator.kt | 5 +- core/src/main/kotlin/Markdown/MarkdownProcessor.kt | 53 -- core/src/main/kotlin/Model/DocumentationNode.kt | 162 ------ core/src/main/kotlin/Utilities/DokkaLogging.kt | 31 -- core/src/main/kotlin/Utilities/Html.kt | 12 - core/src/main/kotlin/Utilities/Path.kt | 5 - core/src/main/kotlin/Utilities/ServiceLocator.kt | 97 ---- core/src/main/kotlin/Utilities/Uri.kt | 40 -- core/src/main/kotlin/Utilities/nodeDebug.kt | 51 -- .../main/kotlin/analysis/AnalysisEnvironment.kt | 454 ++++++++++++++++ .../main/kotlin/analysis/CoreKotlinCacheService.kt | 30 ++ .../main/kotlin/analysis/CoreProjectFileIndex.kt | 568 +++++++++++++++++++++ .../main/kotlin/analysis/DokkaAnalyzerFacades.kt | 164 ++++++ .../main/kotlin/analysis/JavaResolveExtension.kt | 131 +++++ core/src/main/kotlin/markdown/MarkdownProcessor.kt | 53 ++ core/src/main/kotlin/model/DocumentationNode.kt | 162 ++++++ .../pages/DefaultMarkdownToContentConverter.kt | 2 +- .../kotlin/pages/MarkdownToContentConverter.kt | 3 +- core/src/main/kotlin/pages/PageBuilder.kt | 4 +- core/src/main/kotlin/pages/PageContentBuilder.kt | 12 +- core/src/main/kotlin/pages/PageNodes.kt | 2 +- core/src/main/kotlin/plugability/DokkaContext.kt | 2 +- core/src/main/kotlin/renderers/HtmlRenderer.kt | 4 +- .../kotlin/resolvers/DefaultLocationProvider.kt | 2 +- .../DefaultDescriptorToDocumentationTranslator.kt | 8 +- .../DescriptorToDocumentationTranslator.kt | 3 +- .../DefaultDocumentationNodeMerger.kt | 4 +- .../DefaultDocumentationToPageTranslator.kt | 2 +- .../documentation/DocumentationNodeMerger.kt | 2 +- .../documentation/DocumentationNodeTransformer.kt | 2 +- .../documentation/DocumentationToPageTranslator.kt | 5 +- core/src/main/kotlin/utilities/DokkaLogging.kt | 31 ++ core/src/main/kotlin/utilities/Html.kt | 12 + core/src/main/kotlin/utilities/Path.kt | 5 + core/src/main/kotlin/utilities/ServiceLocator.kt | 97 ++++ core/src/main/kotlin/utilities/Uri.kt | 40 ++ core/src/main/kotlin/utilities/nodeDebug.kt | 50 ++ 43 files changed, 1827 insertions(+), 1832 deletions(-) delete mode 100644 core/src/main/kotlin/Analysis/AnalysisEnvironment.kt delete mode 100644 core/src/main/kotlin/Analysis/CoreKotlinCacheService.kt delete mode 100644 core/src/main/kotlin/Analysis/CoreProjectFileIndex.kt delete mode 100644 core/src/main/kotlin/Analysis/DokkaAnalyzerFacades.kt delete mode 100644 core/src/main/kotlin/Analysis/JavaResolveExtension.kt delete mode 100644 core/src/main/kotlin/Markdown/MarkdownProcessor.kt delete mode 100644 core/src/main/kotlin/Model/DocumentationNode.kt delete mode 100644 core/src/main/kotlin/Utilities/DokkaLogging.kt delete mode 100644 core/src/main/kotlin/Utilities/Html.kt delete mode 100644 core/src/main/kotlin/Utilities/Path.kt delete mode 100644 core/src/main/kotlin/Utilities/ServiceLocator.kt delete mode 100644 core/src/main/kotlin/Utilities/Uri.kt delete mode 100644 core/src/main/kotlin/Utilities/nodeDebug.kt create mode 100644 core/src/main/kotlin/analysis/AnalysisEnvironment.kt create mode 100644 core/src/main/kotlin/analysis/CoreKotlinCacheService.kt create mode 100644 core/src/main/kotlin/analysis/CoreProjectFileIndex.kt create mode 100644 core/src/main/kotlin/analysis/DokkaAnalyzerFacades.kt create mode 100644 core/src/main/kotlin/analysis/JavaResolveExtension.kt create mode 100644 core/src/main/kotlin/markdown/MarkdownProcessor.kt create mode 100644 core/src/main/kotlin/model/DocumentationNode.kt create mode 100644 core/src/main/kotlin/utilities/DokkaLogging.kt create mode 100644 core/src/main/kotlin/utilities/Html.kt create mode 100644 core/src/main/kotlin/utilities/Path.kt create mode 100644 core/src/main/kotlin/utilities/ServiceLocator.kt create mode 100644 core/src/main/kotlin/utilities/Uri.kt create mode 100644 core/src/main/kotlin/utilities/nodeDebug.kt (limited to 'core/src') diff --git a/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt b/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt deleted file mode 100644 index c816106e..00000000 --- a/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt +++ /dev/null @@ -1,455 +0,0 @@ -package org.jetbrains.dokka - -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 com.intellij.util.io.URLUtil -import org.jetbrains.dokka.Analysis.DokkaJsAnalyzerFacade -import org.jetbrains.dokka.Analysis.DokkaNativeAnalyzerFacade -import org.jetbrains.kotlin.analyzer.* -import org.jetbrains.kotlin.analyzer.common.CommonAnalysisParameters -import org.jetbrains.kotlin.analyzer.common.CommonAnalyzerFacade -import org.jetbrains.kotlin.builtins.DefaultBuiltIns -import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.builtins.jvm.JvmBuiltIns -import org.jetbrains.kotlin.caches.project.LibraryModuleInfo -import org.jetbrains.kotlin.caches.resolve.KotlinCacheService -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.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.idea.resolve.ResolutionFacade -import org.jetbrains.kotlin.js.config.JSConfigurationKeys -import org.jetbrains.kotlin.js.resolve.JsPlatform -import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.resolve.* -import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics -import org.jetbrains.kotlin.resolve.jvm.JvmAnalyzerFacade -import org.jetbrains.kotlin.resolve.jvm.JvmPlatformParameters -import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform -import org.jetbrains.kotlin.resolve.konan.platform.KonanPlatform -import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode -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 java.io.File - -/** - * 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.fallback", "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) - - Extensions.registerAreaClass("IDEA_MODULE", null) - CoreApplicationEnvironment.registerExtensionPoint(Extensions.getRootArea(), - OrderEnumerationHandler.EP_NAME, OrderEnumerationHandler.Factory::class.java) - - projectComponentManager.registerService(ProjectFileIndex::class.java, - projectFileIndex) - projectComponentManager.registerService(ProjectRootManager::class.java, - CoreProjectRootManager(projectFileIndex)) - return environment - } - - 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) - val sourceFiles = environment.getSourceFiles() - - - val targetPlatform = when (analysisPlatform) { - Platform.js -> JsPlatform - Platform.common -> TargetPlatform.Common - Platform.native -> KonanPlatform - Platform.jvm -> JvmPlatform - } - - val library = object : LibraryModuleInfo { - override val platform: TargetPlatform - get() = targetPlatform - - override fun getLibraryRoots(): Collection { - return classpath.map { it.absolutePath } - } - - override val name: Name = Name.special("") - override fun dependencies(): List = listOf(this) - } - val module = object : ModuleInfo { - override val name: Name = Name.special("") - override fun dependencies(): List = listOf(this, library) - } - - 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)) - else -> throw IllegalArgumentException("Unexpected module info") - } - } - - var builtIns: JvmBuiltIns? = null - - val resolverForProject = when (analysisPlatform) { - Platform.jvm -> { - builtIns = JvmBuiltIns(projectContext.storageManager) - 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 resolverForLibrary = resolverForProject.resolverForModule(library) // Required before module to initialize library properly - val resolverForModule = resolverForProject.resolverForModule(module) - val libraryModuleDescriptor = resolverForProject.descriptorForModule(library) - val moduleDescriptor = resolverForProject.descriptorForModule(module) - builtIns?.initialize(moduleDescriptor, true) - 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 createCommonResolverForProject( - projectContext: ProjectContext, - module: ModuleInfo, - library: LibraryModuleInfo, - modulesContent: (ModuleInfo) -> ModuleContent, - environment: KotlinCoreEnvironment - ): ResolverForProjectImpl { - return ResolverForProjectImpl( - debugName = "Dokka", - projectContext = projectContext, - modules = listOf(module, library), - modulesContent = modulesContent, - modulePlatforms = { MultiTargetPlatform.Common }, - moduleLanguageSettingsProvider = LanguageSettingsProvider.Default /* TODO: Fix this */, - resolverForModuleFactoryByPlatform = { CommonAnalyzerFacade }, - platformParameters = { _ -> - CommonAnalysisParameters { content -> - environment.createPackagePartProvider(content.moduleContentScope) - } - }, - targetEnvironment = CompilerEnvironment, - builtIns = DefaultBuiltIns.Instance - ) - } - - private fun createJsResolverForProject( - projectContext: ProjectContext, - module: ModuleInfo, - library: LibraryModuleInfo, - modulesContent: (ModuleInfo) -> ModuleContent - ): ResolverForProjectImpl { - return ResolverForProjectImpl( - debugName = "Dokka", - projectContext = projectContext, - modules = listOf(module, library), - modulesContent = modulesContent, - modulePlatforms = { JsPlatform.multiTargetPlatform }, - moduleLanguageSettingsProvider = LanguageSettingsProvider.Default /* TODO: Fix this */, - resolverForModuleFactoryByPlatform = { DokkaJsAnalyzerFacade }, - platformParameters = { _ -> PlatformAnalysisParameters.Empty }, - targetEnvironment = CompilerEnvironment, - builtIns = JsPlatform.builtIns - ) - } - - private fun createNativeResolverForProject( - projectContext: ProjectContext, - module: ModuleInfo, - library: LibraryModuleInfo, - modulesContent: (ModuleInfo) -> ModuleContent - ): ResolverForProjectImpl { - return ResolverForProjectImpl( - debugName = "Dokka", - projectContext = projectContext, - modules = listOf(module, library), - modulesContent = modulesContent, - modulePlatforms = { KonanPlatform.multiTargetPlatform }, - moduleLanguageSettingsProvider = LanguageSettingsProvider.Default /* TODO: Fix this */, - resolverForModuleFactoryByPlatform = { DokkaNativeAnalyzerFacade }, - platformParameters = { _ -> PlatformAnalysisParameters.Empty }, - targetEnvironment = CompilerEnvironment - ) - - } - - private fun createJvmResolverForProject( - projectContext: ProjectContext, - module: ModuleInfo, - library: LibraryModuleInfo, - modulesContent: (ModuleInfo) -> ModuleContent, - sourcesScope: GlobalSearchScope, - builtIns: KotlinBuiltIns - ): ResolverForProjectImpl { - val javaRoots = classpath - .mapNotNull { - val rootFile = when { - it.extension == "jar" -> - StandardFileSystems.jar().findFileByPath("${it.absolutePath}${URLUtil.JAR_SEPARATOR}") - else -> - StandardFileSystems.local().findFileByPath(it.absolutePath) - } - - rootFile?.let { JavaRoot(it, JavaRoot.RootType.BINARY) } - } - - return ResolverForProjectImpl( - debugName = "Dokka", - projectContext = projectContext, - modules = listOf(library, module), - modulesContent = { - when (it) { - library -> ModuleContent(it, emptyList(), GlobalSearchScope.notScope(sourcesScope)) - module -> ModuleContent(it, emptyList(), sourcesScope) - else -> throw IllegalArgumentException("Unexpected module info") - } - }, - modulePlatforms = { JvmPlatform.multiTargetPlatform }, - moduleLanguageSettingsProvider = LanguageSettingsProvider.Default /* TODO: Fix this */, - resolverForModuleFactoryByPlatform = { JvmAnalyzerFacade }, - platformParameters = { - JvmPlatformParameters ({ content -> - JvmPackagePartProvider( - configuration.languageVersionSettings, - content.moduleContentScope) - .apply { - addRoots(javaRoots, messageCollector) - } - }, { - val file = (it as JavaClassImpl).psi.containingFile.virtualFile - if (file in sourcesScope) - module - else - library - }) - }, - targetEnvironment = CompilerEnvironment, - builtIns = builtIns - ) - } - - 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) - } -} - -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/core/src/main/kotlin/Analysis/CoreKotlinCacheService.kt b/core/src/main/kotlin/Analysis/CoreKotlinCacheService.kt deleted file mode 100644 index 31b8ffc7..00000000 --- a/core/src/main/kotlin/Analysis/CoreKotlinCacheService.kt +++ /dev/null @@ -1,30 +0,0 @@ -package org.jetbrains.dokka - -import com.intellij.psi.PsiFile -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.TargetPlatform -import org.jetbrains.kotlin.resolve.diagnostics.KotlinSuppressCache - - -class CoreKotlinCacheService(private val resolutionFacade: DokkaResolutionFacade) : KotlinCacheService { - override fun getResolutionFacade(elements: List): ResolutionFacade { - return resolutionFacade - } - - override fun getResolutionFacadeByFile(file: PsiFile, platform: TargetPlatform): ResolutionFacade { - return resolutionFacade - } - - override fun getResolutionFacadeByModuleInfo(moduleInfo: ModuleInfo, platform: TargetPlatform): ResolutionFacade? { - return resolutionFacade - } - - override fun getSuppressionCache(): KotlinSuppressCache { - throw UnsupportedOperationException() - } - -} - diff --git a/core/src/main/kotlin/Analysis/CoreProjectFileIndex.kt b/core/src/main/kotlin/Analysis/CoreProjectFileIndex.kt deleted file mode 100644 index f5fbf991..00000000 --- a/core/src/main/kotlin/Analysis/CoreProjectFileIndex.kt +++ /dev/null @@ -1,568 +0,0 @@ -package org.jetbrains.dokka - -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.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 getOptionValue(p0: String): String? { - throw UnsupportedOperationException() - } - - override fun clearOption(p0: String) { - throw UnsupportedOperationException() - } - - override fun getName(): String = "" - - override fun getModuleWithLibrariesScope(): GlobalSearchScope { - throw UnsupportedOperationException() - } - - override fun getModuleWithDependentsScope(): GlobalSearchScope { - throw UnsupportedOperationException() - } - - override fun getModuleContentScope(): GlobalSearchScope { - throw UnsupportedOperationException() - } - - override fun isLoaded(): Boolean { - throw UnsupportedOperationException() - } - - override fun setOption(p0: String, p1: String?) { - throw UnsupportedOperationException() - } - - override fun getModuleWithDependenciesScope(): GlobalSearchScope { - throw UnsupportedOperationException() - } - - override fun getModuleWithDependenciesAndLibrariesScope(p0: Boolean): GlobalSearchScope { - throw UnsupportedOperationException() - } - - override fun getProject(): Project = this@CoreProjectFileIndex.project - - override fun getModuleContentWithDependenciesScope(): GlobalSearchScope { - throw UnsupportedOperationException() - } - - override fun getModuleFilePath(): String { - throw UnsupportedOperationException() - } - - override fun getModuleTestsWithDependentsScope(): GlobalSearchScope { - throw UnsupportedOperationException() - } - - override fun getModuleScope(): GlobalSearchScope { - throw UnsupportedOperationException() - } - - override fun getModuleScope(p0: Boolean): GlobalSearchScope { - throw UnsupportedOperationException() - } - - override fun getModuleRuntimeScope(p0: Boolean): GlobalSearchScope { - throw UnsupportedOperationException() - } - - override fun getModuleFile(): VirtualFile? { - throw UnsupportedOperationException() - } - - override fun getExtensions(p0: ExtensionPointName): Array { - throw UnsupportedOperationException() - } - - override fun getComponent(p0: String): BaseComponent? { - throw UnsupportedOperationException() - } - - override fun getComponent(p0: Class, p1: T): T { - 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 getComponents(p0: Class): Array { - throw UnsupportedOperationException() - } - - override fun getPicoContainer(): PicoContainer { - throw UnsupportedOperationException() - } - - override fun hasComponent(p0: Class<*>): Boolean { - 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) - StandardFileSystems.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/core/src/main/kotlin/Analysis/DokkaAnalyzerFacades.kt b/core/src/main/kotlin/Analysis/DokkaAnalyzerFacades.kt deleted file mode 100644 index 874341dd..00000000 --- a/core/src/main/kotlin/Analysis/DokkaAnalyzerFacades.kt +++ /dev/null @@ -1,164 +0,0 @@ -package org.jetbrains.dokka.Analysis - -import org.jetbrains.kotlin.analyzer.* -import org.jetbrains.kotlin.caches.project.LibraryModuleInfo -import org.jetbrains.kotlin.config.LanguageVersionSettings -import org.jetbrains.kotlin.config.TargetPlatformVersion -import org.jetbrains.kotlin.container.StorageComponentContainer -import org.jetbrains.kotlin.container.get -import org.jetbrains.kotlin.container.useImpl -import org.jetbrains.kotlin.container.useInstance -import org.jetbrains.kotlin.context.ModuleContext -import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider -import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl -import org.jetbrains.kotlin.frontend.di.configureModule -import org.jetbrains.kotlin.ide.konan.KOTLIN_NATIVE_CURRENT_ABI_VERSION -import org.jetbrains.kotlin.ide.konan.createPackageFragmentProvider -import org.jetbrains.kotlin.incremental.components.LookupTracker -import org.jetbrains.kotlin.js.resolve.JsPlatform -import org.jetbrains.kotlin.konan.file.File -import org.jetbrains.kotlin.konan.library.createKonanLibrary -import org.jetbrains.kotlin.resolve.* -import org.jetbrains.kotlin.resolve.konan.platform.KonanPlatform -import org.jetbrains.kotlin.resolve.lazy.ResolveSession -import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory -import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService -import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil -import org.jetbrains.kotlin.serialization.js.createKotlinJavascriptPackageFragmentProvider -import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils - -fun createContainerForLazyResolve( - moduleContext: ModuleContext, - declarationProviderFactory: DeclarationProviderFactory, - bindingTrace: BindingTrace, - platform: TargetPlatform, - targetPlatformVersion: TargetPlatformVersion, - targetEnvironment: TargetEnvironment, - languageVersionSettings: LanguageVersionSettings -): StorageComponentContainer = createContainer("LazyResolve", platform) { - configureModule(moduleContext, platform, targetPlatformVersion, bindingTrace) - - useInstance(declarationProviderFactory) - useInstance(languageVersionSettings) - - useImpl() - useImpl() - targetEnvironment.configure(this) - - useImpl() - useImpl() -} - - -object DokkaJsAnalyzerFacade : ResolverForModuleFactory() { - override fun createResolverForModule( - moduleDescriptor: ModuleDescriptorImpl, - moduleContext: ModuleContext, - moduleContent: ModuleContent, - platformParameters: PlatformAnalysisParameters, - targetEnvironment: TargetEnvironment, - resolverForProject: ResolverForProject, - languageVersionSettings: LanguageVersionSettings, - targetPlatformVersion: TargetPlatformVersion - ): ResolverForModule { - val (moduleInfo, syntheticFiles, moduleContentScope) = moduleContent - val project = moduleContext.project - val declarationProviderFactory = DeclarationProviderFactoryService.createDeclarationProviderFactory( - project, - moduleContext.storageManager, - syntheticFiles, - moduleContentScope, - moduleInfo - ) - - val container = createContainerForLazyResolve( - moduleContext, - declarationProviderFactory, - BindingTraceContext(), - JsPlatform, - TargetPlatformVersion.NoVersion, - targetEnvironment, - languageVersionSettings - ) - var packageFragmentProvider = container.get().packageFragmentProvider - - if (moduleInfo is LibraryModuleInfo && moduleInfo.platform == JsPlatform) { - val providers = moduleInfo.getLibraryRoots() - .flatMap { KotlinJavascriptMetadataUtils.loadMetadata(it) } - .filter { it.version.isCompatible() } - .map { metadata -> - val (header, packageFragmentProtos) = - KotlinJavascriptSerializationUtil.readModuleAsProto(metadata.body, metadata.version) - createKotlinJavascriptPackageFragmentProvider( - moduleContext.storageManager, moduleDescriptor, header, packageFragmentProtos, metadata.version, - container.get(), LookupTracker.DO_NOTHING - ) - } - - if (providers.isNotEmpty()) { - packageFragmentProvider = CompositePackageFragmentProvider(listOf(packageFragmentProvider) + providers) - } - } - - return ResolverForModule(packageFragmentProvider, container) - } - - override val targetPlatform: TargetPlatform - get() = JsPlatform -} - -object DokkaNativeAnalyzerFacade : ResolverForModuleFactory() { - override val targetPlatform: TargetPlatform - get() = KonanPlatform - - override fun createResolverForModule( - moduleDescriptor: ModuleDescriptorImpl, - moduleContext: ModuleContext, - moduleContent: ModuleContent, - platformParameters: PlatformAnalysisParameters, - targetEnvironment: TargetEnvironment, - resolverForProject: ResolverForProject, - languageVersionSettings: LanguageVersionSettings, - targetPlatformVersion: TargetPlatformVersion - ): ResolverForModule { - - val declarationProviderFactory = DeclarationProviderFactoryService.createDeclarationProviderFactory( - moduleContext.project, - moduleContext.storageManager, - moduleContent.syntheticFiles, - moduleContent.moduleContentScope, - moduleContent.moduleInfo - ) - - val container = createContainerForLazyResolve( - moduleContext, - declarationProviderFactory, - BindingTraceContext(), - targetPlatform, - TargetPlatformVersion.NoVersion, - targetEnvironment, - languageVersionSettings - ) - - val packageFragmentProvider = container.get().packageFragmentProvider - val fragmentProviders = mutableListOf(packageFragmentProvider) - - val moduleInfo = moduleContent.moduleInfo - - if (moduleInfo is LibraryModuleInfo) { - moduleInfo.getLibraryRoots() - .filter { File(it).extension != "jar" } - .map { createKonanLibrary(File(it), KOTLIN_NATIVE_CURRENT_ABI_VERSION) } - .mapTo(fragmentProviders) { - it.createPackageFragmentProvider( - moduleContext.storageManager, - languageVersionSettings, - moduleDescriptor - ) - } - - } - - return ResolverForModule(CompositePackageFragmentProvider(fragmentProviders), container) - } -} diff --git a/core/src/main/kotlin/Analysis/JavaResolveExtension.kt b/core/src/main/kotlin/Analysis/JavaResolveExtension.kt deleted file mode 100644 index 4dc6b366..00000000 --- a/core/src/main/kotlin/Analysis/JavaResolveExtension.kt +++ /dev/null @@ -1,131 +0,0 @@ -/* - * 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 - -import com.intellij.psi.* -import org.jetbrains.kotlin.asJava.classes.KtLightClass -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.psi.KtClassOrObject -import org.jetbrains.kotlin.psi.KtDeclaration -import org.jetbrains.kotlin.psi.psiUtil.parameterIndex -import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver -import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform -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, JvmPlatform)!! diff --git a/core/src/main/kotlin/DokkaBootstrapImpl.kt b/core/src/main/kotlin/DokkaBootstrapImpl.kt index 2e52d9c6..d11f1623 100644 --- a/core/src/main/kotlin/DokkaBootstrapImpl.kt +++ b/core/src/main/kotlin/DokkaBootstrapImpl.kt @@ -2,6 +2,7 @@ package org.jetbrains.dokka import com.google.gson.Gson import org.jetbrains.dokka.DokkaConfiguration.PackageOptions +import org.jetbrains.dokka.utilities.DokkaLogger import java.util.function.BiConsumer diff --git a/core/src/main/kotlin/DokkaGenerator.kt b/core/src/main/kotlin/DokkaGenerator.kt index 2efcca5a..8661ec45 100644 --- a/core/src/main/kotlin/DokkaGenerator.kt +++ b/core/src/main/kotlin/DokkaGenerator.kt @@ -1,10 +1,13 @@ package org.jetbrains.dokka -import org.jetbrains.dokka.Model.Module +import org.jetbrains.dokka.analysis.AnalysisEnvironment +import org.jetbrains.dokka.analysis.DokkaResolutionFacade +import org.jetbrains.dokka.model.Module import org.jetbrains.dokka.pages.PlatformData import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.single import org.jetbrains.dokka.renderers.FileWriter +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 diff --git a/core/src/main/kotlin/Markdown/MarkdownProcessor.kt b/core/src/main/kotlin/Markdown/MarkdownProcessor.kt deleted file mode 100644 index 2c8f7a73..00000000 --- a/core/src/main/kotlin/Markdown/MarkdownProcessor.kt +++ /dev/null @@ -1,53 +0,0 @@ -package org.jetbrains.dokka - -import org.intellij.markdown.IElementType -import org.intellij.markdown.MarkdownElementTypes -import org.intellij.markdown.ast.ASTNode -import org.intellij.markdown.ast.LeafASTNode -import org.intellij.markdown.ast.getTextInNode -import org.intellij.markdown.flavours.commonmark.CommonMarkFlavourDescriptor -import org.intellij.markdown.parser.MarkdownParser - -class MarkdownNode(val node: ASTNode, val parent: MarkdownNode?, val markdown: String) { - val children: List = node.children.map { MarkdownNode(it, this, markdown) } - val type: IElementType get() = node.type - val text: String get() = node.getTextInNode(markdown).toString() - fun child(type: IElementType): MarkdownNode? = children.firstOrNull { it.type == type } - - val previous get() = parent?.children?.getOrNull(parent.children.indexOf(this) - 1) - - override fun toString(): String = StringBuilder().apply { presentTo(this) }.toString() -} - -fun MarkdownNode.visit(action: (MarkdownNode, () -> Unit) -> Unit) { - action(this) { - for (child in children) { - child.visit(action) - } - } -} - -fun MarkdownNode.toTestString(): String { - val sb = StringBuilder() - var level = 0 - visit { node, visitChildren -> - sb.append(" ".repeat(level * 2)) - node.presentTo(sb) - sb.appendln() - level++ - visitChildren() - level-- - } - return sb.toString() -} - -private fun MarkdownNode.presentTo(sb: StringBuilder) { - sb.append(type.toString()) - sb.append(":" + text.replace("\n", "\u23CE")) -} - -fun parseMarkdown(markdown: String): MarkdownNode { - if (markdown.isEmpty()) - return MarkdownNode(LeafASTNode(MarkdownElementTypes.MARKDOWN_FILE, 0, 0), null, markdown) - return MarkdownNode(MarkdownParser(CommonMarkFlavourDescriptor()).buildMarkdownTreeFromString(markdown), null, markdown) -} diff --git a/core/src/main/kotlin/Model/DocumentationNode.kt b/core/src/main/kotlin/Model/DocumentationNode.kt deleted file mode 100644 index b1d4be55..00000000 --- a/core/src/main/kotlin/Model/DocumentationNode.kt +++ /dev/null @@ -1,162 +0,0 @@ -package org.jetbrains.dokka.Model - -import org.jetbrains.dokka.transformers.descriptors.KotlinTypeWrapper -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.pages.PlatformData -import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag - -class Module(val packages: List) : DocumentationNode() { - override val dri: DRI = DRI.topLevel - override val children: List = packages - override val extra: MutableSet = mutableSetOf() -} - -class Package( - override val dri: DRI, - override val functions: List, - override val properties: List, - override val classes: List, - override val extra: MutableSet = mutableSetOf() -) : ScopeNode() { - override val name = dri.packageName.orEmpty() -} - -class Class( - override val dri: DRI, - override val name: String, - val kind: ClassKind, - val constructors: List, - override val functions: List, - override val properties: List, - override val classes: List, - override val expected: ClassPlatformInfo?, - override val actual: List, - override val extra: MutableSet = mutableSetOf() -) : ScopeNode() { - val inherited by lazy { platformInfo.mapNotNull { (it as? ClassPlatformInfo)?.inherited }.flatten() } -} - -class Function( - override val dri: DRI, - override val name: String, - val returnType: TypeWrapper?, - val isConstructor: Boolean, - override val receiver: Parameter?, - val parameters: List, - override val expected: PlatformInfo?, - override val actual: List, - override val extra: MutableSet = mutableSetOf() -) : CallableNode() { - override val children: List - get() = listOfNotNull(receiver) + parameters -} - -class Property( - override val dri: DRI, - override val name: String, - override val receiver: Parameter?, - override val expected: PlatformInfo?, - override val actual: List, - override val extra: MutableSet = mutableSetOf() -) : CallableNode() { - override val children: List - get() = listOfNotNull(receiver) -} - -// TODO: treat named Parameters and receivers differently -class Parameter( - override val dri: DRI, - override val name: String?, - val type: TypeWrapper, - override val actual: List, - override val extra: MutableSet = mutableSetOf() -) : DocumentationNode() { - override val children: List - get() = emptyList() -} - -interface PlatformInfo { - val docTag: KDocTag? - val links: Map - val platformData: List -} - -class BasePlatformInfo( - override val docTag: KDocTag?, - override val links: Map, - override val platformData: List) : PlatformInfo { - - override fun equals(other: Any?): Boolean = - other is PlatformInfo && ( - docTag?.text == other.docTag?.text && - links == other.links) - - override fun hashCode(): Int = - listOf(docTag?.text, links).hashCode() -} - -class ClassPlatformInfo( - val info: PlatformInfo, - val inherited: List) : PlatformInfo by info - -abstract class DocumentationNode { - open val expected: PlatformInfo? = null - open val actual: List = emptyList() - open val name: String? = null - val platformInfo by lazy { listOfNotNull(expected) + actual } - val platformData by lazy { platformInfo.flatMap { it.platformData }.toSet() } - - abstract val dri: DRI - - abstract val children: List - - override fun toString(): String { - return "${javaClass.simpleName}($dri)" + briefDocstring.takeIf { it.isNotBlank() }?.let { " [$it]" }.orEmpty() - } - - override fun equals(other: Any?) = other is DocumentationNode && this.dri == other.dri - - override fun hashCode() = dri.hashCode() - - val commentsData: List>> - get() = platformInfo.mapNotNull { it.docTag?.let { tag -> Pair(tag.getContent(), it.links) } } - - val briefDocstring: String - get() = platformInfo.firstOrNull()?.docTag?.getContent().orEmpty().shorten(40) - - open val extra: MutableSet = mutableSetOf() -} - -abstract class ScopeNode : DocumentationNode() { - abstract val functions: List - abstract val properties: List - abstract val classes: List - - override val children: List - get() = functions + properties + classes -} - -abstract class CallableNode : DocumentationNode() { - abstract val receiver: Parameter? -} - -private fun String.shorten(maxLength: Int) = lineSequence().first().let { - if (it.length != length || it.length > maxLength) it.take(maxLength - 3) + "..." else it -} - -interface TypeWrapper { - val constructorFqName: String? - val constructorNamePathSegments: List - val arguments: List - val dri: DRI? -} -interface ClassKind - -fun DocumentationNode.dfs(predicate: (DocumentationNode) -> Boolean): DocumentationNode? = - if (predicate(this)) { - this - } else { - this.children.asSequence().mapNotNull { it.dfs(predicate) }.firstOrNull() - } - -interface Extra \ No newline at end of file diff --git a/core/src/main/kotlin/Utilities/DokkaLogging.kt b/core/src/main/kotlin/Utilities/DokkaLogging.kt deleted file mode 100644 index d0d1bff6..00000000 --- a/core/src/main/kotlin/Utilities/DokkaLogging.kt +++ /dev/null @@ -1,31 +0,0 @@ -package org.jetbrains.dokka - -interface DokkaLogger { - fun debug(message: String) - fun info(message: String) - fun progress(message: String) - fun warn(message: String) - fun error(message: String) -} - -object DokkaConsoleLogger : DokkaLogger { - var warningCount: Int = 0 - - override fun debug(message: String)= println(message) - - override fun progress(message: String) = println("PROGRESS: $message") - - override fun info(message: String) = println(message) - - override fun warn(message: String) = println("WARN: $message").also { warningCount++ } - - override fun error(message: String) = println("ERROR: $message") - - fun report() { - if (warningCount > 0) { - println("generation completed with $warningCount warnings") - } else { - println("generation completed successfully") - } - } -} diff --git a/core/src/main/kotlin/Utilities/Html.kt b/core/src/main/kotlin/Utilities/Html.kt deleted file mode 100644 index de1ce1a5..00000000 --- a/core/src/main/kotlin/Utilities/Html.kt +++ /dev/null @@ -1,12 +0,0 @@ -package org.jetbrains.dokka - -import java.net.URLEncoder - - -/** - * Replaces symbols reserved in HTML with their respective entities. - * Replaces & with &, < with < and > with > - */ -fun String.htmlEscape(): String = replace("&", "&").replace("<", "<").replace(">", ">") - -fun String.urlEncoded(): String = URLEncoder.encode(this, "UTF-8") \ No newline at end of file diff --git a/core/src/main/kotlin/Utilities/Path.kt b/core/src/main/kotlin/Utilities/Path.kt deleted file mode 100644 index 05838499..00000000 --- a/core/src/main/kotlin/Utilities/Path.kt +++ /dev/null @@ -1,5 +0,0 @@ -package org.jetbrains.dokka - -import java.io.File - -fun File.appendExtension(extension: String) = if (extension.isEmpty()) this else File(path + "." + extension) diff --git a/core/src/main/kotlin/Utilities/ServiceLocator.kt b/core/src/main/kotlin/Utilities/ServiceLocator.kt deleted file mode 100644 index eda83422..00000000 --- a/core/src/main/kotlin/Utilities/ServiceLocator.kt +++ /dev/null @@ -1,97 +0,0 @@ -package org.jetbrains.dokka.Utilities - -import java.io.File -import java.net.URISyntaxException -import java.net.URL -import java.util.* -import java.util.jar.JarFile -import java.util.zip.ZipEntry - -data class ServiceDescriptor(val name: String, val category: String, val description: String?, val className: String) - -class ServiceLookupException(message: String) : Exception(message) - -object ServiceLocator { - fun lookup(clazz: Class, category: String, implementationName: String): T { - val descriptor = lookupDescriptor(category, implementationName) - return lookup(clazz, descriptor) - } - - fun lookup( - clazz: Class, - descriptor: ServiceDescriptor - ): T { - val loadedClass = javaClass.classLoader.loadClass(descriptor.className) - val constructor = loadedClass.constructors.firstOrNull { it.parameterTypes.isEmpty() } ?: throw ServiceLookupException("Class ${descriptor.className} has no corresponding constructor") - - val implementationRawType: Any = - if (constructor.parameterTypes.isEmpty()) constructor.newInstance() else constructor.newInstance(constructor) - - if (!clazz.isInstance(implementationRawType)) { - throw ServiceLookupException("Class ${descriptor.className} is not a subtype of ${clazz.name}") - } - - @Suppress("UNCHECKED_CAST") - return implementationRawType as T - } - - private fun lookupDescriptor(category: String, implementationName: String): ServiceDescriptor { - val properties = javaClass.classLoader.getResourceAsStream("dokka/$category/$implementationName.properties")?.use { stream -> - Properties().let { properties -> - properties.load(stream) - properties - } - } ?: throw ServiceLookupException("No implementation with name $implementationName found in category $category") - - val className = properties["class"]?.toString() ?: throw ServiceLookupException("Implementation $implementationName has no class configured") - - return ServiceDescriptor(implementationName, category, properties["description"]?.toString(), className) - } - - fun URL.toFile(): File { - assert(protocol == "file") - - return try { - File(toURI()) - } catch (e: URISyntaxException) { //Try to handle broken URLs, with unescaped spaces - File(path) - } - } - - fun allServices(category: String): List { - val entries = this.javaClass.classLoader.getResources("dokka/$category")?.toList() ?: emptyList() - - return entries.flatMap { - when (it.protocol) { - "file" -> it.toFile().listFiles()?.filter { it.extension == "properties" }?.map { lookupDescriptor(category, it.nameWithoutExtension) } ?: emptyList() - "jar" -> { - val file = JarFile(URL(it.file.substringBefore("!")).toFile()) - try { - val jarPath = it.file.substringAfterLast("!").removePrefix("/").removeSuffix("/") - file.entries() - .asSequence() - .filter { entry -> !entry.isDirectory && entry.path == jarPath && entry.extension == "properties" } - .map { entry -> - lookupDescriptor(category, entry.fileName.substringBeforeLast(".")) - }.toList() - } finally { - file.close() - } - } - else -> emptyList() - } - } - } -} - -inline fun ServiceLocator.lookup(category: String, implementationName: String): T = lookup(T::class.java, category, implementationName) -inline fun ServiceLocator.lookup(desc: ServiceDescriptor): T = lookup(T::class.java, desc) - -private val ZipEntry.fileName: String - get() = name.substringAfterLast("/", name) - -private val ZipEntry.path: String - get() = name.substringBeforeLast("/", "").removePrefix("/") - -private val ZipEntry.extension: String? - get() = fileName.let { fn -> if ("." in fn) fn.substringAfterLast(".") else null } diff --git a/core/src/main/kotlin/Utilities/Uri.kt b/core/src/main/kotlin/Utilities/Uri.kt deleted file mode 100644 index 9827c624..00000000 --- a/core/src/main/kotlin/Utilities/Uri.kt +++ /dev/null @@ -1,40 +0,0 @@ -package org.jetbrains.dokka - -import java.net.URI - - -fun URI.relativeTo(uri: URI): URI { - // Normalize paths to remove . and .. segments - val base = uri.normalize() - val child = this.normalize() - - fun StringBuilder.appendRelativePath() { - // Split paths into segments - var bParts = base.path.split('/').dropLastWhile { it.isEmpty() } - val cParts = child.path.split('/').dropLastWhile { it.isEmpty() } - - // Discard trailing segment of base path - if (bParts.isNotEmpty() && !base.path.endsWith("/")) { - bParts = bParts.dropLast(1) - } - - // Compute common prefix - val commonPartsSize = bParts.zip(cParts).takeWhile { (basePart, childPart) -> basePart == childPart }.count() - bParts.drop(commonPartsSize).joinTo(this, separator = "") { "../" } - cParts.drop(commonPartsSize).joinTo(this, separator = "/") - } - - return URI.create(buildString { - if (base.path != child.path) { - appendRelativePath() - } - child.rawQuery?.let { - append("?") - append(it) - } - child.rawFragment?.let { - append("#") - append(it) - } - }) -} \ No newline at end of file diff --git a/core/src/main/kotlin/Utilities/nodeDebug.kt b/core/src/main/kotlin/Utilities/nodeDebug.kt deleted file mode 100644 index e89f88ec..00000000 --- a/core/src/main/kotlin/Utilities/nodeDebug.kt +++ /dev/null @@ -1,51 +0,0 @@ -package org.jetbrains.dokka.Utilities - -import org.jetbrains.dokka.Model.DocumentationNode -import org.jetbrains.dokka.pages.* -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor - -const val DOWN = '\u2503' -const val BRANCH = '\u2523' -const val LAST = '\u2517' - -fun DocumentationNode.pretty(prefix: String = "", isLast: Boolean = true): String { - val nextPrefix = prefix + (if (isLast) ' ' else DOWN) + ' ' - - return prefix + (if (isLast) LAST else BRANCH) + this.toString() + - children.dropLast(1) - .map { it.pretty(nextPrefix, false) } - .plus(children.lastOrNull()?.pretty(nextPrefix)) - .filterNotNull() - .takeIf { it.isNotEmpty() } - ?.joinToString(prefix = "\n", separator = "") - .orEmpty() + if (children.isEmpty()) "\n" else "" -} - -//fun Any.genericPretty(prefix: String = "", isLast: Boolean = true): String { -// val nextPrefix = prefix + (if (isLast) ' ' else DOWN) + ' ' -// -// return prefix + (if (isLast) LAST else BRANCH) + this.stringify() + -// allChildren().dropLast(1) -// .map { it.genericPretty(nextPrefix, false) } -// .plus(allChildren().lastOrNull()?.genericPretty(nextPrefix)) -// .filterNotNull() -// .takeIf { it.isNotEmpty() } -// ?.joinToString(prefix = "\n", separator = "") -// .orEmpty() + if (allChildren().isEmpty()) "\n" else "" -//} -private fun Any.stringify() = when(this) { - is ContentNode -> toString() + this.dci - is PageNode -> this.name + this::class.simpleName - else -> toString() -} -//private fun Any.allChildren() = when(this){ -// is PageNode -> children + content -// is ContentBlock -> this.children -// is ContentHeader -> this.items -// is ContentStyle -> this.items -// is ContentSymbol -> this.parts -// is ContentComment -> this.parts -// is ContentGroup -> this.children -// is ContentList -> this.items -// else -> emptyList() -//} diff --git a/core/src/main/kotlin/analysis/AnalysisEnvironment.kt b/core/src/main/kotlin/analysis/AnalysisEnvironment.kt new file mode 100644 index 00000000..30a51136 --- /dev/null +++ b/core/src/main/kotlin/analysis/AnalysisEnvironment.kt @@ -0,0 +1,454 @@ +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 com.intellij.util.io.URLUtil +import org.jetbrains.dokka.Platform +import org.jetbrains.kotlin.analyzer.* +import org.jetbrains.kotlin.analyzer.common.CommonAnalysisParameters +import org.jetbrains.kotlin.analyzer.common.CommonAnalyzerFacade +import org.jetbrains.kotlin.builtins.DefaultBuiltIns +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.builtins.jvm.JvmBuiltIns +import org.jetbrains.kotlin.caches.project.LibraryModuleInfo +import org.jetbrains.kotlin.caches.resolve.KotlinCacheService +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.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.idea.resolve.ResolutionFacade +import org.jetbrains.kotlin.js.config.JSConfigurationKeys +import org.jetbrains.kotlin.js.resolve.JsPlatform +import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.* +import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics +import org.jetbrains.kotlin.resolve.jvm.JvmAnalyzerFacade +import org.jetbrains.kotlin.resolve.jvm.JvmPlatformParameters +import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform +import org.jetbrains.kotlin.resolve.konan.platform.KonanPlatform +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +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 java.io.File + +/** + * 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.fallback", "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) + + Extensions.registerAreaClass("IDEA_MODULE", null) + CoreApplicationEnvironment.registerExtensionPoint(Extensions.getRootArea(), + OrderEnumerationHandler.EP_NAME, OrderEnumerationHandler.Factory::class.java) + + projectComponentManager.registerService(ProjectFileIndex::class.java, + projectFileIndex) + projectComponentManager.registerService(ProjectRootManager::class.java, + CoreProjectRootManager(projectFileIndex)) + return environment + } + + 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) + val sourceFiles = environment.getSourceFiles() + + + val targetPlatform = when (analysisPlatform) { + Platform.js -> JsPlatform + Platform.common -> TargetPlatform.Common + Platform.native -> KonanPlatform + Platform.jvm -> JvmPlatform + } + + val library = object : LibraryModuleInfo { + override val platform: TargetPlatform + get() = targetPlatform + + override fun getLibraryRoots(): Collection { + return classpath.map { it.absolutePath } + } + + override val name: Name = Name.special("") + override fun dependencies(): List = listOf(this) + } + val module = object : ModuleInfo { + override val name: Name = Name.special("") + override fun dependencies(): List = listOf(this, library) + } + + 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)) + else -> throw IllegalArgumentException("Unexpected module info") + } + } + + var builtIns: JvmBuiltIns? = null + + val resolverForProject = when (analysisPlatform) { + Platform.jvm -> { + builtIns = JvmBuiltIns(projectContext.storageManager) + 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 resolverForLibrary = resolverForProject.resolverForModule(library) // Required before module to initialize library properly + val resolverForModule = resolverForProject.resolverForModule(module) + val libraryModuleDescriptor = resolverForProject.descriptorForModule(library) + val moduleDescriptor = resolverForProject.descriptorForModule(module) + builtIns?.initialize(moduleDescriptor, true) + 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 createCommonResolverForProject( + projectContext: ProjectContext, + module: ModuleInfo, + library: LibraryModuleInfo, + modulesContent: (ModuleInfo) -> ModuleContent, + environment: KotlinCoreEnvironment + ): ResolverForProjectImpl { + return ResolverForProjectImpl( + debugName = "Dokka", + projectContext = projectContext, + modules = listOf(module, library), + modulesContent = modulesContent, + modulePlatforms = { MultiTargetPlatform.Common }, + moduleLanguageSettingsProvider = LanguageSettingsProvider.Default /* TODO: Fix this */, + resolverForModuleFactoryByPlatform = { CommonAnalyzerFacade }, + platformParameters = { _ -> + CommonAnalysisParameters { content -> + environment.createPackagePartProvider(content.moduleContentScope) + } + }, + targetEnvironment = CompilerEnvironment, + builtIns = DefaultBuiltIns.Instance + ) + } + + private fun createJsResolverForProject( + projectContext: ProjectContext, + module: ModuleInfo, + library: LibraryModuleInfo, + modulesContent: (ModuleInfo) -> ModuleContent + ): ResolverForProjectImpl { + return ResolverForProjectImpl( + debugName = "Dokka", + projectContext = projectContext, + modules = listOf(module, library), + modulesContent = modulesContent, + modulePlatforms = { JsPlatform.multiTargetPlatform }, + moduleLanguageSettingsProvider = LanguageSettingsProvider.Default /* TODO: Fix this */, + resolverForModuleFactoryByPlatform = { DokkaJsAnalyzerFacade }, + platformParameters = { _ -> PlatformAnalysisParameters.Empty }, + targetEnvironment = CompilerEnvironment, + builtIns = JsPlatform.builtIns + ) + } + + private fun createNativeResolverForProject( + projectContext: ProjectContext, + module: ModuleInfo, + library: LibraryModuleInfo, + modulesContent: (ModuleInfo) -> ModuleContent + ): ResolverForProjectImpl { + return ResolverForProjectImpl( + debugName = "Dokka", + projectContext = projectContext, + modules = listOf(module, library), + modulesContent = modulesContent, + modulePlatforms = { KonanPlatform.multiTargetPlatform }, + moduleLanguageSettingsProvider = LanguageSettingsProvider.Default /* TODO: Fix this */, + resolverForModuleFactoryByPlatform = { DokkaNativeAnalyzerFacade }, + platformParameters = { _ -> PlatformAnalysisParameters.Empty }, + targetEnvironment = CompilerEnvironment + ) + + } + + private fun createJvmResolverForProject( + projectContext: ProjectContext, + module: ModuleInfo, + library: LibraryModuleInfo, + modulesContent: (ModuleInfo) -> ModuleContent, + sourcesScope: GlobalSearchScope, + builtIns: KotlinBuiltIns + ): ResolverForProjectImpl { + val javaRoots = classpath + .mapNotNull { + val rootFile = when { + it.extension == "jar" -> + StandardFileSystems.jar().findFileByPath("${it.absolutePath}${URLUtil.JAR_SEPARATOR}") + else -> + StandardFileSystems.local().findFileByPath(it.absolutePath) + } + + rootFile?.let { JavaRoot(it, JavaRoot.RootType.BINARY) } + } + + return ResolverForProjectImpl( + debugName = "Dokka", + projectContext = projectContext, + modules = listOf(library, module), + modulesContent = { + when (it) { + library -> ModuleContent(it, emptyList(), GlobalSearchScope.notScope(sourcesScope)) + module -> ModuleContent(it, emptyList(), sourcesScope) + else -> throw IllegalArgumentException("Unexpected module info") + } + }, + modulePlatforms = { JvmPlatform.multiTargetPlatform }, + moduleLanguageSettingsProvider = LanguageSettingsProvider.Default /* TODO: Fix this */, + resolverForModuleFactoryByPlatform = { JvmAnalyzerFacade }, + platformParameters = { + JvmPlatformParameters ({ content -> + JvmPackagePartProvider( + configuration.languageVersionSettings, + content.moduleContentScope) + .apply { + addRoots(javaRoots, messageCollector) + } + }, { + val file = (it as JavaClassImpl).psi.containingFile.virtualFile + if (file in sourcesScope) + module + else + library + }) + }, + targetEnvironment = CompilerEnvironment, + builtIns = builtIns + ) + } + + 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) + } +} + +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/core/src/main/kotlin/analysis/CoreKotlinCacheService.kt b/core/src/main/kotlin/analysis/CoreKotlinCacheService.kt new file mode 100644 index 00000000..509c4e10 --- /dev/null +++ b/core/src/main/kotlin/analysis/CoreKotlinCacheService.kt @@ -0,0 +1,30 @@ +package org.jetbrains.dokka.analysis + +import com.intellij.psi.PsiFile +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.TargetPlatform +import org.jetbrains.kotlin.resolve.diagnostics.KotlinSuppressCache + + +class CoreKotlinCacheService(private val resolutionFacade: DokkaResolutionFacade) : KotlinCacheService { + override fun getResolutionFacade(elements: List): ResolutionFacade { + return resolutionFacade + } + + override fun getResolutionFacadeByFile(file: PsiFile, platform: TargetPlatform): ResolutionFacade { + return resolutionFacade + } + + override fun getResolutionFacadeByModuleInfo(moduleInfo: ModuleInfo, platform: TargetPlatform): ResolutionFacade? { + return resolutionFacade + } + + override fun getSuppressionCache(): KotlinSuppressCache { + throw UnsupportedOperationException() + } + +} + diff --git a/core/src/main/kotlin/analysis/CoreProjectFileIndex.kt b/core/src/main/kotlin/analysis/CoreProjectFileIndex.kt new file mode 100644 index 00000000..6863a266 --- /dev/null +++ b/core/src/main/kotlin/analysis/CoreProjectFileIndex.kt @@ -0,0 +1,568 @@ +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.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 getOptionValue(p0: String): String? { + throw UnsupportedOperationException() + } + + override fun clearOption(p0: String) { + throw UnsupportedOperationException() + } + + override fun getName(): String = "" + + override fun getModuleWithLibrariesScope(): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun getModuleWithDependentsScope(): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun getModuleContentScope(): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun isLoaded(): Boolean { + throw UnsupportedOperationException() + } + + override fun setOption(p0: String, p1: String?) { + throw UnsupportedOperationException() + } + + override fun getModuleWithDependenciesScope(): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun getModuleWithDependenciesAndLibrariesScope(p0: Boolean): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun getProject(): Project = this@CoreProjectFileIndex.project + + override fun getModuleContentWithDependenciesScope(): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun getModuleFilePath(): String { + throw UnsupportedOperationException() + } + + override fun getModuleTestsWithDependentsScope(): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun getModuleScope(): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun getModuleScope(p0: Boolean): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun getModuleRuntimeScope(p0: Boolean): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun getModuleFile(): VirtualFile? { + throw UnsupportedOperationException() + } + + override fun getExtensions(p0: ExtensionPointName): Array { + throw UnsupportedOperationException() + } + + override fun getComponent(p0: String): BaseComponent? { + throw UnsupportedOperationException() + } + + override fun getComponent(p0: Class, p1: T): T { + 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 getComponents(p0: Class): Array { + throw UnsupportedOperationException() + } + + override fun getPicoContainer(): PicoContainer { + throw UnsupportedOperationException() + } + + override fun hasComponent(p0: Class<*>): Boolean { + 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) + StandardFileSystems.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/core/src/main/kotlin/analysis/DokkaAnalyzerFacades.kt b/core/src/main/kotlin/analysis/DokkaAnalyzerFacades.kt new file mode 100644 index 00000000..c69ff645 --- /dev/null +++ b/core/src/main/kotlin/analysis/DokkaAnalyzerFacades.kt @@ -0,0 +1,164 @@ +package org.jetbrains.dokka.analysis + +import org.jetbrains.kotlin.analyzer.* +import org.jetbrains.kotlin.caches.project.LibraryModuleInfo +import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.config.TargetPlatformVersion +import org.jetbrains.kotlin.container.StorageComponentContainer +import org.jetbrains.kotlin.container.get +import org.jetbrains.kotlin.container.useImpl +import org.jetbrains.kotlin.container.useInstance +import org.jetbrains.kotlin.context.ModuleContext +import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider +import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl +import org.jetbrains.kotlin.frontend.di.configureModule +import org.jetbrains.kotlin.ide.konan.KOTLIN_NATIVE_CURRENT_ABI_VERSION +import org.jetbrains.kotlin.ide.konan.createPackageFragmentProvider +import org.jetbrains.kotlin.incremental.components.LookupTracker +import org.jetbrains.kotlin.js.resolve.JsPlatform +import org.jetbrains.kotlin.konan.file.File +import org.jetbrains.kotlin.konan.library.createKonanLibrary +import org.jetbrains.kotlin.resolve.* +import org.jetbrains.kotlin.resolve.konan.platform.KonanPlatform +import org.jetbrains.kotlin.resolve.lazy.ResolveSession +import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory +import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService +import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil +import org.jetbrains.kotlin.serialization.js.createKotlinJavascriptPackageFragmentProvider +import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils + +fun createContainerForLazyResolve( + moduleContext: ModuleContext, + declarationProviderFactory: DeclarationProviderFactory, + bindingTrace: BindingTrace, + platform: TargetPlatform, + targetPlatformVersion: TargetPlatformVersion, + targetEnvironment: TargetEnvironment, + languageVersionSettings: LanguageVersionSettings +): StorageComponentContainer = createContainer("LazyResolve", platform) { + configureModule(moduleContext, platform, targetPlatformVersion, bindingTrace) + + useInstance(declarationProviderFactory) + useInstance(languageVersionSettings) + + useImpl() + useImpl() + targetEnvironment.configure(this) + + useImpl() + useImpl() +} + + +object DokkaJsAnalyzerFacade : ResolverForModuleFactory() { + override fun createResolverForModule( + moduleDescriptor: ModuleDescriptorImpl, + moduleContext: ModuleContext, + moduleContent: ModuleContent, + platformParameters: PlatformAnalysisParameters, + targetEnvironment: TargetEnvironment, + resolverForProject: ResolverForProject, + languageVersionSettings: LanguageVersionSettings, + targetPlatformVersion: TargetPlatformVersion + ): ResolverForModule { + val (moduleInfo, syntheticFiles, moduleContentScope) = moduleContent + val project = moduleContext.project + val declarationProviderFactory = DeclarationProviderFactoryService.createDeclarationProviderFactory( + project, + moduleContext.storageManager, + syntheticFiles, + moduleContentScope, + moduleInfo + ) + + val container = createContainerForLazyResolve( + moduleContext, + declarationProviderFactory, + BindingTraceContext(), + JsPlatform, + TargetPlatformVersion.NoVersion, + targetEnvironment, + languageVersionSettings + ) + var packageFragmentProvider = container.get().packageFragmentProvider + + if (moduleInfo is LibraryModuleInfo && moduleInfo.platform == JsPlatform) { + val providers = moduleInfo.getLibraryRoots() + .flatMap { KotlinJavascriptMetadataUtils.loadMetadata(it) } + .filter { it.version.isCompatible() } + .map { metadata -> + val (header, packageFragmentProtos) = + KotlinJavascriptSerializationUtil.readModuleAsProto(metadata.body, metadata.version) + createKotlinJavascriptPackageFragmentProvider( + moduleContext.storageManager, moduleDescriptor, header, packageFragmentProtos, metadata.version, + container.get(), LookupTracker.DO_NOTHING + ) + } + + if (providers.isNotEmpty()) { + packageFragmentProvider = CompositePackageFragmentProvider(listOf(packageFragmentProvider) + providers) + } + } + + return ResolverForModule(packageFragmentProvider, container) + } + + override val targetPlatform: TargetPlatform + get() = JsPlatform +} + +object DokkaNativeAnalyzerFacade : ResolverForModuleFactory() { + override val targetPlatform: TargetPlatform + get() = KonanPlatform + + override fun createResolverForModule( + moduleDescriptor: ModuleDescriptorImpl, + moduleContext: ModuleContext, + moduleContent: ModuleContent, + platformParameters: PlatformAnalysisParameters, + targetEnvironment: TargetEnvironment, + resolverForProject: ResolverForProject, + languageVersionSettings: LanguageVersionSettings, + targetPlatformVersion: TargetPlatformVersion + ): ResolverForModule { + + val declarationProviderFactory = DeclarationProviderFactoryService.createDeclarationProviderFactory( + moduleContext.project, + moduleContext.storageManager, + moduleContent.syntheticFiles, + moduleContent.moduleContentScope, + moduleContent.moduleInfo + ) + + val container = createContainerForLazyResolve( + moduleContext, + declarationProviderFactory, + BindingTraceContext(), + targetPlatform, + TargetPlatformVersion.NoVersion, + targetEnvironment, + languageVersionSettings + ) + + val packageFragmentProvider = container.get().packageFragmentProvider + val fragmentProviders = mutableListOf(packageFragmentProvider) + + val moduleInfo = moduleContent.moduleInfo + + if (moduleInfo is LibraryModuleInfo) { + moduleInfo.getLibraryRoots() + .filter { File(it).extension != "jar" } + .map { createKonanLibrary(File(it), KOTLIN_NATIVE_CURRENT_ABI_VERSION) } + .mapTo(fragmentProviders) { + it.createPackageFragmentProvider( + moduleContext.storageManager, + languageVersionSettings, + moduleDescriptor + ) + } + + } + + return ResolverForModule(CompositePackageFragmentProvider(fragmentProviders), container) + } +} diff --git a/core/src/main/kotlin/analysis/JavaResolveExtension.kt b/core/src/main/kotlin/analysis/JavaResolveExtension.kt new file mode 100644 index 00000000..2b60a639 --- /dev/null +++ b/core/src/main/kotlin/analysis/JavaResolveExtension.kt @@ -0,0 +1,131 @@ +/* + * 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.classes.KtLightClass +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.psi.KtClassOrObject +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.psiUtil.parameterIndex +import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver +import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform +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, JvmPlatform)!! diff --git a/core/src/main/kotlin/markdown/MarkdownProcessor.kt b/core/src/main/kotlin/markdown/MarkdownProcessor.kt new file mode 100644 index 00000000..1304d58e --- /dev/null +++ b/core/src/main/kotlin/markdown/MarkdownProcessor.kt @@ -0,0 +1,53 @@ +package org.jetbrains.dokka.markdown + +import org.intellij.markdown.IElementType +import org.intellij.markdown.MarkdownElementTypes +import org.intellij.markdown.ast.ASTNode +import org.intellij.markdown.ast.LeafASTNode +import org.intellij.markdown.ast.getTextInNode +import org.intellij.markdown.flavours.commonmark.CommonMarkFlavourDescriptor +import org.intellij.markdown.parser.MarkdownParser + +class MarkdownNode(val node: ASTNode, val parent: MarkdownNode?, val markdown: String) { + val children: List = node.children.map { MarkdownNode(it, this, markdown) } + val type: IElementType get() = node.type + val text: String get() = node.getTextInNode(markdown).toString() + fun child(type: IElementType): MarkdownNode? = children.firstOrNull { it.type == type } + + val previous get() = parent?.children?.getOrNull(parent.children.indexOf(this) - 1) + + override fun toString(): String = StringBuilder().apply { presentTo(this) }.toString() +} + +fun MarkdownNode.visit(action: (MarkdownNode, () -> Unit) -> Unit) { + action(this) { + for (child in children) { + child.visit(action) + } + } +} + +fun MarkdownNode.toTestString(): String { + val sb = StringBuilder() + var level = 0 + visit { node, visitChildren -> + sb.append(" ".repeat(level * 2)) + node.presentTo(sb) + sb.appendln() + level++ + visitChildren() + level-- + } + return sb.toString() +} + +private fun MarkdownNode.presentTo(sb: StringBuilder) { + sb.append(type.toString()) + sb.append(":" + text.replace("w\n", "\u23CE")) +} + +fun parseMarkdown(markdown: String): MarkdownNode { + if (markdown.isEmpty()) + return MarkdownNode(LeafASTNode(MarkdownElementTypes.MARKDOWN_FILE, 0, 0), null, markdown) + return MarkdownNode(MarkdownParser(CommonMarkFlavourDescriptor()).buildMarkdownTreeFromString(markdown), null, markdown) +} diff --git a/core/src/main/kotlin/model/DocumentationNode.kt b/core/src/main/kotlin/model/DocumentationNode.kt new file mode 100644 index 00000000..77225eca --- /dev/null +++ b/core/src/main/kotlin/model/DocumentationNode.kt @@ -0,0 +1,162 @@ +package org.jetbrains.dokka.model + +import org.jetbrains.dokka.transformers.descriptors.KotlinTypeWrapper +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.pages.PlatformData +import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag + +class Module(val packages: List) : DocumentationNode() { + override val dri: DRI = DRI.topLevel + override val children: List = packages + override val extra: MutableSet = mutableSetOf() +} + +class Package( + override val dri: DRI, + override val functions: List, + override val properties: List, + override val classes: List, + override val extra: MutableSet = mutableSetOf() +) : ScopeNode() { + override val name = dri.packageName.orEmpty() +} + +class Class( + override val dri: DRI, + override val name: String, + val kind: ClassKind, + val constructors: List, + override val functions: List, + override val properties: List, + override val classes: List, + override val expected: ClassPlatformInfo?, + override val actual: List, + override val extra: MutableSet = mutableSetOf() +) : ScopeNode() { + val inherited by lazy { platformInfo.mapNotNull { (it as? ClassPlatformInfo)?.inherited }.flatten() } +} + +class Function( + override val dri: DRI, + override val name: String, + val returnType: TypeWrapper?, + val isConstructor: Boolean, + override val receiver: Parameter?, + val parameters: List, + override val expected: PlatformInfo?, + override val actual: List, + override val extra: MutableSet = mutableSetOf() +) : CallableNode() { + override val children: List + get() = listOfNotNull(receiver) + parameters +} + +class Property( + override val dri: DRI, + override val name: String, + override val receiver: Parameter?, + override val expected: PlatformInfo?, + override val actual: List, + override val extra: MutableSet = mutableSetOf() +) : CallableNode() { + override val children: List + get() = listOfNotNull(receiver) +} + +// TODO: treat named Parameters and receivers differently +class Parameter( + override val dri: DRI, + override val name: String?, + val type: TypeWrapper, + override val actual: List, + override val extra: MutableSet = mutableSetOf() +) : DocumentationNode() { + override val children: List + get() = emptyList() +} + +interface PlatformInfo { + val docTag: KDocTag? + val links: Map + val platformData: List +} + +class BasePlatformInfo( + override val docTag: KDocTag?, + override val links: Map, + override val platformData: List) : PlatformInfo { + + override fun equals(other: Any?): Boolean = + other is PlatformInfo && ( + docTag?.text == other.docTag?.text && + links == other.links) + + override fun hashCode(): Int = + listOf(docTag?.text, links).hashCode() +} + +class ClassPlatformInfo( + val info: PlatformInfo, + val inherited: List) : PlatformInfo by info + +abstract class DocumentationNode { + open val expected: PlatformInfo? = null + open val actual: List = emptyList() + open val name: String? = null + val platformInfo by lazy { listOfNotNull(expected) + actual } + val platformData by lazy { platformInfo.flatMap { it.platformData }.toSet() } + + abstract val dri: DRI + + abstract val children: List + + override fun toString(): String { + return "${javaClass.simpleName}($dri)" + briefDocstring.takeIf { it.isNotBlank() }?.let { " [$it]" }.orEmpty() + } + + override fun equals(other: Any?) = other is DocumentationNode && this.dri == other.dri + + override fun hashCode() = dri.hashCode() + + val commentsData: List>> + get() = platformInfo.mapNotNull { it.docTag?.let { tag -> Pair(tag.getContent(), it.links) } } + + val briefDocstring: String + get() = platformInfo.firstOrNull()?.docTag?.getContent().orEmpty().shorten(40) + + open val extra: MutableSet = mutableSetOf() +} + +abstract class ScopeNode : DocumentationNode() { + abstract val functions: List + abstract val properties: List + abstract val classes: List + + override val children: List + get() = functions + properties + classes +} + +abstract class CallableNode : DocumentationNode() { + abstract val receiver: Parameter? +} + +private fun String.shorten(maxLength: Int) = lineSequence().first().let { + if (it.length != length || it.length > maxLength) it.take(maxLength - 3) + "..." else it +} + +interface TypeWrapper { + val constructorFqName: String? + val constructorNamePathSegments: List + val arguments: List + val dri: DRI? +} +interface ClassKind + +fun DocumentationNode.dfs(predicate: (DocumentationNode) -> Boolean): DocumentationNode? = + if (predicate(this)) { + this + } else { + this.children.asSequence().mapNotNull { it.dfs(predicate) }.firstOrNull() + } + +interface Extra \ No newline at end of file diff --git a/core/src/main/kotlin/pages/DefaultMarkdownToContentConverter.kt b/core/src/main/kotlin/pages/DefaultMarkdownToContentConverter.kt index 72b5ead2..369c1edb 100644 --- a/core/src/main/kotlin/pages/DefaultMarkdownToContentConverter.kt +++ b/core/src/main/kotlin/pages/DefaultMarkdownToContentConverter.kt @@ -2,7 +2,7 @@ package org.jetbrains.dokka.pages import org.intellij.markdown.MarkdownElementTypes import org.intellij.markdown.MarkdownTokenTypes -import org.jetbrains.dokka.MarkdownNode +import org.jetbrains.dokka.markdown.MarkdownNode import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.plugability.DokkaContext diff --git a/core/src/main/kotlin/pages/MarkdownToContentConverter.kt b/core/src/main/kotlin/pages/MarkdownToContentConverter.kt index fe4736b7..cd96ff79 100644 --- a/core/src/main/kotlin/pages/MarkdownToContentConverter.kt +++ b/core/src/main/kotlin/pages/MarkdownToContentConverter.kt @@ -1,8 +1,7 @@ package org.jetbrains.dokka.pages -import org.jetbrains.dokka.MarkdownNode +import org.jetbrains.dokka.markdown.MarkdownNode import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.plugability.DokkaContext interface MarkdownToContentConverter { fun buildContent( diff --git a/core/src/main/kotlin/pages/PageBuilder.kt b/core/src/main/kotlin/pages/PageBuilder.kt index d20635a4..92e2c5fe 100644 --- a/core/src/main/kotlin/pages/PageBuilder.kt +++ b/core/src/main/kotlin/pages/PageBuilder.kt @@ -1,7 +1,7 @@ package org.jetbrains.dokka.pages -import org.jetbrains.dokka.Model.* -import org.jetbrains.dokka.Model.Function +import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.model.Function class DefaultPageBuilder( override val rootContentGroup: RootContentBuilder diff --git a/core/src/main/kotlin/pages/PageContentBuilder.kt b/core/src/main/kotlin/pages/PageContentBuilder.kt index 2341a59d..3e852306 100644 --- a/core/src/main/kotlin/pages/PageContentBuilder.kt +++ b/core/src/main/kotlin/pages/PageContentBuilder.kt @@ -1,12 +1,12 @@ package org.jetbrains.dokka.pages -import org.jetbrains.dokka.DokkaLogger -import org.jetbrains.dokka.Model.DocumentationNode -import org.jetbrains.dokka.Model.Function -import org.jetbrains.dokka.Model.Parameter -import org.jetbrains.dokka.Model.TypeWrapper +import org.jetbrains.dokka.utilities.DokkaLogger +import org.jetbrains.dokka.model.DocumentationNode +import org.jetbrains.dokka.model.Function +import org.jetbrains.dokka.model.Parameter +import org.jetbrains.dokka.model.TypeWrapper import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.parseMarkdown +import org.jetbrains.dokka.markdown.parseMarkdown class DefaultPageContentBuilder( private val dri: DRI, diff --git a/core/src/main/kotlin/pages/PageNodes.kt b/core/src/main/kotlin/pages/PageNodes.kt index cf5bf453..e8b66f4a 100644 --- a/core/src/main/kotlin/pages/PageNodes.kt +++ b/core/src/main/kotlin/pages/PageNodes.kt @@ -1,6 +1,6 @@ package org.jetbrains.dokka.pages -import org.jetbrains.dokka.Model.DocumentationNode +import org.jetbrains.dokka.model.DocumentationNode import org.jetbrains.dokka.Platform import org.jetbrains.dokka.links.DRI diff --git a/core/src/main/kotlin/plugability/DokkaContext.kt b/core/src/main/kotlin/plugability/DokkaContext.kt index 31c56728..7b1c1306 100644 --- a/core/src/main/kotlin/plugability/DokkaContext.kt +++ b/core/src/main/kotlin/plugability/DokkaContext.kt @@ -1,6 +1,6 @@ package org.jetbrains.dokka.plugability -import org.jetbrains.dokka.DokkaLogger +import org.jetbrains.dokka.utilities.DokkaLogger import org.jetbrains.dokka.EnvironmentAndFacade import org.jetbrains.dokka.pages.PlatformData import java.io.File diff --git a/core/src/main/kotlin/renderers/HtmlRenderer.kt b/core/src/main/kotlin/renderers/HtmlRenderer.kt index 46548699..c04a18b4 100644 --- a/core/src/main/kotlin/renderers/HtmlRenderer.kt +++ b/core/src/main/kotlin/renderers/HtmlRenderer.kt @@ -1,13 +1,11 @@ package org.jetbrains.dokka.renderers -import org.jetbrains.dokka.htmlEscape +import org.jetbrains.dokka.utilities.htmlEscape import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.resolvers.LocationProvider import java.io.File import java.net.URL -import java.nio.file.Path -import java.nio.file.Paths open class HtmlRenderer( fileWriter: FileWriter, diff --git a/core/src/main/kotlin/resolvers/DefaultLocationProvider.kt b/core/src/main/kotlin/resolvers/DefaultLocationProvider.kt index ec5aa29a..5139b3c1 100644 --- a/core/src/main/kotlin/resolvers/DefaultLocationProvider.kt +++ b/core/src/main/kotlin/resolvers/DefaultLocationProvider.kt @@ -2,7 +2,7 @@ package org.jetbrains.dokka.resolvers import org.jetbrains.dokka.CoreExtensions import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.htmlEscape +import org.jetbrains.dokka.utilities.htmlEscape import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.plugability.DokkaContext diff --git a/core/src/main/kotlin/transformers/descriptors/DefaultDescriptorToDocumentationTranslator.kt b/core/src/main/kotlin/transformers/descriptors/DefaultDescriptorToDocumentationTranslator.kt index 19aeef92..4ffa4295 100644 --- a/core/src/main/kotlin/transformers/descriptors/DefaultDescriptorToDocumentationTranslator.kt +++ b/core/src/main/kotlin/transformers/descriptors/DefaultDescriptorToDocumentationTranslator.kt @@ -1,9 +1,9 @@ package org.jetbrains.dokka.transformers.descriptors -import org.jetbrains.dokka.DokkaResolutionFacade -import org.jetbrains.dokka.Model.* -import org.jetbrains.dokka.Model.ClassKind -import org.jetbrains.dokka.Model.Function +import org.jetbrains.dokka.analysis.DokkaResolutionFacade +import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.model.ClassKind +import org.jetbrains.dokka.model.Function import org.jetbrains.dokka.links.Callable import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.links.withClass diff --git a/core/src/main/kotlin/transformers/descriptors/DescriptorToDocumentationTranslator.kt b/core/src/main/kotlin/transformers/descriptors/DescriptorToDocumentationTranslator.kt index d08aba21..bd9359ee 100644 --- a/core/src/main/kotlin/transformers/descriptors/DescriptorToDocumentationTranslator.kt +++ b/core/src/main/kotlin/transformers/descriptors/DescriptorToDocumentationTranslator.kt @@ -1,7 +1,6 @@ package org.jetbrains.dokka.transformers.descriptors -import org.jetbrains.dokka.Model.Module -import org.jetbrains.dokka.Model.Package +import org.jetbrains.dokka.model.Module import org.jetbrains.dokka.pages.PlatformData import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor diff --git a/core/src/main/kotlin/transformers/documentation/DefaultDocumentationNodeMerger.kt b/core/src/main/kotlin/transformers/documentation/DefaultDocumentationNodeMerger.kt index 46ba2816..2b00c582 100644 --- a/core/src/main/kotlin/transformers/documentation/DefaultDocumentationNodeMerger.kt +++ b/core/src/main/kotlin/transformers/documentation/DefaultDocumentationNodeMerger.kt @@ -1,7 +1,7 @@ package org.jetbrains.dokka.transformers.documentation -import org.jetbrains.dokka.Model.* -import org.jetbrains.dokka.Model.Function +import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.model.Function import org.jetbrains.dokka.plugability.DokkaContext internal object DefaultDocumentationNodeMerger : DocumentationNodeMerger { diff --git a/core/src/main/kotlin/transformers/documentation/DefaultDocumentationToPageTranslator.kt b/core/src/main/kotlin/transformers/documentation/DefaultDocumentationToPageTranslator.kt index 236d0864..c6813ef8 100644 --- a/core/src/main/kotlin/transformers/documentation/DefaultDocumentationToPageTranslator.kt +++ b/core/src/main/kotlin/transformers/documentation/DefaultDocumentationToPageTranslator.kt @@ -1,7 +1,7 @@ package org.jetbrains.dokka.transformers.documentation import org.jetbrains.dokka.CoreExtensions -import org.jetbrains.dokka.Model.Module +import org.jetbrains.dokka.model.Module import org.jetbrains.dokka.pages.DefaultPageBuilder import org.jetbrains.dokka.pages.DefaultPageContentBuilder import org.jetbrains.dokka.pages.ModulePageNode diff --git a/core/src/main/kotlin/transformers/documentation/DocumentationNodeMerger.kt b/core/src/main/kotlin/transformers/documentation/DocumentationNodeMerger.kt index 0423f47c..25be625e 100644 --- a/core/src/main/kotlin/transformers/documentation/DocumentationNodeMerger.kt +++ b/core/src/main/kotlin/transformers/documentation/DocumentationNodeMerger.kt @@ -1,6 +1,6 @@ package org.jetbrains.dokka.transformers.documentation -import org.jetbrains.dokka.Model.Module +import org.jetbrains.dokka.model.Module import org.jetbrains.dokka.plugability.DokkaContext interface DocumentationNodeMerger { diff --git a/core/src/main/kotlin/transformers/documentation/DocumentationNodeTransformer.kt b/core/src/main/kotlin/transformers/documentation/DocumentationNodeTransformer.kt index 8ac4a7c2..d6358f07 100644 --- a/core/src/main/kotlin/transformers/documentation/DocumentationNodeTransformer.kt +++ b/core/src/main/kotlin/transformers/documentation/DocumentationNodeTransformer.kt @@ -1,6 +1,6 @@ package org.jetbrains.dokka.transformers.documentation -import org.jetbrains.dokka.Model.Module +import org.jetbrains.dokka.model.Module import org.jetbrains.dokka.plugability.DokkaContext interface DocumentationNodeTransformer { diff --git a/core/src/main/kotlin/transformers/documentation/DocumentationToPageTranslator.kt b/core/src/main/kotlin/transformers/documentation/DocumentationToPageTranslator.kt index ffe34226..08c26b19 100644 --- a/core/src/main/kotlin/transformers/documentation/DocumentationToPageTranslator.kt +++ b/core/src/main/kotlin/transformers/documentation/DocumentationToPageTranslator.kt @@ -1,10 +1,7 @@ package org.jetbrains.dokka.transformers.documentation -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.Model.DocumentationNode -import org.jetbrains.dokka.Model.Module +import org.jetbrains.dokka.model.Module import org.jetbrains.dokka.pages.ModulePageNode -import org.jetbrains.dokka.pages.PageNode import org.jetbrains.dokka.plugability.DokkaContext interface DocumentationToPageTranslator { diff --git a/core/src/main/kotlin/utilities/DokkaLogging.kt b/core/src/main/kotlin/utilities/DokkaLogging.kt new file mode 100644 index 00000000..6eb7867b --- /dev/null +++ b/core/src/main/kotlin/utilities/DokkaLogging.kt @@ -0,0 +1,31 @@ +package org.jetbrains.dokka.utilities + +interface DokkaLogger { + fun debug(message: String) + fun info(message: String) + fun progress(message: String) + fun warn(message: String) + fun error(message: String) +} + +object DokkaConsoleLogger : DokkaLogger { + var warningCount: Int = 0 + + override fun debug(message: String)= println(message) + + override fun progress(message: String) = println("PROGRESS: $message") + + override fun info(message: String) = println(message) + + override fun warn(message: String) = println("WARN: $message").also { warningCount++ } + + override fun error(message: String) = println("ERROR: $message") + + fun report() { + if (warningCount > 0) { + println("generation completed with $warningCount warnings") + } else { + println("generation completed successfully") + } + } +} diff --git a/core/src/main/kotlin/utilities/Html.kt b/core/src/main/kotlin/utilities/Html.kt new file mode 100644 index 00000000..9dc032f6 --- /dev/null +++ b/core/src/main/kotlin/utilities/Html.kt @@ -0,0 +1,12 @@ +package org.jetbrains.dokka.utilities + +import java.net.URLEncoder + + +/** + * Replaces symbols reserved in HTML with their respective entities. + * Replaces & with &, < with < and > with > + */ +fun String.htmlEscape(): String = replace("&", "&").replace("<", "<").replace(">", ">") + +fun String.urlEncoded(): String = URLEncoder.encode(this, "UTF-8") \ No newline at end of file diff --git a/core/src/main/kotlin/utilities/Path.kt b/core/src/main/kotlin/utilities/Path.kt new file mode 100644 index 00000000..00e2aa60 --- /dev/null +++ b/core/src/main/kotlin/utilities/Path.kt @@ -0,0 +1,5 @@ +package org.jetbrains.dokka.utilities + +import java.io.File + +fun File.appendExtension(extension: String) = if (extension.isEmpty()) this else File(path + "." + extension) diff --git a/core/src/main/kotlin/utilities/ServiceLocator.kt b/core/src/main/kotlin/utilities/ServiceLocator.kt new file mode 100644 index 00000000..00c9ae9f --- /dev/null +++ b/core/src/main/kotlin/utilities/ServiceLocator.kt @@ -0,0 +1,97 @@ +package org.jetbrains.dokka.utilities + +import java.io.File +import java.net.URISyntaxException +import java.net.URL +import java.util.* +import java.util.jar.JarFile +import java.util.zip.ZipEntry + +data class ServiceDescriptor(val name: String, val category: String, val description: String?, val className: String) + +class ServiceLookupException(message: String) : Exception(message) + +object ServiceLocator { + fun lookup(clazz: Class, category: String, implementationName: String): T { + val descriptor = lookupDescriptor(category, implementationName) + return lookup(clazz, descriptor) + } + + fun lookup( + clazz: Class, + descriptor: ServiceDescriptor + ): T { + val loadedClass = javaClass.classLoader.loadClass(descriptor.className) + val constructor = loadedClass.constructors.firstOrNull { it.parameterTypes.isEmpty() } ?: throw ServiceLookupException("Class ${descriptor.className} has no corresponding constructor") + + val implementationRawType: Any = + if (constructor.parameterTypes.isEmpty()) constructor.newInstance() else constructor.newInstance(constructor) + + if (!clazz.isInstance(implementationRawType)) { + throw ServiceLookupException("Class ${descriptor.className} is not a subtype of ${clazz.name}") + } + + @Suppress("UNCHECKED_CAST") + return implementationRawType as T + } + + private fun lookupDescriptor(category: String, implementationName: String): ServiceDescriptor { + val properties = javaClass.classLoader.getResourceAsStream("dokka/$category/$implementationName.properties")?.use { stream -> + Properties().let { properties -> + properties.load(stream) + properties + } + } ?: throw ServiceLookupException("No implementation with name $implementationName found in category $category") + + val className = properties["class"]?.toString() ?: throw ServiceLookupException("Implementation $implementationName has no class configured") + + return ServiceDescriptor(implementationName, category, properties["description"]?.toString(), className) + } + + fun URL.toFile(): File { + assert(protocol == "file") + + return try { + File(toURI()) + } catch (e: URISyntaxException) { //Try to handle broken URLs, with unescaped spaces + File(path) + } + } + + fun allServices(category: String): List { + val entries = this.javaClass.classLoader.getResources("dokka/$category")?.toList() ?: emptyList() + + return entries.flatMap { + when (it.protocol) { + "file" -> it.toFile().listFiles()?.filter { it.extension == "properties" }?.map { lookupDescriptor(category, it.nameWithoutExtension) } ?: emptyList() + "jar" -> { + val file = JarFile(URL(it.file.substringBefore("!")).toFile()) + try { + val jarPath = it.file.substringAfterLast("!").removePrefix("/").removeSuffix("/") + file.entries() + .asSequence() + .filter { entry -> !entry.isDirectory && entry.path == jarPath && entry.extension == "properties" } + .map { entry -> + lookupDescriptor(category, entry.fileName.substringBeforeLast(".")) + }.toList() + } finally { + file.close() + } + } + else -> emptyList() + } + } + } +} + +inline fun ServiceLocator.lookup(category: String, implementationName: String): T = lookup(T::class.java, category, implementationName) +inline fun ServiceLocator.lookup(desc: ServiceDescriptor): T = lookup(T::class.java, desc) + +private val ZipEntry.fileName: String + get() = name.substringAfterLast("/", name) + +private val ZipEntry.path: String + get() = name.substringBeforeLast("/", "").removePrefix("/") + +private val ZipEntry.extension: String? + get() = fileName.let { fn -> if ("." in fn) fn.substringAfterLast(".") else null } diff --git a/core/src/main/kotlin/utilities/Uri.kt b/core/src/main/kotlin/utilities/Uri.kt new file mode 100644 index 00000000..089b3cff --- /dev/null +++ b/core/src/main/kotlin/utilities/Uri.kt @@ -0,0 +1,40 @@ +package org.jetbrains.dokka.utilities + +import java.net.URI + + +fun URI.relativeTo(uri: URI): URI { + // Normalize paths to remove . and .. segments + val base = uri.normalize() + val child = this.normalize() + + fun StringBuilder.appendRelativePath() { + // Split paths into segments + var bParts = base.path.split('/').dropLastWhile { it.isEmpty() } + val cParts = child.path.split('/').dropLastWhile { it.isEmpty() } + + // Discard trailing segment of base path + if (bParts.isNotEmpty() && !base.path.endsWith("/")) { + bParts = bParts.dropLast(1) + } + + // Compute common prefix + val commonPartsSize = bParts.zip(cParts).takeWhile { (basePart, childPart) -> basePart == childPart }.count() + bParts.drop(commonPartsSize).joinTo(this, separator = "") { "../" } + cParts.drop(commonPartsSize).joinTo(this, separator = "/") + } + + return URI.create(buildString { + if (base.path != child.path) { + appendRelativePath() + } + child.rawQuery?.let { + append("?") + append(it) + } + child.rawFragment?.let { + append("#") + append(it) + } + }) +} \ No newline at end of file diff --git a/core/src/main/kotlin/utilities/nodeDebug.kt b/core/src/main/kotlin/utilities/nodeDebug.kt new file mode 100644 index 00000000..3290202e --- /dev/null +++ b/core/src/main/kotlin/utilities/nodeDebug.kt @@ -0,0 +1,50 @@ +package org.jetbrains.dokka.utilities + +import org.jetbrains.dokka.model.DocumentationNode +import org.jetbrains.dokka.pages.* + +const val DOWN = '\u2503' +const val BRANCH = '\u2523' +const val LAST = '\u2517' + +fun DocumentationNode.pretty(prefix: String = "", isLast: Boolean = true): String { + val nextPrefix = prefix + (if (isLast) ' ' else DOWN) + ' ' + + return prefix + (if (isLast) LAST else BRANCH) + this.toString() + + children.dropLast(1) + .map { it.pretty(nextPrefix, false) } + .plus(children.lastOrNull()?.pretty(nextPrefix)) + .filterNotNull() + .takeIf { it.isNotEmpty() } + ?.joinToString(prefix = "\n", separator = "") + .orEmpty() + if (children.isEmpty()) "\n" else "" +} + +//fun Any.genericPretty(prefix: String = "", isLast: Boolean = true): String { +// val nextPrefix = prefix + (if (isLast) ' ' else DOWN) + ' ' +// +// return prefix + (if (isLast) LAST else BRANCH) + this.stringify() + +// allChildren().dropLast(1) +// .map { it.genericPretty(nextPrefix, false) } +// .plus(allChildren().lastOrNull()?.genericPretty(nextPrefix)) +// .filterNotNull() +// .takeIf { it.isNotEmpty() } +// ?.joinToString(prefix = "\n", separator = "") +// .orEmpty() + if (allChildren().isEmpty()) "\n" else "" +//} +private fun Any.stringify() = when(this) { + is ContentNode -> toString() + this.dci + is PageNode -> this.name + this::class.simpleName + else -> toString() +} +//private fun Any.allChildren() = when(this){ +// is PageNode -> children + content +// is ContentBlock -> this.children +// is ContentHeader -> this.items +// is ContentStyle -> this.items +// is ContentSymbol -> this.parts +// is ContentComment -> this.parts +// is ContentGroup -> this.children +// is ContentList -> this.items +// else -> emptyList() +//} -- cgit