diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/getModuleInfo.kt.191 b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/getModuleInfo.kt.191 new file mode 100644 index 00000000000..6180f5e1fd5 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/getModuleInfo.kt.191 @@ -0,0 +1,337 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.caches.project + +import com.intellij.ide.scratch.ScratchFileService +import com.intellij.openapi.module.ModuleManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.* +import com.intellij.openapi.util.Key +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.analyzer.ModuleInfo +import org.jetbrains.kotlin.asJava.classes.FakeLightClassForFileOfPackage +import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade +import org.jetbrains.kotlin.asJava.elements.KtLightElement +import org.jetbrains.kotlin.caches.project.cacheInvalidatingOnRootModifications +import org.jetbrains.kotlin.idea.caches.lightClasses.KtLightClassForDecompiledDeclaration +import org.jetbrains.kotlin.idea.core.isInTestSourceContentKotlinAware +import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager +import org.jetbrains.kotlin.idea.core.script.scriptRelatedModuleName +import org.jetbrains.kotlin.idea.highlighter.OutsidersPsiFileSupportUtils +import org.jetbrains.kotlin.idea.util.ProjectRootsUtil +import org.jetbrains.kotlin.idea.util.isInSourceContentWithoutInjected +import org.jetbrains.kotlin.idea.util.isKotlinBinary +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getParentOfType +import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition +import org.jetbrains.kotlin.scripting.definitions.runReadAction +import org.jetbrains.kotlin.utils.addIfNotNull +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull +import org.jetbrains.kotlin.utils.sure +import org.jetbrains.kotlin.utils.yieldIfNotNull + +var PsiFile.forcedModuleInfo: ModuleInfo? by UserDataProperty(Key.create("FORCED_MODULE_INFO")) + +fun PsiElement.getModuleInfo(): IdeaModuleInfo = this.collectInfos(ModuleInfoCollector.NotNullTakeFirst) + +fun PsiElement.getNullableModuleInfo(): IdeaModuleInfo? = this.collectInfos(ModuleInfoCollector.NullableTakeFirst) + +fun PsiElement.getModuleInfos(): Sequence = this.collectInfos(ModuleInfoCollector.ToSequence) + +private fun ModuleInfo.doFindSdk(): SdkInfo? = dependencies().lazyClosure { it.dependencies() }.firstIsInstanceOrNull() + +fun ModuleInfo.findSdkAcrossDependencies(): SdkInfo? { + return when (this) { + // It is important to check for cases of test/production explicitly, because we're using lambda's class + // of 'cacheInvalidatingOnRootModifications' as key for cache, and it should be different for Production/Source + is ModuleProductionSourceInfo -> module.cacheInvalidatingOnRootModifications { doFindSdk() } + is ModuleTestSourceInfo -> module.cacheInvalidatingOnRootModifications { doFindSdk() } + else -> doFindSdk() + } +} + +fun getModuleInfoByVirtualFile(project: Project, virtualFile: VirtualFile): IdeaModuleInfo? = + collectInfosByVirtualFile( + project, virtualFile, + treatAsLibrarySource = false, + onOccurrence = { return@getModuleInfoByVirtualFile it } + ) + +fun getBinaryLibrariesModuleInfos(project: Project, virtualFile: VirtualFile) = + collectModuleInfosByType( + project, + virtualFile + ) + +fun getLibrarySourcesModuleInfos(project: Project, virtualFile: VirtualFile) = + collectModuleInfosByType( + project, + virtualFile + ) + +fun getScriptRelatedModuleInfo(project: Project, virtualFile: VirtualFile): ModuleSourceInfo? { + val moduleRelatedModuleInfo = getModuleRelatedModuleInfo(project, virtualFile) + if (moduleRelatedModuleInfo != null) { + return moduleRelatedModuleInfo + } + + if (ScratchFileService.isInScratchRoot(virtualFile)) { + val scratchModule = virtualFile.scriptRelatedModuleName?.let { ModuleManager.getInstance(project).findModuleByName(it) } + return scratchModule?.testSourceInfo() ?: scratchModule?.productionSourceInfo() + } + + return null +} + +private typealias VirtualFileProcessor = (Project, VirtualFile, Boolean) -> T + +private sealed class ModuleInfoCollector( + val onResult: (IdeaModuleInfo?) -> T, + val onFailure: (String) -> T, + val virtualFileProcessor: VirtualFileProcessor +) { + object NotNullTakeFirst : ModuleInfoCollector( + onResult = { it ?: NotUnderContentRootModuleInfo }, + onFailure = { reason -> + LOG.error("Could not find correct module information.\nReason: $reason") + NotUnderContentRootModuleInfo + }, + virtualFileProcessor = processor@{ project, virtualFile, isLibrarySource -> + collectInfosByVirtualFile( + project, + virtualFile, + isLibrarySource + ) { + return@processor it ?: NotUnderContentRootModuleInfo + } + } + ) + + object NullableTakeFirst : ModuleInfoCollector( + onResult = { it }, + onFailure = { reason -> + LOG.warn("Could not find correct module information.\nReason: $reason") + null + }, + virtualFileProcessor = processor@{ project, virtualFile, isLibrarySource -> + collectInfosByVirtualFile( + project, + virtualFile, + isLibrarySource + ) { return@processor it } + } + ) + + object ToSequence : ModuleInfoCollector>( + onResult = { result -> result?.let { sequenceOf(it) } ?: emptySequence() }, + onFailure = { reason -> + LOG.warn("Could not find correct module information.\nReason: $reason") + emptySequence() + }, + virtualFileProcessor = { project, virtualFile, isLibrarySource -> + sequence { + collectInfosByVirtualFile( + project, + virtualFile, + isLibrarySource + ) { yieldIfNotNull(it) } + } + } + ) +} + +private fun PsiElement.collectInfos(c: ModuleInfoCollector): T { + (containingFile?.forcedModuleInfo as? IdeaModuleInfo)?.let { + return c.onResult(it) + } + + if (this is KtLightElement<*, *>) { + return this.processLightElement(c) + } + + collectModuleInfoByUserData(this).firstOrNull()?.let { + return c.onResult(it) + } + + val containingFile = + containingFile ?: return c.onFailure("Analyzing element of type ${this::class.java} with no containing file\nText:\n$text") + + val containingKtFile = (this as? KtElement)?.containingFile as? KtFile + containingKtFile?.analysisContext?.let { + return it.collectInfos(c) + } + + containingKtFile?.doNotAnalyze?.let { + return c.onFailure("Should not analyze element: $text in file ${containingKtFile.name}\n$it") + } + + val explicitModuleInfo = containingKtFile?.forcedModuleInfo ?: (containingKtFile?.originalFile as? KtFile)?.forcedModuleInfo + if (explicitModuleInfo is IdeaModuleInfo) { + return c.onResult(explicitModuleInfo) + } + + if (containingKtFile is KtCodeFragment) { + val context = containingKtFile.getContext() + ?: return c.onFailure("Analyzing code fragment of type ${containingKtFile::class.java} with no context element\nText:\n${containingKtFile.getText()}") + return context.collectInfos(c) + } + + val virtualFile = containingFile.originalFile.virtualFile + ?: return c.onFailure("Analyzing element of type ${this::class.java} in non-physical file $containingFile of type ${containingFile::class.java}\nText:\n$text") + + val isScript = runReadAction { containingKtFile?.isScript() == true } + if (isScript) { + getModuleRelatedModuleInfo(project, virtualFile)?.let { + return c.onResult(it) + } + val script = runReadAction { containingKtFile?.script } + script?.let { + containingKtFile?.findScriptDefinition()?.let { + return c.onResult(ScriptModuleInfo(project, virtualFile, it)) + } + } + } + + return c.virtualFileProcessor( + project, + virtualFile, + (containingFile as? KtFile)?.isCompiled ?: false + ) +} + +private fun KtLightElement<*, *>.processLightElement(c: ModuleInfoCollector): T { + val decompiledClass = this.getParentOfType(strict = false) + if (decompiledClass != null) { + return c.virtualFileProcessor( + project, + containingFile.virtualFile.sure { "Decompiled class should be build from physical file" }, + false + ) + } + + val element = kotlinOrigin ?: when (this) { + is FakeLightClassForFileOfPackage -> this.getContainingFile()!! + is KtLightClassForFacade -> this.files.first() + else -> return c.onFailure("Light element without origin is referenced by resolve:\n$this\n${this.clsDelegate.text}") + } + + return element.collectInfos(c) +} + +private inline fun collectInfosByVirtualFile( + project: Project, + virtualFile: VirtualFile, + treatAsLibrarySource: Boolean, + onOccurrence: (IdeaModuleInfo?) -> T +): T { + collectModuleInfoByUserData(project, virtualFile).map(onOccurrence) + + val moduleRelatedModuleInfo = getModuleRelatedModuleInfo(project, virtualFile) + if (moduleRelatedModuleInfo != null) { + onOccurrence(moduleRelatedModuleInfo) + } + + val projectFileIndex = ProjectFileIndex.SERVICE.getInstance(project) + projectFileIndex.getOrderEntriesForFile(virtualFile).forEach { + it.toIdeaModuleInfo(project, virtualFile, treatAsLibrarySource).map(onOccurrence) + } + + val isBinary = virtualFile.fileType.isKotlinBinary() + val scriptConfigurationManager = ScriptConfigurationManager.getInstance(project) + if (isBinary && virtualFile in scriptConfigurationManager.getAllScriptsDependenciesClassFilesScope()) { + if (treatAsLibrarySource) { + onOccurrence(ScriptDependenciesSourceInfo.ForProject(project)) + } else { + onOccurrence(ScriptDependenciesInfo.ForProject(project)) + } + } + if (!isBinary && virtualFile in scriptConfigurationManager.getAllScriptDependenciesSourcesScope()) { + onOccurrence(ScriptDependenciesSourceInfo.ForProject(project)) + } + + return onOccurrence(null) +} + +private fun getModuleRelatedModuleInfo(project: Project, virtualFile: VirtualFile): ModuleSourceInfo? { + val projectFileIndex = ProjectFileIndex.SERVICE.getInstance(project) + + val module = projectFileIndex.getModuleForFile(virtualFile) + if (module != null && !module.isDisposed) { + val moduleFileIndex = ModuleRootManager.getInstance(module).fileIndex + if (moduleFileIndex.isInTestSourceContentKotlinAware(virtualFile)) { + return module.testSourceInfo() + } else if (moduleFileIndex.isInSourceContentWithoutInjected(virtualFile)) { + return module.productionSourceInfo() + } + } + + val fileOrigin = OutsidersPsiFileSupportUtils.getOutsiderFileOrigin(project, virtualFile) + if (fileOrigin != null) { + return getModuleRelatedModuleInfo(project, fileOrigin) + } + + return null +} + +private inline fun collectModuleInfosByType(project: Project, virtualFile: VirtualFile): Collection { + val result = linkedSetOf() + collectInfosByVirtualFile(project, virtualFile, treatAsLibrarySource = false) { + result.addIfNotNull(it as? T) + } + + return result +} + +private fun OrderEntry.toIdeaModuleInfo( + project: Project, + virtualFile: VirtualFile, + treatAsLibrarySource: Boolean = false +): List { + if (this is ModuleOrderEntry) return emptyList() + if (!isValid) return emptyList() + + when (this) { + is LibraryOrderEntry -> { + val library = library ?: return emptyList() + if (ProjectRootsUtil.isLibraryClassFile(project, virtualFile) && !treatAsLibrarySource) { + return createLibraryInfo(project, library) + } else if (ProjectRootsUtil.isLibraryFile(project, virtualFile) || treatAsLibrarySource) { + return createLibraryInfo(project, library).map { it.sourcesModuleInfo } + } + } + is JdkOrderEntry -> { + return listOf(SdkInfo(project, jdk ?: return emptyList())) + } + else -> return emptyList() + } + return emptyList() +} + +/** + * @see [org.jetbrains.kotlin.types.typeUtil.closure]. + */ +fun Collection.lazyClosure(f: (T) -> Collection): Sequence = sequence { + if (size == 0) return@sequence + var sizeBeforeIteration = 0 + + yieldAll(this@lazyClosure) + var yieldedCount = size + var elementsToCheck = this@lazyClosure + + while (yieldedCount > sizeBeforeIteration) { + val toAdd = hashSetOf() + elementsToCheck.forEach { + val neighbours = f(it) + yieldAll(neighbours) + yieldedCount += neighbours.size + toAdd.addAll(neighbours) + } + elementsToCheck = toAdd + sizeBeforeIteration = yieldedCount + } +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/getModuleInfo.kt.192 b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/getModuleInfo.kt.192 new file mode 100644 index 00000000000..6180f5e1fd5 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/getModuleInfo.kt.192 @@ -0,0 +1,337 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.caches.project + +import com.intellij.ide.scratch.ScratchFileService +import com.intellij.openapi.module.ModuleManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.* +import com.intellij.openapi.util.Key +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.analyzer.ModuleInfo +import org.jetbrains.kotlin.asJava.classes.FakeLightClassForFileOfPackage +import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade +import org.jetbrains.kotlin.asJava.elements.KtLightElement +import org.jetbrains.kotlin.caches.project.cacheInvalidatingOnRootModifications +import org.jetbrains.kotlin.idea.caches.lightClasses.KtLightClassForDecompiledDeclaration +import org.jetbrains.kotlin.idea.core.isInTestSourceContentKotlinAware +import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager +import org.jetbrains.kotlin.idea.core.script.scriptRelatedModuleName +import org.jetbrains.kotlin.idea.highlighter.OutsidersPsiFileSupportUtils +import org.jetbrains.kotlin.idea.util.ProjectRootsUtil +import org.jetbrains.kotlin.idea.util.isInSourceContentWithoutInjected +import org.jetbrains.kotlin.idea.util.isKotlinBinary +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getParentOfType +import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition +import org.jetbrains.kotlin.scripting.definitions.runReadAction +import org.jetbrains.kotlin.utils.addIfNotNull +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull +import org.jetbrains.kotlin.utils.sure +import org.jetbrains.kotlin.utils.yieldIfNotNull + +var PsiFile.forcedModuleInfo: ModuleInfo? by UserDataProperty(Key.create("FORCED_MODULE_INFO")) + +fun PsiElement.getModuleInfo(): IdeaModuleInfo = this.collectInfos(ModuleInfoCollector.NotNullTakeFirst) + +fun PsiElement.getNullableModuleInfo(): IdeaModuleInfo? = this.collectInfos(ModuleInfoCollector.NullableTakeFirst) + +fun PsiElement.getModuleInfos(): Sequence = this.collectInfos(ModuleInfoCollector.ToSequence) + +private fun ModuleInfo.doFindSdk(): SdkInfo? = dependencies().lazyClosure { it.dependencies() }.firstIsInstanceOrNull() + +fun ModuleInfo.findSdkAcrossDependencies(): SdkInfo? { + return when (this) { + // It is important to check for cases of test/production explicitly, because we're using lambda's class + // of 'cacheInvalidatingOnRootModifications' as key for cache, and it should be different for Production/Source + is ModuleProductionSourceInfo -> module.cacheInvalidatingOnRootModifications { doFindSdk() } + is ModuleTestSourceInfo -> module.cacheInvalidatingOnRootModifications { doFindSdk() } + else -> doFindSdk() + } +} + +fun getModuleInfoByVirtualFile(project: Project, virtualFile: VirtualFile): IdeaModuleInfo? = + collectInfosByVirtualFile( + project, virtualFile, + treatAsLibrarySource = false, + onOccurrence = { return@getModuleInfoByVirtualFile it } + ) + +fun getBinaryLibrariesModuleInfos(project: Project, virtualFile: VirtualFile) = + collectModuleInfosByType( + project, + virtualFile + ) + +fun getLibrarySourcesModuleInfos(project: Project, virtualFile: VirtualFile) = + collectModuleInfosByType( + project, + virtualFile + ) + +fun getScriptRelatedModuleInfo(project: Project, virtualFile: VirtualFile): ModuleSourceInfo? { + val moduleRelatedModuleInfo = getModuleRelatedModuleInfo(project, virtualFile) + if (moduleRelatedModuleInfo != null) { + return moduleRelatedModuleInfo + } + + if (ScratchFileService.isInScratchRoot(virtualFile)) { + val scratchModule = virtualFile.scriptRelatedModuleName?.let { ModuleManager.getInstance(project).findModuleByName(it) } + return scratchModule?.testSourceInfo() ?: scratchModule?.productionSourceInfo() + } + + return null +} + +private typealias VirtualFileProcessor = (Project, VirtualFile, Boolean) -> T + +private sealed class ModuleInfoCollector( + val onResult: (IdeaModuleInfo?) -> T, + val onFailure: (String) -> T, + val virtualFileProcessor: VirtualFileProcessor +) { + object NotNullTakeFirst : ModuleInfoCollector( + onResult = { it ?: NotUnderContentRootModuleInfo }, + onFailure = { reason -> + LOG.error("Could not find correct module information.\nReason: $reason") + NotUnderContentRootModuleInfo + }, + virtualFileProcessor = processor@{ project, virtualFile, isLibrarySource -> + collectInfosByVirtualFile( + project, + virtualFile, + isLibrarySource + ) { + return@processor it ?: NotUnderContentRootModuleInfo + } + } + ) + + object NullableTakeFirst : ModuleInfoCollector( + onResult = { it }, + onFailure = { reason -> + LOG.warn("Could not find correct module information.\nReason: $reason") + null + }, + virtualFileProcessor = processor@{ project, virtualFile, isLibrarySource -> + collectInfosByVirtualFile( + project, + virtualFile, + isLibrarySource + ) { return@processor it } + } + ) + + object ToSequence : ModuleInfoCollector>( + onResult = { result -> result?.let { sequenceOf(it) } ?: emptySequence() }, + onFailure = { reason -> + LOG.warn("Could not find correct module information.\nReason: $reason") + emptySequence() + }, + virtualFileProcessor = { project, virtualFile, isLibrarySource -> + sequence { + collectInfosByVirtualFile( + project, + virtualFile, + isLibrarySource + ) { yieldIfNotNull(it) } + } + } + ) +} + +private fun PsiElement.collectInfos(c: ModuleInfoCollector): T { + (containingFile?.forcedModuleInfo as? IdeaModuleInfo)?.let { + return c.onResult(it) + } + + if (this is KtLightElement<*, *>) { + return this.processLightElement(c) + } + + collectModuleInfoByUserData(this).firstOrNull()?.let { + return c.onResult(it) + } + + val containingFile = + containingFile ?: return c.onFailure("Analyzing element of type ${this::class.java} with no containing file\nText:\n$text") + + val containingKtFile = (this as? KtElement)?.containingFile as? KtFile + containingKtFile?.analysisContext?.let { + return it.collectInfos(c) + } + + containingKtFile?.doNotAnalyze?.let { + return c.onFailure("Should not analyze element: $text in file ${containingKtFile.name}\n$it") + } + + val explicitModuleInfo = containingKtFile?.forcedModuleInfo ?: (containingKtFile?.originalFile as? KtFile)?.forcedModuleInfo + if (explicitModuleInfo is IdeaModuleInfo) { + return c.onResult(explicitModuleInfo) + } + + if (containingKtFile is KtCodeFragment) { + val context = containingKtFile.getContext() + ?: return c.onFailure("Analyzing code fragment of type ${containingKtFile::class.java} with no context element\nText:\n${containingKtFile.getText()}") + return context.collectInfos(c) + } + + val virtualFile = containingFile.originalFile.virtualFile + ?: return c.onFailure("Analyzing element of type ${this::class.java} in non-physical file $containingFile of type ${containingFile::class.java}\nText:\n$text") + + val isScript = runReadAction { containingKtFile?.isScript() == true } + if (isScript) { + getModuleRelatedModuleInfo(project, virtualFile)?.let { + return c.onResult(it) + } + val script = runReadAction { containingKtFile?.script } + script?.let { + containingKtFile?.findScriptDefinition()?.let { + return c.onResult(ScriptModuleInfo(project, virtualFile, it)) + } + } + } + + return c.virtualFileProcessor( + project, + virtualFile, + (containingFile as? KtFile)?.isCompiled ?: false + ) +} + +private fun KtLightElement<*, *>.processLightElement(c: ModuleInfoCollector): T { + val decompiledClass = this.getParentOfType(strict = false) + if (decompiledClass != null) { + return c.virtualFileProcessor( + project, + containingFile.virtualFile.sure { "Decompiled class should be build from physical file" }, + false + ) + } + + val element = kotlinOrigin ?: when (this) { + is FakeLightClassForFileOfPackage -> this.getContainingFile()!! + is KtLightClassForFacade -> this.files.first() + else -> return c.onFailure("Light element without origin is referenced by resolve:\n$this\n${this.clsDelegate.text}") + } + + return element.collectInfos(c) +} + +private inline fun collectInfosByVirtualFile( + project: Project, + virtualFile: VirtualFile, + treatAsLibrarySource: Boolean, + onOccurrence: (IdeaModuleInfo?) -> T +): T { + collectModuleInfoByUserData(project, virtualFile).map(onOccurrence) + + val moduleRelatedModuleInfo = getModuleRelatedModuleInfo(project, virtualFile) + if (moduleRelatedModuleInfo != null) { + onOccurrence(moduleRelatedModuleInfo) + } + + val projectFileIndex = ProjectFileIndex.SERVICE.getInstance(project) + projectFileIndex.getOrderEntriesForFile(virtualFile).forEach { + it.toIdeaModuleInfo(project, virtualFile, treatAsLibrarySource).map(onOccurrence) + } + + val isBinary = virtualFile.fileType.isKotlinBinary() + val scriptConfigurationManager = ScriptConfigurationManager.getInstance(project) + if (isBinary && virtualFile in scriptConfigurationManager.getAllScriptsDependenciesClassFilesScope()) { + if (treatAsLibrarySource) { + onOccurrence(ScriptDependenciesSourceInfo.ForProject(project)) + } else { + onOccurrence(ScriptDependenciesInfo.ForProject(project)) + } + } + if (!isBinary && virtualFile in scriptConfigurationManager.getAllScriptDependenciesSourcesScope()) { + onOccurrence(ScriptDependenciesSourceInfo.ForProject(project)) + } + + return onOccurrence(null) +} + +private fun getModuleRelatedModuleInfo(project: Project, virtualFile: VirtualFile): ModuleSourceInfo? { + val projectFileIndex = ProjectFileIndex.SERVICE.getInstance(project) + + val module = projectFileIndex.getModuleForFile(virtualFile) + if (module != null && !module.isDisposed) { + val moduleFileIndex = ModuleRootManager.getInstance(module).fileIndex + if (moduleFileIndex.isInTestSourceContentKotlinAware(virtualFile)) { + return module.testSourceInfo() + } else if (moduleFileIndex.isInSourceContentWithoutInjected(virtualFile)) { + return module.productionSourceInfo() + } + } + + val fileOrigin = OutsidersPsiFileSupportUtils.getOutsiderFileOrigin(project, virtualFile) + if (fileOrigin != null) { + return getModuleRelatedModuleInfo(project, fileOrigin) + } + + return null +} + +private inline fun collectModuleInfosByType(project: Project, virtualFile: VirtualFile): Collection { + val result = linkedSetOf() + collectInfosByVirtualFile(project, virtualFile, treatAsLibrarySource = false) { + result.addIfNotNull(it as? T) + } + + return result +} + +private fun OrderEntry.toIdeaModuleInfo( + project: Project, + virtualFile: VirtualFile, + treatAsLibrarySource: Boolean = false +): List { + if (this is ModuleOrderEntry) return emptyList() + if (!isValid) return emptyList() + + when (this) { + is LibraryOrderEntry -> { + val library = library ?: return emptyList() + if (ProjectRootsUtil.isLibraryClassFile(project, virtualFile) && !treatAsLibrarySource) { + return createLibraryInfo(project, library) + } else if (ProjectRootsUtil.isLibraryFile(project, virtualFile) || treatAsLibrarySource) { + return createLibraryInfo(project, library).map { it.sourcesModuleInfo } + } + } + is JdkOrderEntry -> { + return listOf(SdkInfo(project, jdk ?: return emptyList())) + } + else -> return emptyList() + } + return emptyList() +} + +/** + * @see [org.jetbrains.kotlin.types.typeUtil.closure]. + */ +fun Collection.lazyClosure(f: (T) -> Collection): Sequence = sequence { + if (size == 0) return@sequence + var sizeBeforeIteration = 0 + + yieldAll(this@lazyClosure) + var yieldedCount = size + var elementsToCheck = this@lazyClosure + + while (yieldedCount > sizeBeforeIteration) { + val toAdd = hashSetOf() + elementsToCheck.forEach { + val neighbours = f(it) + yieldAll(neighbours) + yieldedCount += neighbours.size + toAdd.addAll(neighbours) + } + elementsToCheck = toAdd + sizeBeforeIteration = yieldedCount + } +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/getModuleInfo.kt.as40 b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/getModuleInfo.kt.as40 new file mode 100644 index 00000000000..6180f5e1fd5 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/getModuleInfo.kt.as40 @@ -0,0 +1,337 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.caches.project + +import com.intellij.ide.scratch.ScratchFileService +import com.intellij.openapi.module.ModuleManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.* +import com.intellij.openapi.util.Key +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.analyzer.ModuleInfo +import org.jetbrains.kotlin.asJava.classes.FakeLightClassForFileOfPackage +import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade +import org.jetbrains.kotlin.asJava.elements.KtLightElement +import org.jetbrains.kotlin.caches.project.cacheInvalidatingOnRootModifications +import org.jetbrains.kotlin.idea.caches.lightClasses.KtLightClassForDecompiledDeclaration +import org.jetbrains.kotlin.idea.core.isInTestSourceContentKotlinAware +import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager +import org.jetbrains.kotlin.idea.core.script.scriptRelatedModuleName +import org.jetbrains.kotlin.idea.highlighter.OutsidersPsiFileSupportUtils +import org.jetbrains.kotlin.idea.util.ProjectRootsUtil +import org.jetbrains.kotlin.idea.util.isInSourceContentWithoutInjected +import org.jetbrains.kotlin.idea.util.isKotlinBinary +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getParentOfType +import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition +import org.jetbrains.kotlin.scripting.definitions.runReadAction +import org.jetbrains.kotlin.utils.addIfNotNull +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull +import org.jetbrains.kotlin.utils.sure +import org.jetbrains.kotlin.utils.yieldIfNotNull + +var PsiFile.forcedModuleInfo: ModuleInfo? by UserDataProperty(Key.create("FORCED_MODULE_INFO")) + +fun PsiElement.getModuleInfo(): IdeaModuleInfo = this.collectInfos(ModuleInfoCollector.NotNullTakeFirst) + +fun PsiElement.getNullableModuleInfo(): IdeaModuleInfo? = this.collectInfos(ModuleInfoCollector.NullableTakeFirst) + +fun PsiElement.getModuleInfos(): Sequence = this.collectInfos(ModuleInfoCollector.ToSequence) + +private fun ModuleInfo.doFindSdk(): SdkInfo? = dependencies().lazyClosure { it.dependencies() }.firstIsInstanceOrNull() + +fun ModuleInfo.findSdkAcrossDependencies(): SdkInfo? { + return when (this) { + // It is important to check for cases of test/production explicitly, because we're using lambda's class + // of 'cacheInvalidatingOnRootModifications' as key for cache, and it should be different for Production/Source + is ModuleProductionSourceInfo -> module.cacheInvalidatingOnRootModifications { doFindSdk() } + is ModuleTestSourceInfo -> module.cacheInvalidatingOnRootModifications { doFindSdk() } + else -> doFindSdk() + } +} + +fun getModuleInfoByVirtualFile(project: Project, virtualFile: VirtualFile): IdeaModuleInfo? = + collectInfosByVirtualFile( + project, virtualFile, + treatAsLibrarySource = false, + onOccurrence = { return@getModuleInfoByVirtualFile it } + ) + +fun getBinaryLibrariesModuleInfos(project: Project, virtualFile: VirtualFile) = + collectModuleInfosByType( + project, + virtualFile + ) + +fun getLibrarySourcesModuleInfos(project: Project, virtualFile: VirtualFile) = + collectModuleInfosByType( + project, + virtualFile + ) + +fun getScriptRelatedModuleInfo(project: Project, virtualFile: VirtualFile): ModuleSourceInfo? { + val moduleRelatedModuleInfo = getModuleRelatedModuleInfo(project, virtualFile) + if (moduleRelatedModuleInfo != null) { + return moduleRelatedModuleInfo + } + + if (ScratchFileService.isInScratchRoot(virtualFile)) { + val scratchModule = virtualFile.scriptRelatedModuleName?.let { ModuleManager.getInstance(project).findModuleByName(it) } + return scratchModule?.testSourceInfo() ?: scratchModule?.productionSourceInfo() + } + + return null +} + +private typealias VirtualFileProcessor = (Project, VirtualFile, Boolean) -> T + +private sealed class ModuleInfoCollector( + val onResult: (IdeaModuleInfo?) -> T, + val onFailure: (String) -> T, + val virtualFileProcessor: VirtualFileProcessor +) { + object NotNullTakeFirst : ModuleInfoCollector( + onResult = { it ?: NotUnderContentRootModuleInfo }, + onFailure = { reason -> + LOG.error("Could not find correct module information.\nReason: $reason") + NotUnderContentRootModuleInfo + }, + virtualFileProcessor = processor@{ project, virtualFile, isLibrarySource -> + collectInfosByVirtualFile( + project, + virtualFile, + isLibrarySource + ) { + return@processor it ?: NotUnderContentRootModuleInfo + } + } + ) + + object NullableTakeFirst : ModuleInfoCollector( + onResult = { it }, + onFailure = { reason -> + LOG.warn("Could not find correct module information.\nReason: $reason") + null + }, + virtualFileProcessor = processor@{ project, virtualFile, isLibrarySource -> + collectInfosByVirtualFile( + project, + virtualFile, + isLibrarySource + ) { return@processor it } + } + ) + + object ToSequence : ModuleInfoCollector>( + onResult = { result -> result?.let { sequenceOf(it) } ?: emptySequence() }, + onFailure = { reason -> + LOG.warn("Could not find correct module information.\nReason: $reason") + emptySequence() + }, + virtualFileProcessor = { project, virtualFile, isLibrarySource -> + sequence { + collectInfosByVirtualFile( + project, + virtualFile, + isLibrarySource + ) { yieldIfNotNull(it) } + } + } + ) +} + +private fun PsiElement.collectInfos(c: ModuleInfoCollector): T { + (containingFile?.forcedModuleInfo as? IdeaModuleInfo)?.let { + return c.onResult(it) + } + + if (this is KtLightElement<*, *>) { + return this.processLightElement(c) + } + + collectModuleInfoByUserData(this).firstOrNull()?.let { + return c.onResult(it) + } + + val containingFile = + containingFile ?: return c.onFailure("Analyzing element of type ${this::class.java} with no containing file\nText:\n$text") + + val containingKtFile = (this as? KtElement)?.containingFile as? KtFile + containingKtFile?.analysisContext?.let { + return it.collectInfos(c) + } + + containingKtFile?.doNotAnalyze?.let { + return c.onFailure("Should not analyze element: $text in file ${containingKtFile.name}\n$it") + } + + val explicitModuleInfo = containingKtFile?.forcedModuleInfo ?: (containingKtFile?.originalFile as? KtFile)?.forcedModuleInfo + if (explicitModuleInfo is IdeaModuleInfo) { + return c.onResult(explicitModuleInfo) + } + + if (containingKtFile is KtCodeFragment) { + val context = containingKtFile.getContext() + ?: return c.onFailure("Analyzing code fragment of type ${containingKtFile::class.java} with no context element\nText:\n${containingKtFile.getText()}") + return context.collectInfos(c) + } + + val virtualFile = containingFile.originalFile.virtualFile + ?: return c.onFailure("Analyzing element of type ${this::class.java} in non-physical file $containingFile of type ${containingFile::class.java}\nText:\n$text") + + val isScript = runReadAction { containingKtFile?.isScript() == true } + if (isScript) { + getModuleRelatedModuleInfo(project, virtualFile)?.let { + return c.onResult(it) + } + val script = runReadAction { containingKtFile?.script } + script?.let { + containingKtFile?.findScriptDefinition()?.let { + return c.onResult(ScriptModuleInfo(project, virtualFile, it)) + } + } + } + + return c.virtualFileProcessor( + project, + virtualFile, + (containingFile as? KtFile)?.isCompiled ?: false + ) +} + +private fun KtLightElement<*, *>.processLightElement(c: ModuleInfoCollector): T { + val decompiledClass = this.getParentOfType(strict = false) + if (decompiledClass != null) { + return c.virtualFileProcessor( + project, + containingFile.virtualFile.sure { "Decompiled class should be build from physical file" }, + false + ) + } + + val element = kotlinOrigin ?: when (this) { + is FakeLightClassForFileOfPackage -> this.getContainingFile()!! + is KtLightClassForFacade -> this.files.first() + else -> return c.onFailure("Light element without origin is referenced by resolve:\n$this\n${this.clsDelegate.text}") + } + + return element.collectInfos(c) +} + +private inline fun collectInfosByVirtualFile( + project: Project, + virtualFile: VirtualFile, + treatAsLibrarySource: Boolean, + onOccurrence: (IdeaModuleInfo?) -> T +): T { + collectModuleInfoByUserData(project, virtualFile).map(onOccurrence) + + val moduleRelatedModuleInfo = getModuleRelatedModuleInfo(project, virtualFile) + if (moduleRelatedModuleInfo != null) { + onOccurrence(moduleRelatedModuleInfo) + } + + val projectFileIndex = ProjectFileIndex.SERVICE.getInstance(project) + projectFileIndex.getOrderEntriesForFile(virtualFile).forEach { + it.toIdeaModuleInfo(project, virtualFile, treatAsLibrarySource).map(onOccurrence) + } + + val isBinary = virtualFile.fileType.isKotlinBinary() + val scriptConfigurationManager = ScriptConfigurationManager.getInstance(project) + if (isBinary && virtualFile in scriptConfigurationManager.getAllScriptsDependenciesClassFilesScope()) { + if (treatAsLibrarySource) { + onOccurrence(ScriptDependenciesSourceInfo.ForProject(project)) + } else { + onOccurrence(ScriptDependenciesInfo.ForProject(project)) + } + } + if (!isBinary && virtualFile in scriptConfigurationManager.getAllScriptDependenciesSourcesScope()) { + onOccurrence(ScriptDependenciesSourceInfo.ForProject(project)) + } + + return onOccurrence(null) +} + +private fun getModuleRelatedModuleInfo(project: Project, virtualFile: VirtualFile): ModuleSourceInfo? { + val projectFileIndex = ProjectFileIndex.SERVICE.getInstance(project) + + val module = projectFileIndex.getModuleForFile(virtualFile) + if (module != null && !module.isDisposed) { + val moduleFileIndex = ModuleRootManager.getInstance(module).fileIndex + if (moduleFileIndex.isInTestSourceContentKotlinAware(virtualFile)) { + return module.testSourceInfo() + } else if (moduleFileIndex.isInSourceContentWithoutInjected(virtualFile)) { + return module.productionSourceInfo() + } + } + + val fileOrigin = OutsidersPsiFileSupportUtils.getOutsiderFileOrigin(project, virtualFile) + if (fileOrigin != null) { + return getModuleRelatedModuleInfo(project, fileOrigin) + } + + return null +} + +private inline fun collectModuleInfosByType(project: Project, virtualFile: VirtualFile): Collection { + val result = linkedSetOf() + collectInfosByVirtualFile(project, virtualFile, treatAsLibrarySource = false) { + result.addIfNotNull(it as? T) + } + + return result +} + +private fun OrderEntry.toIdeaModuleInfo( + project: Project, + virtualFile: VirtualFile, + treatAsLibrarySource: Boolean = false +): List { + if (this is ModuleOrderEntry) return emptyList() + if (!isValid) return emptyList() + + when (this) { + is LibraryOrderEntry -> { + val library = library ?: return emptyList() + if (ProjectRootsUtil.isLibraryClassFile(project, virtualFile) && !treatAsLibrarySource) { + return createLibraryInfo(project, library) + } else if (ProjectRootsUtil.isLibraryFile(project, virtualFile) || treatAsLibrarySource) { + return createLibraryInfo(project, library).map { it.sourcesModuleInfo } + } + } + is JdkOrderEntry -> { + return listOf(SdkInfo(project, jdk ?: return emptyList())) + } + else -> return emptyList() + } + return emptyList() +} + +/** + * @see [org.jetbrains.kotlin.types.typeUtil.closure]. + */ +fun Collection.lazyClosure(f: (T) -> Collection): Sequence = sequence { + if (size == 0) return@sequence + var sizeBeforeIteration = 0 + + yieldAll(this@lazyClosure) + var yieldedCount = size + var elementsToCheck = this@lazyClosure + + while (yieldedCount > sizeBeforeIteration) { + val toAdd = hashSetOf() + elementsToCheck.forEach { + val neighbours = f(it) + yieldAll(neighbours) + yieldedCount += neighbours.size + toAdd.addAll(neighbours) + } + elementsToCheck = toAdd + sizeBeforeIteration = yieldedCount + } +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/ModuleHighlightUtil2.java.191 b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/ModuleHighlightUtil2.java.191 new file mode 100644 index 00000000000..053f070e51d --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/ModuleHighlightUtil2.java.191 @@ -0,0 +1,114 @@ +/* + * 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. + */ + +package org.jetbrains.kotlin.idea.modules; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.ProjectFileIndex; +import com.intellij.openapi.vfs.JarFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiJavaFile; +import com.intellij.psi.PsiJavaModule; +import com.intellij.psi.PsiManager; +import com.intellij.psi.impl.light.LightJavaModule; +import kotlin.collections.ArraysKt; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.idea.core.FileIndexUtilsKt; + +import java.io.IOException; +import java.io.InputStream; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import java.util.jar.Manifest; + +import static com.intellij.psi.PsiJavaModule.MODULE_INFO_FILE; + +// Copied from com.intellij.codeInsight.daemon.impl.analysis.ModuleHighlightUtil +public class ModuleHighlightUtil2 { + private static final Attributes.Name MULTI_RELEASE = new Attributes.Name("Multi-Release"); + + @Nullable + static PsiJavaModule getModuleDescriptor(@NotNull VirtualFile file, @NotNull Project project) { + ProjectFileIndex index = ProjectFileIndex.SERVICE.getInstance(project); + if (index.isInLibrary(file)) { + VirtualFile root; + if ((root = index.getClassRootForFile(file)) != null) { + VirtualFile descriptorFile = root.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE); + if (descriptorFile == null) { + VirtualFile alt = root.findFileByRelativePath("META-INF/versions/9/" + PsiJavaModule.MODULE_INFO_CLS_FILE); + if (alt != null && isMultiReleaseJar(root)) { + descriptorFile = alt; + } + } + if (descriptorFile != null) { + PsiFile psiFile = PsiManager.getInstance(project).findFile(descriptorFile); + if (psiFile instanceof PsiJavaFile) { + return ((PsiJavaFile) psiFile).getModuleDeclaration(); + } + } + else if (root.getFileSystem() instanceof JarFileSystem && "jar".equalsIgnoreCase(root.getExtension())) { + return LightJavaModule.getModule(PsiManager.getInstance(project), root); + } + } + else if ((root = index.getSourceRootForFile(file)) != null) { + VirtualFile descriptorFile = root.findChild(MODULE_INFO_FILE); + if (descriptorFile != null) { + PsiFile psiFile = PsiManager.getInstance(project).findFile(descriptorFile); + if (psiFile instanceof PsiJavaFile) { + return ((PsiJavaFile) psiFile).getModuleDeclaration(); + } + } + } + } + else { + Module module = index.getModuleForFile(file); + if (module != null) { + boolean isTest = FileIndexUtilsKt.isInTestSourceContentKotlinAware(index, file); + VirtualFile modularRoot = ArraysKt.singleOrNull(ModuleRootManager.getInstance(module).getSourceRoots(isTest), + root -> root.findChild(MODULE_INFO_FILE) != null); + if (modularRoot != null) { + VirtualFile moduleInfo = modularRoot.findChild(MODULE_INFO_FILE); + assert moduleInfo != null : modularRoot; + PsiFile psiFile = PsiManager.getInstance(project).findFile(moduleInfo); + if (psiFile instanceof PsiJavaFile) { + return ((PsiJavaFile) psiFile).getModuleDeclaration(); + } + } + } + } + + return null; + } + + private static boolean isMultiReleaseJar(VirtualFile root) { + if (root.getFileSystem() instanceof JarFileSystem) { + VirtualFile manifest = root.findFileByRelativePath(JarFile.MANIFEST_NAME); + if (manifest != null) { + try (InputStream stream = manifest.getInputStream()) { + return Boolean.valueOf(new Manifest(stream).getMainAttributes().getValue(MULTI_RELEASE)); + } + catch (IOException ignored) { + } + } + } + + return false; + } +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/ModuleHighlightUtil2.java.192 b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/ModuleHighlightUtil2.java.192 new file mode 100644 index 00000000000..053f070e51d --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/ModuleHighlightUtil2.java.192 @@ -0,0 +1,114 @@ +/* + * 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. + */ + +package org.jetbrains.kotlin.idea.modules; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.ProjectFileIndex; +import com.intellij.openapi.vfs.JarFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiJavaFile; +import com.intellij.psi.PsiJavaModule; +import com.intellij.psi.PsiManager; +import com.intellij.psi.impl.light.LightJavaModule; +import kotlin.collections.ArraysKt; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.idea.core.FileIndexUtilsKt; + +import java.io.IOException; +import java.io.InputStream; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import java.util.jar.Manifest; + +import static com.intellij.psi.PsiJavaModule.MODULE_INFO_FILE; + +// Copied from com.intellij.codeInsight.daemon.impl.analysis.ModuleHighlightUtil +public class ModuleHighlightUtil2 { + private static final Attributes.Name MULTI_RELEASE = new Attributes.Name("Multi-Release"); + + @Nullable + static PsiJavaModule getModuleDescriptor(@NotNull VirtualFile file, @NotNull Project project) { + ProjectFileIndex index = ProjectFileIndex.SERVICE.getInstance(project); + if (index.isInLibrary(file)) { + VirtualFile root; + if ((root = index.getClassRootForFile(file)) != null) { + VirtualFile descriptorFile = root.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE); + if (descriptorFile == null) { + VirtualFile alt = root.findFileByRelativePath("META-INF/versions/9/" + PsiJavaModule.MODULE_INFO_CLS_FILE); + if (alt != null && isMultiReleaseJar(root)) { + descriptorFile = alt; + } + } + if (descriptorFile != null) { + PsiFile psiFile = PsiManager.getInstance(project).findFile(descriptorFile); + if (psiFile instanceof PsiJavaFile) { + return ((PsiJavaFile) psiFile).getModuleDeclaration(); + } + } + else if (root.getFileSystem() instanceof JarFileSystem && "jar".equalsIgnoreCase(root.getExtension())) { + return LightJavaModule.getModule(PsiManager.getInstance(project), root); + } + } + else if ((root = index.getSourceRootForFile(file)) != null) { + VirtualFile descriptorFile = root.findChild(MODULE_INFO_FILE); + if (descriptorFile != null) { + PsiFile psiFile = PsiManager.getInstance(project).findFile(descriptorFile); + if (psiFile instanceof PsiJavaFile) { + return ((PsiJavaFile) psiFile).getModuleDeclaration(); + } + } + } + } + else { + Module module = index.getModuleForFile(file); + if (module != null) { + boolean isTest = FileIndexUtilsKt.isInTestSourceContentKotlinAware(index, file); + VirtualFile modularRoot = ArraysKt.singleOrNull(ModuleRootManager.getInstance(module).getSourceRoots(isTest), + root -> root.findChild(MODULE_INFO_FILE) != null); + if (modularRoot != null) { + VirtualFile moduleInfo = modularRoot.findChild(MODULE_INFO_FILE); + assert moduleInfo != null : modularRoot; + PsiFile psiFile = PsiManager.getInstance(project).findFile(moduleInfo); + if (psiFile instanceof PsiJavaFile) { + return ((PsiJavaFile) psiFile).getModuleDeclaration(); + } + } + } + } + + return null; + } + + private static boolean isMultiReleaseJar(VirtualFile root) { + if (root.getFileSystem() instanceof JarFileSystem) { + VirtualFile manifest = root.findFileByRelativePath(JarFile.MANIFEST_NAME); + if (manifest != null) { + try (InputStream stream = manifest.getInputStream()) { + return Boolean.valueOf(new Manifest(stream).getMainAttributes().getValue(MULTI_RELEASE)); + } + catch (IOException ignored) { + } + } + } + + return false; + } +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/ModuleHighlightUtil2.java.as40 b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/ModuleHighlightUtil2.java.as40 new file mode 100644 index 00000000000..053f070e51d --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/ModuleHighlightUtil2.java.as40 @@ -0,0 +1,114 @@ +/* + * 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. + */ + +package org.jetbrains.kotlin.idea.modules; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.ProjectFileIndex; +import com.intellij.openapi.vfs.JarFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiJavaFile; +import com.intellij.psi.PsiJavaModule; +import com.intellij.psi.PsiManager; +import com.intellij.psi.impl.light.LightJavaModule; +import kotlin.collections.ArraysKt; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.idea.core.FileIndexUtilsKt; + +import java.io.IOException; +import java.io.InputStream; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import java.util.jar.Manifest; + +import static com.intellij.psi.PsiJavaModule.MODULE_INFO_FILE; + +// Copied from com.intellij.codeInsight.daemon.impl.analysis.ModuleHighlightUtil +public class ModuleHighlightUtil2 { + private static final Attributes.Name MULTI_RELEASE = new Attributes.Name("Multi-Release"); + + @Nullable + static PsiJavaModule getModuleDescriptor(@NotNull VirtualFile file, @NotNull Project project) { + ProjectFileIndex index = ProjectFileIndex.SERVICE.getInstance(project); + if (index.isInLibrary(file)) { + VirtualFile root; + if ((root = index.getClassRootForFile(file)) != null) { + VirtualFile descriptorFile = root.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE); + if (descriptorFile == null) { + VirtualFile alt = root.findFileByRelativePath("META-INF/versions/9/" + PsiJavaModule.MODULE_INFO_CLS_FILE); + if (alt != null && isMultiReleaseJar(root)) { + descriptorFile = alt; + } + } + if (descriptorFile != null) { + PsiFile psiFile = PsiManager.getInstance(project).findFile(descriptorFile); + if (psiFile instanceof PsiJavaFile) { + return ((PsiJavaFile) psiFile).getModuleDeclaration(); + } + } + else if (root.getFileSystem() instanceof JarFileSystem && "jar".equalsIgnoreCase(root.getExtension())) { + return LightJavaModule.getModule(PsiManager.getInstance(project), root); + } + } + else if ((root = index.getSourceRootForFile(file)) != null) { + VirtualFile descriptorFile = root.findChild(MODULE_INFO_FILE); + if (descriptorFile != null) { + PsiFile psiFile = PsiManager.getInstance(project).findFile(descriptorFile); + if (psiFile instanceof PsiJavaFile) { + return ((PsiJavaFile) psiFile).getModuleDeclaration(); + } + } + } + } + else { + Module module = index.getModuleForFile(file); + if (module != null) { + boolean isTest = FileIndexUtilsKt.isInTestSourceContentKotlinAware(index, file); + VirtualFile modularRoot = ArraysKt.singleOrNull(ModuleRootManager.getInstance(module).getSourceRoots(isTest), + root -> root.findChild(MODULE_INFO_FILE) != null); + if (modularRoot != null) { + VirtualFile moduleInfo = modularRoot.findChild(MODULE_INFO_FILE); + assert moduleInfo != null : modularRoot; + PsiFile psiFile = PsiManager.getInstance(project).findFile(moduleInfo); + if (psiFile instanceof PsiJavaFile) { + return ((PsiJavaFile) psiFile).getModuleDeclaration(); + } + } + } + } + + return null; + } + + private static boolean isMultiReleaseJar(VirtualFile root) { + if (root.getFileSystem() instanceof JarFileSystem) { + VirtualFile manifest = root.findFileByRelativePath(JarFile.MANIFEST_NAME); + if (manifest != null) { + try (InputStream stream = manifest.getInputStream()) { + return Boolean.valueOf(new Manifest(stream).getMainAttributes().getValue(MULTI_RELEASE)); + } + catch (IOException ignored) { + } + } + } + + return false; + } +} diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/statistics/IDESettingsFUSCollector.kt.191 b/idea/idea-core/src/org/jetbrains/kotlin/idea/statistics/IDESettingsFUSCollector.kt.191 new file mode 100644 index 00000000000..6ec4f95b598 --- /dev/null +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/statistics/IDESettingsFUSCollector.kt.191 @@ -0,0 +1,39 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.statistics + +import com.intellij.internal.statistic.beans.UsageDescriptor +import com.intellij.internal.statistic.eventLog.FeatureUsageData +import com.intellij.internal.statistic.service.fus.collectors.ProjectUsagesCollector +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.idea.KotlinPluginUtil +import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings +import org.jetbrains.kotlin.idea.project.NewInferenceForIDEAnalysisComponent + +class IDESettingsFUSCollector : ProjectUsagesCollector() { + + override fun getUsages(project: Project): Set { + val usages = mutableSetOf() + + @Suppress("DEPRECATION") + val inferenceState = NewInferenceForIDEAnalysisComponent.isEnabledForV1(project) + usages.add(UsageDescriptor("newInference", flagUsage(inferenceState))) + + val scriptingAutoReloadEnabled = KotlinScriptingSettings.getInstance(project).isAutoReloadEnabled + usages.add(UsageDescriptor("scriptingAutoReloadEnabled", flagUsage(scriptingAutoReloadEnabled))) + + return usages + } + + private fun flagUsage(enabled: Boolean): FeatureUsageData { + return FeatureUsageData() + .addData("enabled", enabled) + .addData("pluginVersion", KotlinPluginUtil.getPluginVersion()) + } + + override fun getGroupId() = "kotlin.ide.settings" + override fun getVersion(): Int = 2 +} \ No newline at end of file diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/statistics/ProjectConfigurationCollector.kt.191 b/idea/idea-core/src/org/jetbrains/kotlin/idea/statistics/ProjectConfigurationCollector.kt.191 new file mode 100644 index 00000000000..41fb977b5b4 --- /dev/null +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/statistics/ProjectConfigurationCollector.kt.191 @@ -0,0 +1,73 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.statistics + +import com.intellij.facet.ProjectFacetManager +import com.intellij.internal.statistic.beans.UsageDescriptor +import com.intellij.internal.statistic.eventLog.FeatureUsageData +import com.intellij.internal.statistic.service.fus.collectors.ProjectUsagesCollector +import com.intellij.openapi.module.Module +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.idea.KotlinPluginUtil +import org.jetbrains.kotlin.idea.configuration.BuildSystemType +import org.jetbrains.kotlin.idea.configuration.getBuildSystemType +import org.jetbrains.kotlin.idea.facet.KotlinFacetType +import org.jetbrains.kotlin.idea.project.languageVersionSettings +import org.jetbrains.kotlin.idea.project.platform +import org.jetbrains.kotlin.platform.isCommon +import org.jetbrains.kotlin.platform.js.isJs +import org.jetbrains.kotlin.platform.jvm.isJvm +import org.jetbrains.kotlin.platform.konan.isNative + +class ProjectConfigurationCollector : ProjectUsagesCollector() { + + override fun getUsages(project: Project): Set { + val usages = mutableSetOf() + val modulesWithFacet = ProjectFacetManager.getInstance(project).getModulesWithFacet(KotlinFacetType.TYPE_ID) + + if (modulesWithFacet.isNotEmpty()) { + val pluginVersion = KotlinPluginUtil.getPluginVersion() + modulesWithFacet.forEach { + + val buildSystem = getBuildSystemType(it) + val platform = getPlatform(it) + val languageVersion = it.languageVersionSettings.languageVersion.versionString + + val data = FeatureUsageData() + .addData("pluginVersion", pluginVersion) + .addData("system", buildSystem) + .addData("platform", platform) + .addData("languageVersion", languageVersion) + val usageDescriptor = UsageDescriptor("Build", data) + usages.add(usageDescriptor) + } + } + return usages + } + + private fun getPlatform(it: Module): String { + return when { + it.platform.isJvm() -> "jvm" + it.platform.isJs() -> "js" + it.platform.isCommon() -> "common" + it.platform.isNative() -> "native" + else -> "unknown" + } + } + + private fun getBuildSystemType(it: Module): String { + val buildSystem = it.getBuildSystemType() + return when { + buildSystem == BuildSystemType.JPS -> "JPS" + buildSystem.toString().toLowerCase().contains("maven") -> "Maven" + buildSystem.toString().toLowerCase().contains("gradle") -> "Gradle" + else -> "unknown" + } + } + + override fun getGroupId() = "kotlin.project.configuration" + override fun getVersion(): Int = 1 +} diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/run/jvmTestClassUtils.kt.191 b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/run/jvmTestClassUtils.kt.191 new file mode 100644 index 00000000000..86f76ce8d51 --- /dev/null +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/run/jvmTestClassUtils.kt.191 @@ -0,0 +1,57 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.run + +import com.intellij.execution.Location +import com.intellij.execution.actions.ConfigurationFromContext +import com.intellij.execution.junit.JUnitConfigurationProducer +import com.intellij.execution.testframework.AbstractPatternBasedConfigurationProducer +import com.intellij.ide.plugins.PluginManager +import com.intellij.openapi.extensions.PluginId.getId +import com.intellij.openapi.util.component1 +import com.intellij.openapi.util.component2 +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiMethod + +private val isJUnitEnabled by lazy { isPluginEnabled("JUnit") } +private val isTestNgEnabled by lazy { isPluginEnabled("TestNG-J") } + +private fun isPluginEnabled(id: String): Boolean { + return PluginManager.isPluginInstalled(getId(id)) && id !in PluginManager.getDisabledPlugins() +} + +internal fun ConfigurationFromContext.isJpsJunitConfiguration(): Boolean { + return isProducedBy(JUnitConfigurationProducer::class.java) + || isProducedBy(AbstractPatternBasedConfigurationProducer::class.java) +} + +internal fun canRunJvmTests() = isJUnitEnabled || isTestNgEnabled + +internal fun getTestClassForJvm(location: Location<*>): PsiClass? { + val leaf = location.psiElement ?: return null + + if (isJUnitEnabled) { + KotlinJUnitRunConfigurationProducer.getTestClass(leaf)?.let { return it } + } + if (isTestNgEnabled) { + KotlinTestNgConfigurationProducer.getTestClassAndMethod(leaf)?.let { (testClass, testMethod) -> + return if (testMethod == null) testClass else null + } + } + return null +} + +internal fun getTestMethodForJvm(location: Location<*>): PsiMethod? { + val leaf = location.psiElement ?: return null + + if (isJUnitEnabled) { + KotlinJUnitRunConfigurationProducer.getTestMethod(leaf)?.let { return it } + } + if (isTestNgEnabled) { + KotlinTestNgConfigurationProducer.getTestClassAndMethod(leaf)?.second?.let { return it } + } + return null +} \ No newline at end of file diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/run/jvmTestClassUtils.kt.192 b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/run/jvmTestClassUtils.kt.192 new file mode 100644 index 00000000000..86f76ce8d51 --- /dev/null +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/run/jvmTestClassUtils.kt.192 @@ -0,0 +1,57 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.run + +import com.intellij.execution.Location +import com.intellij.execution.actions.ConfigurationFromContext +import com.intellij.execution.junit.JUnitConfigurationProducer +import com.intellij.execution.testframework.AbstractPatternBasedConfigurationProducer +import com.intellij.ide.plugins.PluginManager +import com.intellij.openapi.extensions.PluginId.getId +import com.intellij.openapi.util.component1 +import com.intellij.openapi.util.component2 +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiMethod + +private val isJUnitEnabled by lazy { isPluginEnabled("JUnit") } +private val isTestNgEnabled by lazy { isPluginEnabled("TestNG-J") } + +private fun isPluginEnabled(id: String): Boolean { + return PluginManager.isPluginInstalled(getId(id)) && id !in PluginManager.getDisabledPlugins() +} + +internal fun ConfigurationFromContext.isJpsJunitConfiguration(): Boolean { + return isProducedBy(JUnitConfigurationProducer::class.java) + || isProducedBy(AbstractPatternBasedConfigurationProducer::class.java) +} + +internal fun canRunJvmTests() = isJUnitEnabled || isTestNgEnabled + +internal fun getTestClassForJvm(location: Location<*>): PsiClass? { + val leaf = location.psiElement ?: return null + + if (isJUnitEnabled) { + KotlinJUnitRunConfigurationProducer.getTestClass(leaf)?.let { return it } + } + if (isTestNgEnabled) { + KotlinTestNgConfigurationProducer.getTestClassAndMethod(leaf)?.let { (testClass, testMethod) -> + return if (testMethod == null) testClass else null + } + } + return null +} + +internal fun getTestMethodForJvm(location: Location<*>): PsiMethod? { + val leaf = location.psiElement ?: return null + + if (isJUnitEnabled) { + KotlinJUnitRunConfigurationProducer.getTestMethod(leaf)?.let { return it } + } + if (isTestNgEnabled) { + KotlinTestNgConfigurationProducer.getTestClassAndMethod(leaf)?.second?.let { return it } + } + return null +} \ No newline at end of file diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/compiler/configuration/KotlinBuildProcessParametersProvider.kt.191 b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/compiler/configuration/KotlinBuildProcessParametersProvider.kt.191 new file mode 100644 index 00000000000..e3954f77d31 --- /dev/null +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/compiler/configuration/KotlinBuildProcessParametersProvider.kt.191 @@ -0,0 +1,39 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.compiler.configuration + +import com.intellij.compiler.server.BuildProcessParametersProvider +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.registry.Registry +import org.jetbrains.kotlin.config.IncrementalCompilation +import org.jetbrains.kotlin.idea.PluginStartupComponent + +class KotlinBuildProcessParametersProvider(private val project: Project) : BuildProcessParametersProvider() { + override fun getVMArguments(): MutableList { + val compilerWorkspaceSettings = KotlinCompilerWorkspaceSettings.getInstance(project) + + val res = arrayListOf() + if (compilerWorkspaceSettings.preciseIncrementalEnabled) { + res.add("-D" + IncrementalCompilation.INCREMENTAL_COMPILATION_JVM_PROPERTY + "=true") + } + if (compilerWorkspaceSettings.incrementalCompilationForJsEnabled) { + res.add("-D" + IncrementalCompilation.INCREMENTAL_COMPILATION_JS_PROPERTY + "=true") + } + if (compilerWorkspaceSettings.enableDaemon) { + res.add("-Dkotlin.daemon.enabled") + } + if (Registry.`is`("kotlin.jps.instrument.bytecode", false)) { + res.add("-Dkotlin.jps.instrument.bytecode=true") + } + PluginStartupComponent.getInstance().aliveFlagPath.let { + if (!it.isBlank()) { + // TODO: consider taking the property name from compiler/daemon/common (check whether dependency will be not too heavy) + res.add("-Dkotlin.daemon.client.alive.path=\"$it\"") + } + } + return res + } +} diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/compiler/configuration/KotlinBuildProcessParametersProvider.kt.192 b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/compiler/configuration/KotlinBuildProcessParametersProvider.kt.192 new file mode 100644 index 00000000000..e3954f77d31 --- /dev/null +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/compiler/configuration/KotlinBuildProcessParametersProvider.kt.192 @@ -0,0 +1,39 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.compiler.configuration + +import com.intellij.compiler.server.BuildProcessParametersProvider +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.registry.Registry +import org.jetbrains.kotlin.config.IncrementalCompilation +import org.jetbrains.kotlin.idea.PluginStartupComponent + +class KotlinBuildProcessParametersProvider(private val project: Project) : BuildProcessParametersProvider() { + override fun getVMArguments(): MutableList { + val compilerWorkspaceSettings = KotlinCompilerWorkspaceSettings.getInstance(project) + + val res = arrayListOf() + if (compilerWorkspaceSettings.preciseIncrementalEnabled) { + res.add("-D" + IncrementalCompilation.INCREMENTAL_COMPILATION_JVM_PROPERTY + "=true") + } + if (compilerWorkspaceSettings.incrementalCompilationForJsEnabled) { + res.add("-D" + IncrementalCompilation.INCREMENTAL_COMPILATION_JS_PROPERTY + "=true") + } + if (compilerWorkspaceSettings.enableDaemon) { + res.add("-Dkotlin.daemon.enabled") + } + if (Registry.`is`("kotlin.jps.instrument.bytecode", false)) { + res.add("-Dkotlin.jps.instrument.bytecode=true") + } + PluginStartupComponent.getInstance().aliveFlagPath.let { + if (!it.isBlank()) { + // TODO: consider taking the property name from compiler/daemon/common (check whether dependency will be not too heavy) + res.add("-Dkotlin.daemon.client.alive.path=\"$it\"") + } + } + return res + } +} diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ScratchAdditionalIdeaDependenciesProvider.kt.191 b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ScratchAdditionalIdeaDependenciesProvider.kt.191 new file mode 100644 index 00000000000..40e4aea0d63 --- /dev/null +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ScratchAdditionalIdeaDependenciesProvider.kt.191 @@ -0,0 +1,58 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.scratch + +import com.intellij.ide.scratch.ScratchFileService +import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.* +import com.intellij.openapi.roots.libraries.Library +import com.intellij.openapi.vfs.VirtualFile +import org.jetbrains.kotlin.idea.core.script.dependencies.ScriptAdditionalIdeaDependenciesProvider +import org.jetbrains.kotlin.idea.core.script.scriptRelatedModuleName +import org.jetbrains.kotlin.utils.addIfNotNull + +class ScratchAdditionalIdeaDependenciesProvider : ScriptAdditionalIdeaDependenciesProvider() { + + override fun getRelatedModules(file: VirtualFile, project: Project): List { + if (!ScratchFileService.isInScratchRoot(file)) return emptyList() + + val scratchModule = file.scriptRelatedModuleName?.let { + ModuleManager.getInstance(project).findModuleByName(it) + } ?: return emptyList() + + val modules = linkedSetOf(scratchModule) + moduleDependencyEnumerator(scratchModule).withoutLibraries().forEach { orderEntry -> + when (orderEntry) { + is ModuleSourceOrderEntry -> modules.add(orderEntry.getOwnerModule()) + is ModuleOrderEntry -> modules.addIfNotNull(orderEntry.module) + } + true + } + return modules.toList() + } + + override fun getRelatedLibraries(file: VirtualFile, project: Project): List { + if (!ScratchFileService.isInScratchRoot(file)) return emptyList() + + val result = linkedSetOf() + getRelatedModules(file, project).forEach { + moduleDependencyEnumerator(it).withoutDepModules().forEach { orderEntry -> + if (orderEntry is LibraryOrderEntry) { + result.addIfNotNull(orderEntry.library) + } + true + } + } + return result.toList() + } + + private fun moduleDependencyEnumerator(it: Module): OrderEnumerator { + return ModuleRootManager.getInstance(it).orderEntries() + .compileOnly().withoutSdk().recursively().exportedOnly() + } +} \ No newline at end of file diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ScratchAdditionalIdeaDependenciesProvider.kt.192 b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ScratchAdditionalIdeaDependenciesProvider.kt.192 new file mode 100644 index 00000000000..40e4aea0d63 --- /dev/null +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ScratchAdditionalIdeaDependenciesProvider.kt.192 @@ -0,0 +1,58 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.scratch + +import com.intellij.ide.scratch.ScratchFileService +import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.* +import com.intellij.openapi.roots.libraries.Library +import com.intellij.openapi.vfs.VirtualFile +import org.jetbrains.kotlin.idea.core.script.dependencies.ScriptAdditionalIdeaDependenciesProvider +import org.jetbrains.kotlin.idea.core.script.scriptRelatedModuleName +import org.jetbrains.kotlin.utils.addIfNotNull + +class ScratchAdditionalIdeaDependenciesProvider : ScriptAdditionalIdeaDependenciesProvider() { + + override fun getRelatedModules(file: VirtualFile, project: Project): List { + if (!ScratchFileService.isInScratchRoot(file)) return emptyList() + + val scratchModule = file.scriptRelatedModuleName?.let { + ModuleManager.getInstance(project).findModuleByName(it) + } ?: return emptyList() + + val modules = linkedSetOf(scratchModule) + moduleDependencyEnumerator(scratchModule).withoutLibraries().forEach { orderEntry -> + when (orderEntry) { + is ModuleSourceOrderEntry -> modules.add(orderEntry.getOwnerModule()) + is ModuleOrderEntry -> modules.addIfNotNull(orderEntry.module) + } + true + } + return modules.toList() + } + + override fun getRelatedLibraries(file: VirtualFile, project: Project): List { + if (!ScratchFileService.isInScratchRoot(file)) return emptyList() + + val result = linkedSetOf() + getRelatedModules(file, project).forEach { + moduleDependencyEnumerator(it).withoutDepModules().forEach { orderEntry -> + if (orderEntry is LibraryOrderEntry) { + result.addIfNotNull(orderEntry.library) + } + true + } + } + return result.toList() + } + + private fun moduleDependencyEnumerator(it: Module): OrderEnumerator { + return ModuleRootManager.getInstance(it).orderEntries() + .compileOnly().withoutSdk().recursively().exportedOnly() + } +} \ No newline at end of file diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ScratchAdditionalIdeaDependenciesProvider.kt.as40 b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ScratchAdditionalIdeaDependenciesProvider.kt.as40 new file mode 100644 index 00000000000..40e4aea0d63 --- /dev/null +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ScratchAdditionalIdeaDependenciesProvider.kt.as40 @@ -0,0 +1,58 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.scratch + +import com.intellij.ide.scratch.ScratchFileService +import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.* +import com.intellij.openapi.roots.libraries.Library +import com.intellij.openapi.vfs.VirtualFile +import org.jetbrains.kotlin.idea.core.script.dependencies.ScriptAdditionalIdeaDependenciesProvider +import org.jetbrains.kotlin.idea.core.script.scriptRelatedModuleName +import org.jetbrains.kotlin.utils.addIfNotNull + +class ScratchAdditionalIdeaDependenciesProvider : ScriptAdditionalIdeaDependenciesProvider() { + + override fun getRelatedModules(file: VirtualFile, project: Project): List { + if (!ScratchFileService.isInScratchRoot(file)) return emptyList() + + val scratchModule = file.scriptRelatedModuleName?.let { + ModuleManager.getInstance(project).findModuleByName(it) + } ?: return emptyList() + + val modules = linkedSetOf(scratchModule) + moduleDependencyEnumerator(scratchModule).withoutLibraries().forEach { orderEntry -> + when (orderEntry) { + is ModuleSourceOrderEntry -> modules.add(orderEntry.getOwnerModule()) + is ModuleOrderEntry -> modules.addIfNotNull(orderEntry.module) + } + true + } + return modules.toList() + } + + override fun getRelatedLibraries(file: VirtualFile, project: Project): List { + if (!ScratchFileService.isInScratchRoot(file)) return emptyList() + + val result = linkedSetOf() + getRelatedModules(file, project).forEach { + moduleDependencyEnumerator(it).withoutDepModules().forEach { orderEntry -> + if (orderEntry is LibraryOrderEntry) { + result.addIfNotNull(orderEntry.library) + } + true + } + } + return result.toList() + } + + private fun moduleDependencyEnumerator(it: Module): OrderEnumerator { + return ModuleRootManager.getInstance(it).orderEntries() + .compileOnly().withoutSdk().recursively().exportedOnly() + } +} \ No newline at end of file diff --git a/idea/resources/META-INF/plugin-common.xml.191 b/idea/resources/META-INF/plugin-common.xml.191 new file mode 100644 index 00000000000..3b3ae2a2de9 --- /dev/null +++ b/idea/resources/META-INF/plugin-common.xml.191 @@ -0,0 +1,3543 @@ + + + + org.jetbrains.kotlin.idea.highlighter.KotlinBeforeResolveHighlightingPass$Factory + + + org.jetbrains.kotlin.idea.parameterInfo.custom.KotlinCodeHintsPass$Companion$Factory + + + org.jetbrains.kotlin.idea.refactoring.cutPaste.MoveDeclarationsPassFactory + + + + org.jetbrains.kotlin.idea.highlighter.ScriptExternalHighlightingPass$Factory + + + org.jetbrains.kotlin.idea.completion.LookupCancelWatcher + + + org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListener + + + org.jetbrains.kotlin.idea.caches.KotlinPackageContentModificationListener + + + org.jetbrains.kotlin.idea.completion.CompletionBindingContextProvider + org.jetbrains.kotlin.idea.completion.CompletionBindingContextProvider + + + org.jetbrains.kotlin.idea.configuration.KotlinMigrationProjectComponent + + + org.jetbrains.kotlin.idea.parameterInfo.custom.KotlinCodeHintsModel + + + + + + org.jetbrains.kotlin.idea.PluginStartupComponent + + + + org.jetbrains.kotlin.idea.versions.KotlinUpdatePluginComponent + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.jetbrains.kotlin.idea.intentions.ImportMemberIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ImportAllMembersIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.SpecifyTypeExplicitlyIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.SpecifyTypeExplicitlyInDestructuringAssignmentIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveExplicitTypeIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertToBlockBodyIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.conventionNameCalls.ReplaceContainsIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.conventionNameCalls.ReplaceInvokeIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.conventionNameCalls.ReplaceCallWithUnaryOperatorIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.FoldIfToReturnAsymmetricallyIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.UnfoldAssignmentToIfIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.UnfoldPropertyToIfIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.UnfoldAssignmentToWhenIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.UnfoldPropertyToWhenIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.UnfoldReturnToIfIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.UnfoldReturnToWhenIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.DoubleBangToIfThenIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.ElvisToIfThenIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.SafeAccessToIfThenIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.IfToWhenIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.WhenToIfIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.FlattenWhenIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.EliminateWhenSubjectIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveUnnecessaryParenthesesIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveExplicitTypeArgumentsIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveExplicitSuperQualifierIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.InsertCurlyBracesToTemplateIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.MoveLambdaInsideParenthesesIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.InsertExplicitTypeArgumentsIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.declarations.SplitPropertyDeclarationIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.declarations.ConvertMemberToExtensionIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ReconstructTypeInCastOrIsIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.InfixCallToOrdinaryIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ToInfixCallIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ReplaceExplicitFunctionLiteralParamWithItIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ReplaceItWithExplicitFunctionLiteralParamIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveBracesIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddBracesIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertBinaryExpressionWithDemorgansLawIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.SimplifyBooleanWithConstantsIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddForLoopIndicesIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveForLoopIndicesIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.loopToCallChain.UseWithIndexIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.SwapBinaryExpressionIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.SwapStringEqualsIgnoreCaseIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.SplitIfIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ReplaceWithOrdinaryAssignmentIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.SpecifyExplicitLambdaSignatureIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveExplicitLambdaParameterTypesIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertForEachToForLoopIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertToForEachFunctionCallIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertToStringTemplateIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertToRawStringTemplateIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.OperatorToFunctionIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertToConcatenatedStringIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertFunctionToPropertyIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertPropertyToFunctionIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertReceiverToParameterIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertParameterToReceiverIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertPropertyInitializerToGetterIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.InvertIfConditionIntention + Kotlin + + + + org.jetbrains.kotlin.idea.refactoring.move.changePackage.ChangePackageIntention + Kotlin + + + + org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ExtractDeclarationFromCurrentFileIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ChangeVisibilityModifierIntention$Public + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ChangeVisibilityModifierIntention$Private + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ChangeVisibilityModifierIntention$Protected + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ChangeVisibilityModifierIntention$Internal + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddNameToArgumentIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddNamesToFollowingArgumentsIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ReplaceUnderscoreWithParameterNameIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddJvmOverloadsIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddJvmStaticIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveArgumentNameIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.IterateExpressionIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.UsePropertyAccessSyntaxIntention + Kotlin + + + + org.jetbrains.kotlin.idea.quickfix.AddConstModifierIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.IntroduceBackingPropertyIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.JoinDeclarationAndAssignmentIntention + Kotlin + + + + org.jetbrains.kotlin.idea.testIntegration.KotlinCreateTestIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ObjectLiteralToLambdaIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.DestructureIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AnonymousFunctionToLambdaIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ImplementAbstractMemberIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ImplementAbstractMemberAsConstructorParameterIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddValVarToConstructorParameterAction$Intention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.MoveMemberToCompanionObjectIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.MoveMemberOutOfCompanionObjectIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.CreateKotlinSubClassIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ToRawStringLiteralIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.TrailingCommaIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ToOrdinaryStringLiteralIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.IntroduceVariableIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.IntroduceImportAliasIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveSingleExpressionStringTemplateIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ReplaceUntilWithRangeToIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveEmptyParenthesesFromLambdaCallIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertCamelCaseTestFunctionToSpacedIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertSnakeCaseTestFunctionToSpacedIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.copyConcatenatedStringToClipboard.CopyConcatenatedStringToClipboardIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveConstructorKeywordIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertPrimaryConstructorToSecondaryIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertSecondaryConstructorToPrimaryIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ReplaceSizeCheckWithIsNotEmptyIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ReplaceSizeZeroCheckWithIsEmptyIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveEmptyClassBodyIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertEnumToSealedClassIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertSealedClassToEnumIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveRedundantCallsOfConversionMethodsIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveEmptyPrimaryConstructorIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveEmptySecondaryConstructorBodyIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertTryFinallyToUseCallIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddNamesToCallArgumentsIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertFunctionTypeParameterToReceiverIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertFunctionTypeReceiverToParameterIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertRangeCheckToTwoComparisonsIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RenameFileToMatchClassIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertObjectLiteralToClassIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.MergeIfsIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.MergeElseIfIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddMissingDestructuringIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertToApplyIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertToAlsoIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertToWithIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertToRunIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.MovePropertyToClassBodyIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.MovePropertyToConstructorIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddOpenModifierIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ValToObjectIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ChopParameterListIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ChopArgumentListIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.NullableBooleanEqualityCheckToElvisIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ReplaceAddWithPlusAssignIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddPropertyAccessorsIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddPropertyGetterIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddPropertySetterIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.MoveMemberToTopLevelIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertUnsafeCastCallToUnsafeCastIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertUnsafeCastToUnsafeCastCallIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveLabeledReturnInLambdaIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddLabeledReturnInLambdaIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddAnnotationUseSiteTargetIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.JoinParameterListIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.JoinArgumentListIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertLineCommentToBlockCommentIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertBlockCommentToLineCommentIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.IndentRawStringIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertVarargParameterToArrayIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertArrayParameterToVarargIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.LambdaToAnonymousFunctionIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddWhenRemainingBranchesIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertPropertyGetterToInitializerIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.SamConversionToAnonymousObjectIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddThrowsAnnotationIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertNullablePropertyToLateinitIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertLateinitPropertyToNullableIntention + Kotlin + + + + org.jetbrains.kotlin.idea.parameterInfo.custom.DisableReturnLambdaHintOptionAction + + + + org.jetbrains.kotlin.idea.intentions.AddUnderscoresToNumericLiteralIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ReplaceMapGetOrDefaultIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveUnderscoresFromNumericLiteralIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RenameClassToContainingFileNameIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertCollectionConstructorToFunction + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertOrdinaryPropertyToLazyIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertLazyPropertyToOrdinaryIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertLambdaToMultiLineIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertLambdaToSingleLineIntention + Kotlin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/idea/resources/META-INF/plugin-common.xml.192 b/idea/resources/META-INF/plugin-common.xml.192 new file mode 100644 index 00000000000..3b3ae2a2de9 --- /dev/null +++ b/idea/resources/META-INF/plugin-common.xml.192 @@ -0,0 +1,3543 @@ + + + + org.jetbrains.kotlin.idea.highlighter.KotlinBeforeResolveHighlightingPass$Factory + + + org.jetbrains.kotlin.idea.parameterInfo.custom.KotlinCodeHintsPass$Companion$Factory + + + org.jetbrains.kotlin.idea.refactoring.cutPaste.MoveDeclarationsPassFactory + + + + org.jetbrains.kotlin.idea.highlighter.ScriptExternalHighlightingPass$Factory + + + org.jetbrains.kotlin.idea.completion.LookupCancelWatcher + + + org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListener + + + org.jetbrains.kotlin.idea.caches.KotlinPackageContentModificationListener + + + org.jetbrains.kotlin.idea.completion.CompletionBindingContextProvider + org.jetbrains.kotlin.idea.completion.CompletionBindingContextProvider + + + org.jetbrains.kotlin.idea.configuration.KotlinMigrationProjectComponent + + + org.jetbrains.kotlin.idea.parameterInfo.custom.KotlinCodeHintsModel + + + + + + org.jetbrains.kotlin.idea.PluginStartupComponent + + + + org.jetbrains.kotlin.idea.versions.KotlinUpdatePluginComponent + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.jetbrains.kotlin.idea.intentions.ImportMemberIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ImportAllMembersIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.SpecifyTypeExplicitlyIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.SpecifyTypeExplicitlyInDestructuringAssignmentIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveExplicitTypeIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertToBlockBodyIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.conventionNameCalls.ReplaceContainsIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.conventionNameCalls.ReplaceInvokeIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.conventionNameCalls.ReplaceCallWithUnaryOperatorIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.FoldIfToReturnAsymmetricallyIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.UnfoldAssignmentToIfIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.UnfoldPropertyToIfIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.UnfoldAssignmentToWhenIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.UnfoldPropertyToWhenIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.UnfoldReturnToIfIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.UnfoldReturnToWhenIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.DoubleBangToIfThenIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.ElvisToIfThenIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.SafeAccessToIfThenIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.IfToWhenIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.WhenToIfIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.FlattenWhenIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.EliminateWhenSubjectIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveUnnecessaryParenthesesIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveExplicitTypeArgumentsIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveExplicitSuperQualifierIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.InsertCurlyBracesToTemplateIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.MoveLambdaInsideParenthesesIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.InsertExplicitTypeArgumentsIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.declarations.SplitPropertyDeclarationIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.declarations.ConvertMemberToExtensionIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ReconstructTypeInCastOrIsIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.InfixCallToOrdinaryIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ToInfixCallIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ReplaceExplicitFunctionLiteralParamWithItIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ReplaceItWithExplicitFunctionLiteralParamIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveBracesIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddBracesIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertBinaryExpressionWithDemorgansLawIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.SimplifyBooleanWithConstantsIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddForLoopIndicesIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveForLoopIndicesIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.loopToCallChain.UseWithIndexIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.SwapBinaryExpressionIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.SwapStringEqualsIgnoreCaseIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.SplitIfIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ReplaceWithOrdinaryAssignmentIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.SpecifyExplicitLambdaSignatureIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveExplicitLambdaParameterTypesIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertForEachToForLoopIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertToForEachFunctionCallIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertToStringTemplateIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertToRawStringTemplateIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.OperatorToFunctionIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertToConcatenatedStringIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertFunctionToPropertyIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertPropertyToFunctionIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertReceiverToParameterIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertParameterToReceiverIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertPropertyInitializerToGetterIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.InvertIfConditionIntention + Kotlin + + + + org.jetbrains.kotlin.idea.refactoring.move.changePackage.ChangePackageIntention + Kotlin + + + + org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ExtractDeclarationFromCurrentFileIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ChangeVisibilityModifierIntention$Public + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ChangeVisibilityModifierIntention$Private + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ChangeVisibilityModifierIntention$Protected + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ChangeVisibilityModifierIntention$Internal + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddNameToArgumentIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddNamesToFollowingArgumentsIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ReplaceUnderscoreWithParameterNameIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddJvmOverloadsIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddJvmStaticIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveArgumentNameIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.IterateExpressionIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.UsePropertyAccessSyntaxIntention + Kotlin + + + + org.jetbrains.kotlin.idea.quickfix.AddConstModifierIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.IntroduceBackingPropertyIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.JoinDeclarationAndAssignmentIntention + Kotlin + + + + org.jetbrains.kotlin.idea.testIntegration.KotlinCreateTestIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ObjectLiteralToLambdaIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.DestructureIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AnonymousFunctionToLambdaIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ImplementAbstractMemberIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ImplementAbstractMemberAsConstructorParameterIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddValVarToConstructorParameterAction$Intention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.MoveMemberToCompanionObjectIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.MoveMemberOutOfCompanionObjectIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.CreateKotlinSubClassIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ToRawStringLiteralIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.TrailingCommaIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ToOrdinaryStringLiteralIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.IntroduceVariableIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.IntroduceImportAliasIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveSingleExpressionStringTemplateIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ReplaceUntilWithRangeToIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveEmptyParenthesesFromLambdaCallIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertCamelCaseTestFunctionToSpacedIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertSnakeCaseTestFunctionToSpacedIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.copyConcatenatedStringToClipboard.CopyConcatenatedStringToClipboardIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveConstructorKeywordIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertPrimaryConstructorToSecondaryIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertSecondaryConstructorToPrimaryIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ReplaceSizeCheckWithIsNotEmptyIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ReplaceSizeZeroCheckWithIsEmptyIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveEmptyClassBodyIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertEnumToSealedClassIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertSealedClassToEnumIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveRedundantCallsOfConversionMethodsIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveEmptyPrimaryConstructorIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveEmptySecondaryConstructorBodyIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertTryFinallyToUseCallIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddNamesToCallArgumentsIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertFunctionTypeParameterToReceiverIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertFunctionTypeReceiverToParameterIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertRangeCheckToTwoComparisonsIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RenameFileToMatchClassIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertObjectLiteralToClassIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.MergeIfsIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.MergeElseIfIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddMissingDestructuringIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertToApplyIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertToAlsoIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertToWithIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertToRunIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.MovePropertyToClassBodyIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.MovePropertyToConstructorIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddOpenModifierIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ValToObjectIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ChopParameterListIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ChopArgumentListIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.NullableBooleanEqualityCheckToElvisIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ReplaceAddWithPlusAssignIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddPropertyAccessorsIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddPropertyGetterIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddPropertySetterIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.MoveMemberToTopLevelIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertUnsafeCastCallToUnsafeCastIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertUnsafeCastToUnsafeCastCallIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveLabeledReturnInLambdaIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddLabeledReturnInLambdaIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddAnnotationUseSiteTargetIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.JoinParameterListIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.JoinArgumentListIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertLineCommentToBlockCommentIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertBlockCommentToLineCommentIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.IndentRawStringIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertVarargParameterToArrayIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertArrayParameterToVarargIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.LambdaToAnonymousFunctionIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddWhenRemainingBranchesIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertPropertyGetterToInitializerIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.SamConversionToAnonymousObjectIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.AddThrowsAnnotationIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertNullablePropertyToLateinitIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertLateinitPropertyToNullableIntention + Kotlin + + + + org.jetbrains.kotlin.idea.parameterInfo.custom.DisableReturnLambdaHintOptionAction + + + + org.jetbrains.kotlin.idea.intentions.AddUnderscoresToNumericLiteralIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ReplaceMapGetOrDefaultIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveUnderscoresFromNumericLiteralIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RenameClassToContainingFileNameIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertCollectionConstructorToFunction + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertOrdinaryPropertyToLazyIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertLazyPropertyToOrdinaryIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertLambdaToMultiLineIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertLambdaToSingleLineIntention + Kotlin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/idea/src/org/jetbrains/kotlin/idea/KotlinIdeFileIconProviderService.kt.191 b/idea/src/org/jetbrains/kotlin/idea/KotlinIdeFileIconProviderService.kt.191 new file mode 100644 index 00000000000..4997d39f358 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/KotlinIdeFileIconProviderService.kt.191 @@ -0,0 +1,25 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea + +import com.intellij.openapi.util.IconLoader +import com.intellij.psi.PsiModifierListOwner +import com.intellij.psi.impl.ElementPresentationUtil +import com.intellij.util.PlatformIcons +import javax.swing.Icon + +class KotlinIdeFileIconProviderService : KotlinIconProviderService() { + override fun getFileIcon(): Icon = KOTLIN_FILE + + override fun getLightVariableIcon(element: PsiModifierListOwner, flags: Int): Icon { + val baseIcon = ElementPresentationUtil.createLayeredIcon(PlatformIcons.VARIABLE_ICON, element, false) + return ElementPresentationUtil.addVisibilityIcon(element, flags, baseIcon) + } + + companion object { + private val KOTLIN_FILE = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/kotlin_file.svg") + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/PluginStartupActivity.java.191 b/idea/src/org/jetbrains/kotlin/idea/PluginStartupActivity.java.191 new file mode 100644 index 00000000000..a60f0e72cbb --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/PluginStartupActivity.java.191 @@ -0,0 +1,23 @@ +/* + * Copyright 2010-2020 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. + */ + +package org.jetbrains.kotlin.idea; + + +public class PluginStartupActivity { + + +} diff --git a/idea/src/org/jetbrains/kotlin/idea/PluginStartupActivity.java.192 b/idea/src/org/jetbrains/kotlin/idea/PluginStartupActivity.java.192 new file mode 100644 index 00000000000..a60f0e72cbb --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/PluginStartupActivity.java.192 @@ -0,0 +1,23 @@ +/* + * Copyright 2010-2020 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. + */ + +package org.jetbrains.kotlin.idea; + + +public class PluginStartupActivity { + + +} diff --git a/idea/src/org/jetbrains/kotlin/idea/PluginStartupComponent.java.191 b/idea/src/org/jetbrains/kotlin/idea/PluginStartupComponent.java.191 new file mode 100644 index 00000000000..1f51bfad486 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/PluginStartupComponent.java.191 @@ -0,0 +1,126 @@ +/* + * Copyright 2010-2015 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. + */ + +package org.jetbrains.kotlin.idea; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.PathMacros; +import com.intellij.openapi.components.BaseComponent; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.EditorFactory; +import com.intellij.openapi.editor.event.DocumentEvent; +import com.intellij.openapi.editor.event.DocumentListener; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.updateSettings.impl.UpdateChecker; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.search.searches.IndexPatternSearch; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.idea.reporter.KotlinReportSubmitter; +import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinTodoSearcher; +import org.jetbrains.kotlin.utils.PathUtil; + +import java.io.File; +import java.io.IOException; + +import static org.jetbrains.kotlin.idea.TestResourceBundleKt.registerAdditionalResourceBundleInTests; + +public class PluginStartupComponent implements BaseComponent { + private static final Logger LOG = Logger.getInstance(PluginStartupComponent.class); + + private static final String KOTLIN_BUNDLED = "KOTLIN_BUNDLED"; + + public static PluginStartupComponent getInstance() { + return ApplicationManager.getApplication().getComponent(PluginStartupComponent.class); + } + + @Override + @NotNull + public String getComponentName() { + return PluginStartupComponent.class.getName(); + } + + @Override + public void initComponent() { + if (ApplicationManager.getApplication().isUnitTestMode()) { + registerAdditionalResourceBundleInTests(); + } + + registerPathVariable(); + + try { + // API added in 15.0.2 + UpdateChecker.INSTANCE.getExcludedFromUpdateCheckPlugins().add("org.jetbrains.kotlin"); + } + catch (Throwable throwable) { + LOG.debug("Excluding Kotlin plugin updates using old API", throwable); + UpdateChecker.getDisabledToUpdatePlugins().add("org.jetbrains.kotlin"); + } + EditorFactory.getInstance().getEventMulticaster().addDocumentListener(new DocumentListener() { + @Override + public void documentChanged(@NotNull DocumentEvent e) { + VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(e.getDocument()); + if (virtualFile != null && virtualFile.getFileType() == KotlinFileType.INSTANCE) { + KotlinPluginUpdater.Companion.getInstance().kotlinFileEdited(virtualFile); + } + } + }); + + ServiceManager.getService(IndexPatternSearch.class).registerExecutor(new KotlinTodoSearcher()); + + KotlinPluginCompatibilityVerifier.checkCompatibility(); + + KotlinReportSubmitter.Companion.setupReportingFromRelease(); + + //todo[Sedunov]: wait for fix in platform to avoid misunderstood from Java newbies (also ConfigureKotlinInTempDirTest) + //KotlinSdkType.Companion.setUpIfNeeded(); + } + + private static void registerPathVariable() { + PathMacros macros = PathMacros.getInstance(); + macros.setMacro(KOTLIN_BUNDLED, PathUtil.getKotlinPathsForIdeaPlugin().getHomePath().getPath()); + } + + private String aliveFlagPath; + + public synchronized String getAliveFlagPath() { + if (this.aliveFlagPath == null) { + try { + File flagFile = File.createTempFile("kotlin-idea-", "-is-running"); + flagFile.deleteOnExit(); + this.aliveFlagPath = flagFile.getAbsolutePath(); + } + catch (IOException e) { + this.aliveFlagPath = ""; + } + } + return this.aliveFlagPath; + } + + public synchronized void resetAliveFlag() { + if (this.aliveFlagPath != null) { + File flagFile = new File(this.aliveFlagPath); + if (flagFile.exists()) { + if (flagFile.delete()) { + this.aliveFlagPath = null; + } + } + } + } + + @Override + public void disposeComponent() {} +} diff --git a/idea/src/org/jetbrains/kotlin/idea/PluginStartupComponent.java.192 b/idea/src/org/jetbrains/kotlin/idea/PluginStartupComponent.java.192 new file mode 100644 index 00000000000..1f51bfad486 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/PluginStartupComponent.java.192 @@ -0,0 +1,126 @@ +/* + * Copyright 2010-2015 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. + */ + +package org.jetbrains.kotlin.idea; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.PathMacros; +import com.intellij.openapi.components.BaseComponent; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.EditorFactory; +import com.intellij.openapi.editor.event.DocumentEvent; +import com.intellij.openapi.editor.event.DocumentListener; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.updateSettings.impl.UpdateChecker; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.search.searches.IndexPatternSearch; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.idea.reporter.KotlinReportSubmitter; +import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinTodoSearcher; +import org.jetbrains.kotlin.utils.PathUtil; + +import java.io.File; +import java.io.IOException; + +import static org.jetbrains.kotlin.idea.TestResourceBundleKt.registerAdditionalResourceBundleInTests; + +public class PluginStartupComponent implements BaseComponent { + private static final Logger LOG = Logger.getInstance(PluginStartupComponent.class); + + private static final String KOTLIN_BUNDLED = "KOTLIN_BUNDLED"; + + public static PluginStartupComponent getInstance() { + return ApplicationManager.getApplication().getComponent(PluginStartupComponent.class); + } + + @Override + @NotNull + public String getComponentName() { + return PluginStartupComponent.class.getName(); + } + + @Override + public void initComponent() { + if (ApplicationManager.getApplication().isUnitTestMode()) { + registerAdditionalResourceBundleInTests(); + } + + registerPathVariable(); + + try { + // API added in 15.0.2 + UpdateChecker.INSTANCE.getExcludedFromUpdateCheckPlugins().add("org.jetbrains.kotlin"); + } + catch (Throwable throwable) { + LOG.debug("Excluding Kotlin plugin updates using old API", throwable); + UpdateChecker.getDisabledToUpdatePlugins().add("org.jetbrains.kotlin"); + } + EditorFactory.getInstance().getEventMulticaster().addDocumentListener(new DocumentListener() { + @Override + public void documentChanged(@NotNull DocumentEvent e) { + VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(e.getDocument()); + if (virtualFile != null && virtualFile.getFileType() == KotlinFileType.INSTANCE) { + KotlinPluginUpdater.Companion.getInstance().kotlinFileEdited(virtualFile); + } + } + }); + + ServiceManager.getService(IndexPatternSearch.class).registerExecutor(new KotlinTodoSearcher()); + + KotlinPluginCompatibilityVerifier.checkCompatibility(); + + KotlinReportSubmitter.Companion.setupReportingFromRelease(); + + //todo[Sedunov]: wait for fix in platform to avoid misunderstood from Java newbies (also ConfigureKotlinInTempDirTest) + //KotlinSdkType.Companion.setUpIfNeeded(); + } + + private static void registerPathVariable() { + PathMacros macros = PathMacros.getInstance(); + macros.setMacro(KOTLIN_BUNDLED, PathUtil.getKotlinPathsForIdeaPlugin().getHomePath().getPath()); + } + + private String aliveFlagPath; + + public synchronized String getAliveFlagPath() { + if (this.aliveFlagPath == null) { + try { + File flagFile = File.createTempFile("kotlin-idea-", "-is-running"); + flagFile.deleteOnExit(); + this.aliveFlagPath = flagFile.getAbsolutePath(); + } + catch (IOException e) { + this.aliveFlagPath = ""; + } + } + return this.aliveFlagPath; + } + + public synchronized void resetAliveFlag() { + if (this.aliveFlagPath != null) { + File flagFile = new File(this.aliveFlagPath); + if (flagFile.exists()) { + if (flagFile.delete()) { + this.aliveFlagPath = null; + } + } + } + } + + @Override + public void disposeComponent() {} +} diff --git a/idea/src/org/jetbrains/kotlin/idea/PluginStartupService.java.191 b/idea/src/org/jetbrains/kotlin/idea/PluginStartupService.java.191 new file mode 100644 index 00000000000..9a3ed2b5a68 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/PluginStartupService.java.191 @@ -0,0 +1,27 @@ +/* + * Copyright 2010-2020 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. + */ + +package org.jetbrains.kotlin.idea; + +import com.intellij.openapi.application.ApplicationManager; + +import java.io.File; +import java.io.IOException; + +public class PluginStartupService { + + +} diff --git a/idea/src/org/jetbrains/kotlin/idea/PluginStartupService.java.192 b/idea/src/org/jetbrains/kotlin/idea/PluginStartupService.java.192 new file mode 100644 index 00000000000..9a3ed2b5a68 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/PluginStartupService.java.192 @@ -0,0 +1,27 @@ +/* + * Copyright 2010-2020 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. + */ + +package org.jetbrains.kotlin.idea; + +import com.intellij.openapi.application.ApplicationManager; + +import java.io.File; +import java.io.IOException; + +public class PluginStartupService { + + +} diff --git a/idea/src/org/jetbrains/kotlin/idea/compiler/configuration/KotlinCompilerConfigurableTab.java.191 b/idea/src/org/jetbrains/kotlin/idea/compiler/configuration/KotlinCompilerConfigurableTab.java.191 new file mode 100644 index 00000000000..cf9ade58e29 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/compiler/configuration/KotlinCompilerConfigurableTab.java.191 @@ -0,0 +1,751 @@ +/* + * Copyright 2000-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.compiler.configuration; + +import com.intellij.icons.AllIcons; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.fileChooser.FileChooserDescriptor; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.options.Configurable; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.options.SearchableConfigurable; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.TextComponentAccessor; +import com.intellij.openapi.ui.TextFieldWithBrowseButton; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.ui.ListCellRendererWrapper; +import com.intellij.ui.RawCommandLineEditor; +import com.intellij.util.text.VersionComparatorUtil; +import com.intellij.util.ui.ThreeStateCheckBox; +import com.intellij.util.ui.UIUtil; +import kotlin.collections.ArraysKt; +import kotlin.collections.CollectionsKt; +import kotlin.jvm.functions.Function0; +import kotlin.jvm.functions.Function1; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments; +import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments; +import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments; +import org.jetbrains.kotlin.cli.common.arguments.K2JsArgumentConstants; +import org.jetbrains.kotlin.config.*; +import org.jetbrains.kotlin.idea.KotlinBundle; +import org.jetbrains.kotlin.idea.PluginStartupComponent; +import org.jetbrains.kotlin.idea.facet.DescriptionListCellRenderer; +import org.jetbrains.kotlin.idea.facet.KotlinFacet; +import org.jetbrains.kotlin.idea.project.NewInferenceForIDEAnalysisComponent; +import org.jetbrains.kotlin.idea.roots.RootUtilsKt; +import org.jetbrains.kotlin.idea.util.CidrUtil; +import org.jetbrains.kotlin.idea.util.application.ApplicationUtilsKt; +import org.jetbrains.kotlin.platform.IdePlatformKind; +import org.jetbrains.kotlin.platform.PlatformUtilKt; +import org.jetbrains.kotlin.platform.impl.JsIdePlatformUtil; +import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind; +import org.jetbrains.kotlin.platform.impl.JvmIdePlatformUtil; +import org.jetbrains.kotlin.config.JvmTarget; +import org.jetbrains.kotlin.platform.jvm.JdkPlatform; +import org.jetbrains.kotlin.platform.TargetPlatform; + +import javax.swing.*; +import java.util.*; + +public class KotlinCompilerConfigurableTab implements SearchableConfigurable { + private static final Map moduleKindDescriptions = new LinkedHashMap<>(); + private static final Map soruceMapSourceEmbeddingDescriptions = new LinkedHashMap<>(); + private static final List languageFeatureStates = Arrays.asList( + LanguageFeature.State.ENABLED, LanguageFeature.State.ENABLED_WITH_WARNING, LanguageFeature.State.ENABLED_WITH_ERROR + ); + private static final int MAX_WARNING_SIZE = 75; + + static { + moduleKindDescriptions.put(K2JsArgumentConstants.MODULE_PLAIN, "Plain (put to global scope)"); + moduleKindDescriptions.put(K2JsArgumentConstants.MODULE_AMD, "AMD"); + moduleKindDescriptions.put(K2JsArgumentConstants.MODULE_COMMONJS, "CommonJS"); + moduleKindDescriptions.put(K2JsArgumentConstants.MODULE_UMD, "UMD (detect AMD or CommonJS if available, fallback to plain)"); + + soruceMapSourceEmbeddingDescriptions.put(K2JsArgumentConstants.SOURCE_MAP_SOURCE_CONTENT_NEVER, "Never"); + soruceMapSourceEmbeddingDescriptions.put(K2JsArgumentConstants.SOURCE_MAP_SOURCE_CONTENT_ALWAYS, "Always"); + soruceMapSourceEmbeddingDescriptions.put(K2JsArgumentConstants.SOURCE_MAP_SOURCE_CONTENT_INLINING, + "When inlining a function from other module with embedded sources"); + } + + @Nullable + private final KotlinCompilerWorkspaceSettings compilerWorkspaceSettings; + private final Project project; + private final boolean isProjectSettings; + private CommonCompilerArguments commonCompilerArguments; + private K2JSCompilerArguments k2jsCompilerArguments; + private K2JVMCompilerArguments k2jvmCompilerArguments; + private CompilerSettings compilerSettings; + private JPanel contentPane; + private ThreeStateCheckBox reportWarningsCheckBox; + private RawCommandLineEditor additionalArgsOptionsField; + private JLabel additionalArgsLabel; + private ThreeStateCheckBox generateSourceMapsCheckBox; + private TextFieldWithBrowseButton outputPrefixFile; + private TextFieldWithBrowseButton outputPostfixFile; + private JLabel labelForOutputDirectory; + private TextFieldWithBrowseButton outputDirectory; + private ThreeStateCheckBox copyRuntimeFilesCheckBox; + private ThreeStateCheckBox keepAliveCheckBox; + private JCheckBox enableIncrementalCompilationForJvmCheckBox; + private JCheckBox enableIncrementalCompilationForJsCheckBox; + private JComboBox moduleKindComboBox; + private JTextField scriptTemplatesField; + private JTextField scriptTemplatesClasspathField; + private JLabel scriptTemplatesLabel; + private JLabel scriptTemplatesClasspathLabel; + private JPanel k2jvmPanel; + private JPanel k2jsPanel; + private JComboBox jvmVersionComboBox; + private JComboBox languageVersionComboBox; + private JComboBox coroutineSupportComboBox; + private JComboBox apiVersionComboBox; + private JPanel scriptPanel; + private JLabel labelForOutputPrefixFile; + private JLabel labelForOutputPostfixFile; + private JLabel warningLabel; + private JTextField sourceMapPrefix; + private JLabel labelForSourceMapPrefix; + private JComboBox sourceMapEmbedSources; + private JPanel coroutinesPanel; + private ThreeStateCheckBox enableNewInferenceInIDECheckBox; + private boolean isEnabled = true; + + public KotlinCompilerConfigurableTab( + Project project, + @NotNull CommonCompilerArguments commonCompilerArguments, + @NotNull K2JSCompilerArguments k2jsCompilerArguments, + @NotNull K2JVMCompilerArguments k2jvmCompilerArguments, CompilerSettings compilerSettings, + @Nullable KotlinCompilerWorkspaceSettings compilerWorkspaceSettings, + boolean isProjectSettings, + boolean isMultiEditor + ) { + this.project = project; + this.commonCompilerArguments = commonCompilerArguments; + this.k2jsCompilerArguments = k2jsCompilerArguments; + this.compilerSettings = compilerSettings; + this.compilerWorkspaceSettings = compilerWorkspaceSettings; + this.k2jvmCompilerArguments = k2jvmCompilerArguments; + this.isProjectSettings = isProjectSettings; + + warningLabel.setIcon(AllIcons.General.WarningDialog); + + if (isProjectSettings) { + languageVersionComboBox.addActionListener(e -> onLanguageLevelChanged(getSelectedLanguageVersionView())); + } + + additionalArgsOptionsField.attachLabel(additionalArgsLabel); + + fillLanguageAndAPIVersionList(); + fillCoroutineSupportList(); + + if (CidrUtil.isRunningInCidrIde()) { + keepAliveCheckBox.setVisible(false); + k2jvmPanel.setVisible(false); + k2jsPanel.setVisible(false); + } + else { + initializeNonCidrSettings(isMultiEditor); + } + + reportWarningsCheckBox.setThirdStateEnabled(isMultiEditor); + enableNewInferenceInIDECheckBox.setThirdStateEnabled(isMultiEditor); + + if (isProjectSettings) { + List modulesOverridingProjectSettings = ArraysKt.mapNotNull( + ModuleManager.getInstance(project).getModules(), + module -> { + KotlinFacet facet = KotlinFacet.Companion.get(module); + if (facet == null) return null; + KotlinFacetSettings facetSettings = facet.getConfiguration().getSettings(); + if (facetSettings.getUseProjectSettings()) return null; + return module.getName(); + } + ); + CollectionsKt.sort(modulesOverridingProjectSettings); + if (!modulesOverridingProjectSettings.isEmpty()) { + warningLabel.setVisible(true); + warningLabel.setText(buildOverridingModulesWarning(modulesOverridingProjectSettings)); + } + } + } + + @SuppressWarnings("unused") + public KotlinCompilerConfigurableTab(Project project) { + this(project, + (CommonCompilerArguments) KotlinCommonCompilerArgumentsHolder.Companion.getInstance(project).getSettings().unfrozen(), + (K2JSCompilerArguments) Kotlin2JsCompilerArgumentsHolder.Companion.getInstance(project).getSettings().unfrozen(), + (K2JVMCompilerArguments) Kotlin2JvmCompilerArgumentsHolder.Companion.getInstance(project).getSettings().unfrozen(), + (CompilerSettings) KotlinCompilerSettings.Companion.getInstance(project).getSettings().unfrozen(), + KotlinCompilerWorkspaceSettings.getInstance(project), + true, + false); + } + + private void initializeNonCidrSettings(boolean isMultiEditor) { + setupFileChooser(labelForOutputPrefixFile, outputPrefixFile, + KotlinBundle.message("kotlin.compiler.js.option.output.prefix.browse.title"), + true); + setupFileChooser(labelForOutputPostfixFile, outputPostfixFile, + KotlinBundle.message("kotlin.compiler.js.option.output.postfix.browse.title"), + true); + setupFileChooser(labelForOutputDirectory, outputDirectory, + "Choose Output Directory", + false); + + fillModuleKindList(); + fillSourceMapSourceEmbeddingList(); + fillJvmVersionList(); + + generateSourceMapsCheckBox.setThirdStateEnabled(isMultiEditor); + generateSourceMapsCheckBox.addActionListener(event -> sourceMapPrefix.setEnabled(generateSourceMapsCheckBox.isSelected())); + + copyRuntimeFilesCheckBox.setThirdStateEnabled(isMultiEditor); + keepAliveCheckBox.setThirdStateEnabled(isMultiEditor); + + if (compilerWorkspaceSettings == null) { + keepAliveCheckBox.setVisible(false); + k2jvmPanel.setVisible(false); + enableIncrementalCompilationForJsCheckBox.setVisible(false); + enableNewInferenceInIDECheckBox.setVisible(false); + } + + updateOutputDirEnabled(); + } + + private static int calculateNameCountToShowInWarning(List allNames) { + int lengthSoFar = 0; + int size = allNames.size(); + for (int i = 0; i < size; i++) { + lengthSoFar = (i > 0 ? lengthSoFar + 2 : 0) + allNames.get(i).length(); + if (lengthSoFar > MAX_WARNING_SIZE) return i; + } + return size; + } + + @NotNull + private static String buildOverridingModulesWarning(List modulesOverridingProjectSettings) { + int nameCountToShow = calculateNameCountToShowInWarning(modulesOverridingProjectSettings); + int allNamesCount = modulesOverridingProjectSettings.size(); + if (nameCountToShow == 0) { + return String.valueOf(allNamesCount) + " modules override project settings"; + } + + StringBuilder builder = new StringBuilder(); + builder.append("Following modules override project settings: "); + CollectionsKt.joinTo( + modulesOverridingProjectSettings.subList(0, nameCountToShow), + builder, + ", ", + "", + "", + -1, + "", + new Function1() { + @Override + public CharSequence invoke(String s) { + return "" + s + ""; + } + } + ); + if (nameCountToShow < allNamesCount) { + builder.append(" and ").append(allNamesCount - nameCountToShow).append(" other(s)"); + } + return builder.toString(); + } + + @NotNull + private static String getModuleKindDescription(@Nullable String moduleKind) { + if (moduleKind == null) return ""; + String result = moduleKindDescriptions.get(moduleKind); + assert result != null : "Module kind " + moduleKind + " was not added to combobox, therefore it should not be here"; + return result; + } + + @NotNull + private static String getSourceMapSourceEmbeddingDescription(@Nullable String sourceMapSourceEmbeddingId) { + if (sourceMapSourceEmbeddingId == null) return ""; + String result = soruceMapSourceEmbeddingDescriptions.get(sourceMapSourceEmbeddingId); + assert result != null : "Source map source embedding mode " + sourceMapSourceEmbeddingId + + " was not added to combobox, therefore it should not be here"; + return result; + } + + @NotNull + private static String getModuleKindOrDefault(@Nullable String moduleKindId) { + if (moduleKindId == null) { + moduleKindId = K2JsArgumentConstants.MODULE_PLAIN; + } + return moduleKindId; + } + + @NotNull + private static String getSourceMapSourceEmbeddingOrDefault(@Nullable String sourceMapSourceEmbeddingId) { + if (sourceMapSourceEmbeddingId == null) { + sourceMapSourceEmbeddingId = K2JsArgumentConstants.SOURCE_MAP_SOURCE_CONTENT_INLINING; + } + return sourceMapSourceEmbeddingId; + } + + private static String getJvmVersionOrDefault(@Nullable String jvmVersion) { + return jvmVersion != null ? jvmVersion : JvmTarget.DEFAULT.getDescription(); + } + + private static void setupFileChooser( + @NotNull JLabel label, + @NotNull TextFieldWithBrowseButton fileChooser, + @NotNull String title, + boolean forFiles + ) { + label.setLabelFor(fileChooser); + + fileChooser.addBrowseFolderListener(title, null, null, + new FileChooserDescriptor(forFiles, !forFiles, false, false, false, false), + TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT); + } + + private static boolean isModifiedWithNullize(@NotNull TextFieldWithBrowseButton chooser, @Nullable String currentValue) { + return !StringUtil.equals( + StringUtil.nullize(chooser.getText(), true), + StringUtil.nullize(currentValue, true)); + } + + private static boolean isModified(@NotNull TextFieldWithBrowseButton chooser, @NotNull String currentValue) { + return !StringUtil.equals(chooser.getText(), currentValue); + } + + private void updateOutputDirEnabled() { + if (isEnabled && copyRuntimeFilesCheckBox != null) { + outputDirectory.setEnabled(copyRuntimeFilesCheckBox.isSelected()); + labelForOutputDirectory.setEnabled(copyRuntimeFilesCheckBox.isSelected()); + } + } + + private boolean isLessOrEqual(LanguageVersion version, LanguageVersion upperBound) { + return VersionComparatorUtil.compare(version.getVersionString(), upperBound.getVersionString()) <= 0; + } + + public void onLanguageLevelChanged(VersionView languageLevel) { + restrictAPIVersions(languageLevel); + coroutinesPanel.setVisible(languageLevel.getVersion().compareTo(LanguageVersion.KOTLIN_1_3) < 0); + } + + @SuppressWarnings("unchecked") + private void restrictAPIVersions(VersionView upperBoundView) { + VersionView selectedAPIView = getSelectedAPIVersionView(); + LanguageVersion selectedAPIVersion = selectedAPIView.getVersion(); + LanguageVersion upperBound = upperBoundView.getVersion(); + List permittedAPIVersions = new ArrayList<>(LanguageVersion.values().length + 1); + if (isLessOrEqual(VersionView.LatestStable.INSTANCE.getVersion(), upperBound)) { + permittedAPIVersions.add(VersionView.LatestStable.INSTANCE); + } + ArraysKt.mapNotNullTo( + LanguageVersion.values(), + permittedAPIVersions, + version -> isLessOrEqual(version, upperBound) && !version.isUnsupported() ? new VersionView.Specific(version) : null + ); + apiVersionComboBox.setModel( + new DefaultComboBoxModel(permittedAPIVersions.toArray()) + ); + apiVersionComboBox.setSelectedItem( + VersionComparatorUtil.compare(selectedAPIVersion.getVersionString(), upperBound.getVersionString()) <= 0 + ? selectedAPIView + : upperBoundView + ); + } + + @SuppressWarnings("unchecked") + private void fillJvmVersionList() { + for (TargetPlatform jvm : JvmIdePlatformKind.INSTANCE.getPlatforms()) { + jvmVersionComboBox.addItem(PlatformUtilKt.subplatformOfType(jvm, JdkPlatform.class).getTargetVersion().getDescription()); + } + } + + private void fillLanguageAndAPIVersionList() { + languageVersionComboBox.addItem(VersionView.LatestStable.INSTANCE); + apiVersionComboBox.addItem(VersionView.LatestStable.INSTANCE); + + for (LanguageVersion version : LanguageVersion.values()) { + if (version.isUnsupported() || !version.isStable() && !ApplicationManager.getApplication().isInternal()) { + continue; + } + + VersionView.Specific specificVersion = new VersionView.Specific(version); + languageVersionComboBox.addItem(specificVersion); + apiVersionComboBox.addItem(specificVersion); + } + languageVersionComboBox.setRenderer(new DescriptionListCellRenderer()); + apiVersionComboBox.setRenderer(new DescriptionListCellRenderer()); + } + + @SuppressWarnings("unchecked") + private void fillCoroutineSupportList() { + for (LanguageFeature.State coroutineSupport : languageFeatureStates) { + coroutineSupportComboBox.addItem(coroutineSupport); + } + coroutineSupportComboBox.setRenderer(new DescriptionListCellRenderer()); + } + + public void setTargetPlatform(@Nullable IdePlatformKind targetPlatform) { + k2jsPanel.setVisible(JsIdePlatformUtil.isJavaScript(targetPlatform)); + scriptPanel.setVisible(JvmIdePlatformUtil.isJvm(targetPlatform)); + } + + @SuppressWarnings("unchecked") + private void fillModuleKindList() { + for (String moduleKind : moduleKindDescriptions.keySet()) { + moduleKindComboBox.addItem(moduleKind); + } + moduleKindComboBox.setRenderer(new ListCellRendererWrapper() { + @Override + public void customize(JList list, String value, int index, boolean selected, boolean hasFocus) { + setText(getModuleKindDescription(value)); + } + }); + } + + @SuppressWarnings("unchecked") + private void fillSourceMapSourceEmbeddingList() { + for (String moduleKind : soruceMapSourceEmbeddingDescriptions.keySet()) { + sourceMapEmbedSources.addItem(moduleKind); + } + sourceMapEmbedSources.setRenderer(new ListCellRendererWrapper() { + @Override + public void customize(JList list, String value, int index, boolean selected, boolean hasFocus) { + setText(value != null ? getSourceMapSourceEmbeddingDescription(value) : ""); + } + }); + } + + @NotNull + @Override + public String getId() { + return "project.kotlinCompiler"; + } + + @Nullable + @Override + public Runnable enableSearch(String option) { + return null; + } + + @Nullable + @Override + public JComponent createComponent() { + return contentPane; + } + + @Override + public boolean isModified() { + return isModified(reportWarningsCheckBox, !commonCompilerArguments.getSuppressWarnings()) || + isModified(enableNewInferenceInIDECheckBox, NewInferenceForIDEAnalysisComponent.isEnabled(project)) || + !getSelectedLanguageVersionView().equals(KotlinFacetSettingsKt.getLanguageVersionView(commonCompilerArguments)) || + !getSelectedAPIVersionView().equals(KotlinFacetSettingsKt.getApiVersionView(commonCompilerArguments)) || + !getSelectedCoroutineState().equals(commonCompilerArguments.getCoroutinesState()) || + !additionalArgsOptionsField.getText().equals(compilerSettings.getAdditionalArguments()) || + isModified(scriptTemplatesField, compilerSettings.getScriptTemplates()) || + isModified(scriptTemplatesClasspathField, compilerSettings.getScriptTemplatesClasspath()) || + isModified(copyRuntimeFilesCheckBox, compilerSettings.getCopyJsLibraryFiles()) || + isModified(outputDirectory, compilerSettings.getOutputDirectoryForJsLibraryFiles()) || + + (compilerWorkspaceSettings != null && + (isModified(enableIncrementalCompilationForJvmCheckBox, compilerWorkspaceSettings.getPreciseIncrementalEnabled()) || + isModified(enableIncrementalCompilationForJsCheckBox, compilerWorkspaceSettings.getIncrementalCompilationForJsEnabled()) || + isModified(keepAliveCheckBox, compilerWorkspaceSettings.getEnableDaemon()))) || + + isModified(generateSourceMapsCheckBox, k2jsCompilerArguments.getSourceMap()) || + isModifiedWithNullize(outputPrefixFile, k2jsCompilerArguments.getOutputPrefix()) || + isModifiedWithNullize(outputPostfixFile, k2jsCompilerArguments.getOutputPostfix()) || + !getSelectedModuleKind().equals(getModuleKindOrDefault(k2jsCompilerArguments.getModuleKind())) || + isModified(sourceMapPrefix, StringUtil.notNullize(k2jsCompilerArguments.getSourceMapPrefix())) || + !getSelectedSourceMapSourceEmbedding().equals( + getSourceMapSourceEmbeddingOrDefault(k2jsCompilerArguments.getSourceMapEmbedSources())) || + !getSelectedJvmVersion().equals(getJvmVersionOrDefault(k2jvmCompilerArguments.getJvmTarget())); + } + + @NotNull + private String getSelectedModuleKind() { + return getModuleKindOrDefault((String) moduleKindComboBox.getSelectedItem()); + } + + private String getSelectedSourceMapSourceEmbedding() { + return getSourceMapSourceEmbeddingOrDefault((String) sourceMapEmbedSources.getSelectedItem()); + } + + @NotNull + private String getSelectedJvmVersion() { + return getJvmVersionOrDefault((String) jvmVersionComboBox.getSelectedItem()); + } + + @NotNull + public VersionView getSelectedLanguageVersionView() { + Object item = languageVersionComboBox.getSelectedItem(); + return item != null ? (VersionView) item : VersionView.LatestStable.INSTANCE; + } + + @NotNull + private VersionView getSelectedAPIVersionView() { + Object item = apiVersionComboBox.getSelectedItem(); + return item != null ? (VersionView) item : VersionView.LatestStable.INSTANCE; + } + + @NotNull + private String getSelectedCoroutineState() { + if (getSelectedLanguageVersionView().getVersion().compareTo(LanguageVersion.KOTLIN_1_3) >= 0) { + return CommonCompilerArguments.DEFAULT; + } + + LanguageFeature.State state = (LanguageFeature.State) coroutineSupportComboBox.getSelectedItem(); + if (state == null) return CommonCompilerArguments.DEFAULT; + switch (state) { + case ENABLED: return CommonCompilerArguments.ENABLE; + case ENABLED_WITH_WARNING: return CommonCompilerArguments.WARN; + case ENABLED_WITH_ERROR: return CommonCompilerArguments.ERROR; + default: return CommonCompilerArguments.DEFAULT; + } + } + + public void applyTo( + CommonCompilerArguments commonCompilerArguments, + K2JVMCompilerArguments k2jvmCompilerArguments, + K2JSCompilerArguments k2jsCompilerArguments, + CompilerSettings compilerSettings + ) throws ConfigurationException { + if (isProjectSettings) { + boolean shouldInvalidateCaches = + !getSelectedLanguageVersionView().equals(KotlinFacetSettingsKt.getLanguageVersionView(commonCompilerArguments)) || + !getSelectedAPIVersionView().equals(KotlinFacetSettingsKt.getApiVersionView(commonCompilerArguments)) || + !getSelectedCoroutineState().equals(commonCompilerArguments.getCoroutinesState()) || + !additionalArgsOptionsField.getText().equals(compilerSettings.getAdditionalArguments()) || + enableNewInferenceInIDECheckBox.isSelected() != NewInferenceForIDEAnalysisComponent.isEnabled(project); + + if (shouldInvalidateCaches) { + ApplicationUtilsKt.runWriteAction( + new Function0() { + @Override + public Object invoke() { + RootUtilsKt.invalidateProjectRoots(project); + return null; + } + } + ); + } + } + + commonCompilerArguments.setSuppressWarnings(!reportWarningsCheckBox.isSelected()); + NewInferenceForIDEAnalysisComponent.setEnabled(project, enableNewInferenceInIDECheckBox.isSelected()); + KotlinFacetSettingsKt.setLanguageVersionView(commonCompilerArguments, getSelectedLanguageVersionView()); + KotlinFacetSettingsKt.setApiVersionView(commonCompilerArguments, getSelectedAPIVersionView()); + + commonCompilerArguments.setCoroutinesState(getSelectedCoroutineState()); + + compilerSettings.setAdditionalArguments(additionalArgsOptionsField.getText()); + compilerSettings.setScriptTemplates(scriptTemplatesField.getText()); + compilerSettings.setScriptTemplatesClasspath(scriptTemplatesClasspathField.getText()); + compilerSettings.setCopyJsLibraryFiles(copyRuntimeFilesCheckBox.isSelected()); + compilerSettings.setOutputDirectoryForJsLibraryFiles(outputDirectory.getText()); + + if (compilerWorkspaceSettings != null) { + compilerWorkspaceSettings.setPreciseIncrementalEnabled(enableIncrementalCompilationForJvmCheckBox.isSelected()); + compilerWorkspaceSettings.setIncrementalCompilationForJsEnabled(enableIncrementalCompilationForJsCheckBox.isSelected()); + + boolean oldEnableDaemon = compilerWorkspaceSettings.getEnableDaemon(); + compilerWorkspaceSettings.setEnableDaemon(keepAliveCheckBox.isSelected()); + if (keepAliveCheckBox.isSelected() != oldEnableDaemon) { + PluginStartupComponent.getInstance().resetAliveFlag(); + } + } + + k2jsCompilerArguments.setSourceMap(generateSourceMapsCheckBox.isSelected()); + k2jsCompilerArguments.setOutputPrefix(StringUtil.nullize(outputPrefixFile.getText(), true)); + k2jsCompilerArguments.setOutputPostfix(StringUtil.nullize(outputPostfixFile.getText(), true)); + k2jsCompilerArguments.setModuleKind(getSelectedModuleKind()); + + k2jsCompilerArguments.setSourceMapPrefix(sourceMapPrefix.getText()); + k2jsCompilerArguments.setSourceMapEmbedSources(generateSourceMapsCheckBox.isSelected() ? getSelectedSourceMapSourceEmbedding() : null); + + k2jvmCompilerArguments.setJvmTarget(getSelectedJvmVersion()); + + if (isProjectSettings) { + KotlinCommonCompilerArgumentsHolder.Companion.getInstance(project).setSettings(commonCompilerArguments); + Kotlin2JvmCompilerArgumentsHolder.Companion.getInstance(project).setSettings(k2jvmCompilerArguments); + Kotlin2JsCompilerArgumentsHolder.Companion.getInstance(project).setSettings(k2jsCompilerArguments); + KotlinCompilerSettings.Companion.getInstance(project).setSettings(compilerSettings); + } + + for (ClearBuildStateExtension extension : ClearBuildStateExtension.getExtensions()) { + extension.clearState(project); + } + } + + @Override + public void apply() throws ConfigurationException { + applyTo(commonCompilerArguments, k2jvmCompilerArguments, k2jsCompilerArguments, compilerSettings); + } + + @Override + public void reset() { + reportWarningsCheckBox.setSelected(!commonCompilerArguments.getSuppressWarnings()); + enableNewInferenceInIDECheckBox.setSelected(NewInferenceForIDEAnalysisComponent.isEnabled(project)); + languageVersionComboBox.setSelectedItem(KotlinFacetSettingsKt.getLanguageVersionView(commonCompilerArguments)); + onLanguageLevelChanged(getSelectedLanguageVersionView()); + apiVersionComboBox.setSelectedItem(KotlinFacetSettingsKt.getApiVersionView(commonCompilerArguments)); + coroutineSupportComboBox.setSelectedItem(CoroutineSupport.byCompilerArguments(commonCompilerArguments)); + additionalArgsOptionsField.setText(compilerSettings.getAdditionalArguments()); + scriptTemplatesField.setText(compilerSettings.getScriptTemplates()); + scriptTemplatesClasspathField.setText(compilerSettings.getScriptTemplatesClasspath()); + copyRuntimeFilesCheckBox.setSelected(compilerSettings.getCopyJsLibraryFiles()); + outputDirectory.setText(compilerSettings.getOutputDirectoryForJsLibraryFiles()); + + if (compilerWorkspaceSettings != null) { + enableIncrementalCompilationForJvmCheckBox.setSelected(compilerWorkspaceSettings.getPreciseIncrementalEnabled()); + enableIncrementalCompilationForJsCheckBox.setSelected(compilerWorkspaceSettings.getIncrementalCompilationForJsEnabled()); + keepAliveCheckBox.setSelected(compilerWorkspaceSettings.getEnableDaemon()); + } + + generateSourceMapsCheckBox.setSelected(k2jsCompilerArguments.getSourceMap()); + outputPrefixFile.setText(k2jsCompilerArguments.getOutputPrefix()); + outputPostfixFile.setText(k2jsCompilerArguments.getOutputPostfix()); + + moduleKindComboBox.setSelectedItem(getModuleKindOrDefault(k2jsCompilerArguments.getModuleKind())); + sourceMapPrefix.setText(k2jsCompilerArguments.getSourceMapPrefix()); + sourceMapPrefix.setEnabled(k2jsCompilerArguments.getSourceMap()); + sourceMapEmbedSources.setSelectedItem(getSourceMapSourceEmbeddingOrDefault(k2jsCompilerArguments.getSourceMapEmbedSources())); + + jvmVersionComboBox.setSelectedItem(getJvmVersionOrDefault(k2jvmCompilerArguments.getJvmTarget())); + } + + @Override + public void disposeUIResources() { + } + + @Nls + @Override + public String getDisplayName() { + return "Kotlin Compiler"; + } + + @Nullable + @Override + public String getHelpTopic() { + return "reference.compiler.kotlin"; + } + + public JPanel getContentPane() { + return contentPane; + } + + public ThreeStateCheckBox getReportWarningsCheckBox() { + return reportWarningsCheckBox; + } + + public ThreeStateCheckBox getEnableNewInferenceInIDECheckBox() { + return enableNewInferenceInIDECheckBox; + } + + public RawCommandLineEditor getAdditionalArgsOptionsField() { + return additionalArgsOptionsField; + } + + public ThreeStateCheckBox getGenerateSourceMapsCheckBox() { + return generateSourceMapsCheckBox; + } + + public TextFieldWithBrowseButton getOutputPrefixFile() { + return outputPrefixFile; + } + + public TextFieldWithBrowseButton getOutputPostfixFile() { + return outputPostfixFile; + } + + public TextFieldWithBrowseButton getOutputDirectory() { + return outputDirectory; + } + + public ThreeStateCheckBox getCopyRuntimeFilesCheckBox() { + return copyRuntimeFilesCheckBox; + } + + public ThreeStateCheckBox getKeepAliveCheckBox() { + return keepAliveCheckBox; + } + + public JComboBox getModuleKindComboBox() { + return moduleKindComboBox; + } + + public JTextField getScriptTemplatesField() { + return scriptTemplatesField; + } + + public JTextField getScriptTemplatesClasspathField() { + return scriptTemplatesClasspathField; + } + + public JComboBox getLanguageVersionComboBox() { + return languageVersionComboBox; + } + + public JComboBox getApiVersionComboBox() { + return apiVersionComboBox; + } + + public JComboBox getCoroutineSupportComboBox() { + return coroutineSupportComboBox; + } + + public void setEnabled(boolean value) { + isEnabled = value; + UIUtil.setEnabled(getContentPane(), value, true); + } + + public CommonCompilerArguments getCommonCompilerArguments() { + return commonCompilerArguments; + } + + public void setCommonCompilerArguments(CommonCompilerArguments commonCompilerArguments) { + this.commonCompilerArguments = commonCompilerArguments; + } + + public K2JSCompilerArguments getK2jsCompilerArguments() { + return k2jsCompilerArguments; + } + + public void setK2jsCompilerArguments(K2JSCompilerArguments k2jsCompilerArguments) { + this.k2jsCompilerArguments = k2jsCompilerArguments; + } + + public K2JVMCompilerArguments getK2jvmCompilerArguments() { + return k2jvmCompilerArguments; + } + + public void setK2jvmCompilerArguments(K2JVMCompilerArguments k2jvmCompilerArguments) { + this.k2jvmCompilerArguments = k2jvmCompilerArguments; + } + + public CompilerSettings getCompilerSettings() { + return compilerSettings; + } + + public void setCompilerSettings(CompilerSettings compilerSettings) { + this.compilerSettings = compilerSettings; + } + + private void createUIComponents() { + // Workaround: ThreeStateCheckBox doesn't send suitable notification on state change + // TODO: replace with PropertyChangerListener after fix is available in IDEA + copyRuntimeFilesCheckBox = new ThreeStateCheckBox() { + @Override + public void setState(State state) { + super.setState(state); + updateOutputDirEnabled(); + } + }; + } +} diff --git a/idea/src/org/jetbrains/kotlin/idea/compiler/configuration/KotlinCompilerConfigurableTab.java.192 b/idea/src/org/jetbrains/kotlin/idea/compiler/configuration/KotlinCompilerConfigurableTab.java.192 new file mode 100644 index 00000000000..cf9ade58e29 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/compiler/configuration/KotlinCompilerConfigurableTab.java.192 @@ -0,0 +1,751 @@ +/* + * Copyright 2000-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.compiler.configuration; + +import com.intellij.icons.AllIcons; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.fileChooser.FileChooserDescriptor; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.options.Configurable; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.options.SearchableConfigurable; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.TextComponentAccessor; +import com.intellij.openapi.ui.TextFieldWithBrowseButton; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.ui.ListCellRendererWrapper; +import com.intellij.ui.RawCommandLineEditor; +import com.intellij.util.text.VersionComparatorUtil; +import com.intellij.util.ui.ThreeStateCheckBox; +import com.intellij.util.ui.UIUtil; +import kotlin.collections.ArraysKt; +import kotlin.collections.CollectionsKt; +import kotlin.jvm.functions.Function0; +import kotlin.jvm.functions.Function1; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments; +import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments; +import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments; +import org.jetbrains.kotlin.cli.common.arguments.K2JsArgumentConstants; +import org.jetbrains.kotlin.config.*; +import org.jetbrains.kotlin.idea.KotlinBundle; +import org.jetbrains.kotlin.idea.PluginStartupComponent; +import org.jetbrains.kotlin.idea.facet.DescriptionListCellRenderer; +import org.jetbrains.kotlin.idea.facet.KotlinFacet; +import org.jetbrains.kotlin.idea.project.NewInferenceForIDEAnalysisComponent; +import org.jetbrains.kotlin.idea.roots.RootUtilsKt; +import org.jetbrains.kotlin.idea.util.CidrUtil; +import org.jetbrains.kotlin.idea.util.application.ApplicationUtilsKt; +import org.jetbrains.kotlin.platform.IdePlatformKind; +import org.jetbrains.kotlin.platform.PlatformUtilKt; +import org.jetbrains.kotlin.platform.impl.JsIdePlatformUtil; +import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind; +import org.jetbrains.kotlin.platform.impl.JvmIdePlatformUtil; +import org.jetbrains.kotlin.config.JvmTarget; +import org.jetbrains.kotlin.platform.jvm.JdkPlatform; +import org.jetbrains.kotlin.platform.TargetPlatform; + +import javax.swing.*; +import java.util.*; + +public class KotlinCompilerConfigurableTab implements SearchableConfigurable { + private static final Map moduleKindDescriptions = new LinkedHashMap<>(); + private static final Map soruceMapSourceEmbeddingDescriptions = new LinkedHashMap<>(); + private static final List languageFeatureStates = Arrays.asList( + LanguageFeature.State.ENABLED, LanguageFeature.State.ENABLED_WITH_WARNING, LanguageFeature.State.ENABLED_WITH_ERROR + ); + private static final int MAX_WARNING_SIZE = 75; + + static { + moduleKindDescriptions.put(K2JsArgumentConstants.MODULE_PLAIN, "Plain (put to global scope)"); + moduleKindDescriptions.put(K2JsArgumentConstants.MODULE_AMD, "AMD"); + moduleKindDescriptions.put(K2JsArgumentConstants.MODULE_COMMONJS, "CommonJS"); + moduleKindDescriptions.put(K2JsArgumentConstants.MODULE_UMD, "UMD (detect AMD or CommonJS if available, fallback to plain)"); + + soruceMapSourceEmbeddingDescriptions.put(K2JsArgumentConstants.SOURCE_MAP_SOURCE_CONTENT_NEVER, "Never"); + soruceMapSourceEmbeddingDescriptions.put(K2JsArgumentConstants.SOURCE_MAP_SOURCE_CONTENT_ALWAYS, "Always"); + soruceMapSourceEmbeddingDescriptions.put(K2JsArgumentConstants.SOURCE_MAP_SOURCE_CONTENT_INLINING, + "When inlining a function from other module with embedded sources"); + } + + @Nullable + private final KotlinCompilerWorkspaceSettings compilerWorkspaceSettings; + private final Project project; + private final boolean isProjectSettings; + private CommonCompilerArguments commonCompilerArguments; + private K2JSCompilerArguments k2jsCompilerArguments; + private K2JVMCompilerArguments k2jvmCompilerArguments; + private CompilerSettings compilerSettings; + private JPanel contentPane; + private ThreeStateCheckBox reportWarningsCheckBox; + private RawCommandLineEditor additionalArgsOptionsField; + private JLabel additionalArgsLabel; + private ThreeStateCheckBox generateSourceMapsCheckBox; + private TextFieldWithBrowseButton outputPrefixFile; + private TextFieldWithBrowseButton outputPostfixFile; + private JLabel labelForOutputDirectory; + private TextFieldWithBrowseButton outputDirectory; + private ThreeStateCheckBox copyRuntimeFilesCheckBox; + private ThreeStateCheckBox keepAliveCheckBox; + private JCheckBox enableIncrementalCompilationForJvmCheckBox; + private JCheckBox enableIncrementalCompilationForJsCheckBox; + private JComboBox moduleKindComboBox; + private JTextField scriptTemplatesField; + private JTextField scriptTemplatesClasspathField; + private JLabel scriptTemplatesLabel; + private JLabel scriptTemplatesClasspathLabel; + private JPanel k2jvmPanel; + private JPanel k2jsPanel; + private JComboBox jvmVersionComboBox; + private JComboBox languageVersionComboBox; + private JComboBox coroutineSupportComboBox; + private JComboBox apiVersionComboBox; + private JPanel scriptPanel; + private JLabel labelForOutputPrefixFile; + private JLabel labelForOutputPostfixFile; + private JLabel warningLabel; + private JTextField sourceMapPrefix; + private JLabel labelForSourceMapPrefix; + private JComboBox sourceMapEmbedSources; + private JPanel coroutinesPanel; + private ThreeStateCheckBox enableNewInferenceInIDECheckBox; + private boolean isEnabled = true; + + public KotlinCompilerConfigurableTab( + Project project, + @NotNull CommonCompilerArguments commonCompilerArguments, + @NotNull K2JSCompilerArguments k2jsCompilerArguments, + @NotNull K2JVMCompilerArguments k2jvmCompilerArguments, CompilerSettings compilerSettings, + @Nullable KotlinCompilerWorkspaceSettings compilerWorkspaceSettings, + boolean isProjectSettings, + boolean isMultiEditor + ) { + this.project = project; + this.commonCompilerArguments = commonCompilerArguments; + this.k2jsCompilerArguments = k2jsCompilerArguments; + this.compilerSettings = compilerSettings; + this.compilerWorkspaceSettings = compilerWorkspaceSettings; + this.k2jvmCompilerArguments = k2jvmCompilerArguments; + this.isProjectSettings = isProjectSettings; + + warningLabel.setIcon(AllIcons.General.WarningDialog); + + if (isProjectSettings) { + languageVersionComboBox.addActionListener(e -> onLanguageLevelChanged(getSelectedLanguageVersionView())); + } + + additionalArgsOptionsField.attachLabel(additionalArgsLabel); + + fillLanguageAndAPIVersionList(); + fillCoroutineSupportList(); + + if (CidrUtil.isRunningInCidrIde()) { + keepAliveCheckBox.setVisible(false); + k2jvmPanel.setVisible(false); + k2jsPanel.setVisible(false); + } + else { + initializeNonCidrSettings(isMultiEditor); + } + + reportWarningsCheckBox.setThirdStateEnabled(isMultiEditor); + enableNewInferenceInIDECheckBox.setThirdStateEnabled(isMultiEditor); + + if (isProjectSettings) { + List modulesOverridingProjectSettings = ArraysKt.mapNotNull( + ModuleManager.getInstance(project).getModules(), + module -> { + KotlinFacet facet = KotlinFacet.Companion.get(module); + if (facet == null) return null; + KotlinFacetSettings facetSettings = facet.getConfiguration().getSettings(); + if (facetSettings.getUseProjectSettings()) return null; + return module.getName(); + } + ); + CollectionsKt.sort(modulesOverridingProjectSettings); + if (!modulesOverridingProjectSettings.isEmpty()) { + warningLabel.setVisible(true); + warningLabel.setText(buildOverridingModulesWarning(modulesOverridingProjectSettings)); + } + } + } + + @SuppressWarnings("unused") + public KotlinCompilerConfigurableTab(Project project) { + this(project, + (CommonCompilerArguments) KotlinCommonCompilerArgumentsHolder.Companion.getInstance(project).getSettings().unfrozen(), + (K2JSCompilerArguments) Kotlin2JsCompilerArgumentsHolder.Companion.getInstance(project).getSettings().unfrozen(), + (K2JVMCompilerArguments) Kotlin2JvmCompilerArgumentsHolder.Companion.getInstance(project).getSettings().unfrozen(), + (CompilerSettings) KotlinCompilerSettings.Companion.getInstance(project).getSettings().unfrozen(), + KotlinCompilerWorkspaceSettings.getInstance(project), + true, + false); + } + + private void initializeNonCidrSettings(boolean isMultiEditor) { + setupFileChooser(labelForOutputPrefixFile, outputPrefixFile, + KotlinBundle.message("kotlin.compiler.js.option.output.prefix.browse.title"), + true); + setupFileChooser(labelForOutputPostfixFile, outputPostfixFile, + KotlinBundle.message("kotlin.compiler.js.option.output.postfix.browse.title"), + true); + setupFileChooser(labelForOutputDirectory, outputDirectory, + "Choose Output Directory", + false); + + fillModuleKindList(); + fillSourceMapSourceEmbeddingList(); + fillJvmVersionList(); + + generateSourceMapsCheckBox.setThirdStateEnabled(isMultiEditor); + generateSourceMapsCheckBox.addActionListener(event -> sourceMapPrefix.setEnabled(generateSourceMapsCheckBox.isSelected())); + + copyRuntimeFilesCheckBox.setThirdStateEnabled(isMultiEditor); + keepAliveCheckBox.setThirdStateEnabled(isMultiEditor); + + if (compilerWorkspaceSettings == null) { + keepAliveCheckBox.setVisible(false); + k2jvmPanel.setVisible(false); + enableIncrementalCompilationForJsCheckBox.setVisible(false); + enableNewInferenceInIDECheckBox.setVisible(false); + } + + updateOutputDirEnabled(); + } + + private static int calculateNameCountToShowInWarning(List allNames) { + int lengthSoFar = 0; + int size = allNames.size(); + for (int i = 0; i < size; i++) { + lengthSoFar = (i > 0 ? lengthSoFar + 2 : 0) + allNames.get(i).length(); + if (lengthSoFar > MAX_WARNING_SIZE) return i; + } + return size; + } + + @NotNull + private static String buildOverridingModulesWarning(List modulesOverridingProjectSettings) { + int nameCountToShow = calculateNameCountToShowInWarning(modulesOverridingProjectSettings); + int allNamesCount = modulesOverridingProjectSettings.size(); + if (nameCountToShow == 0) { + return String.valueOf(allNamesCount) + " modules override project settings"; + } + + StringBuilder builder = new StringBuilder(); + builder.append("Following modules override project settings: "); + CollectionsKt.joinTo( + modulesOverridingProjectSettings.subList(0, nameCountToShow), + builder, + ", ", + "", + "", + -1, + "", + new Function1() { + @Override + public CharSequence invoke(String s) { + return "" + s + ""; + } + } + ); + if (nameCountToShow < allNamesCount) { + builder.append(" and ").append(allNamesCount - nameCountToShow).append(" other(s)"); + } + return builder.toString(); + } + + @NotNull + private static String getModuleKindDescription(@Nullable String moduleKind) { + if (moduleKind == null) return ""; + String result = moduleKindDescriptions.get(moduleKind); + assert result != null : "Module kind " + moduleKind + " was not added to combobox, therefore it should not be here"; + return result; + } + + @NotNull + private static String getSourceMapSourceEmbeddingDescription(@Nullable String sourceMapSourceEmbeddingId) { + if (sourceMapSourceEmbeddingId == null) return ""; + String result = soruceMapSourceEmbeddingDescriptions.get(sourceMapSourceEmbeddingId); + assert result != null : "Source map source embedding mode " + sourceMapSourceEmbeddingId + + " was not added to combobox, therefore it should not be here"; + return result; + } + + @NotNull + private static String getModuleKindOrDefault(@Nullable String moduleKindId) { + if (moduleKindId == null) { + moduleKindId = K2JsArgumentConstants.MODULE_PLAIN; + } + return moduleKindId; + } + + @NotNull + private static String getSourceMapSourceEmbeddingOrDefault(@Nullable String sourceMapSourceEmbeddingId) { + if (sourceMapSourceEmbeddingId == null) { + sourceMapSourceEmbeddingId = K2JsArgumentConstants.SOURCE_MAP_SOURCE_CONTENT_INLINING; + } + return sourceMapSourceEmbeddingId; + } + + private static String getJvmVersionOrDefault(@Nullable String jvmVersion) { + return jvmVersion != null ? jvmVersion : JvmTarget.DEFAULT.getDescription(); + } + + private static void setupFileChooser( + @NotNull JLabel label, + @NotNull TextFieldWithBrowseButton fileChooser, + @NotNull String title, + boolean forFiles + ) { + label.setLabelFor(fileChooser); + + fileChooser.addBrowseFolderListener(title, null, null, + new FileChooserDescriptor(forFiles, !forFiles, false, false, false, false), + TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT); + } + + private static boolean isModifiedWithNullize(@NotNull TextFieldWithBrowseButton chooser, @Nullable String currentValue) { + return !StringUtil.equals( + StringUtil.nullize(chooser.getText(), true), + StringUtil.nullize(currentValue, true)); + } + + private static boolean isModified(@NotNull TextFieldWithBrowseButton chooser, @NotNull String currentValue) { + return !StringUtil.equals(chooser.getText(), currentValue); + } + + private void updateOutputDirEnabled() { + if (isEnabled && copyRuntimeFilesCheckBox != null) { + outputDirectory.setEnabled(copyRuntimeFilesCheckBox.isSelected()); + labelForOutputDirectory.setEnabled(copyRuntimeFilesCheckBox.isSelected()); + } + } + + private boolean isLessOrEqual(LanguageVersion version, LanguageVersion upperBound) { + return VersionComparatorUtil.compare(version.getVersionString(), upperBound.getVersionString()) <= 0; + } + + public void onLanguageLevelChanged(VersionView languageLevel) { + restrictAPIVersions(languageLevel); + coroutinesPanel.setVisible(languageLevel.getVersion().compareTo(LanguageVersion.KOTLIN_1_3) < 0); + } + + @SuppressWarnings("unchecked") + private void restrictAPIVersions(VersionView upperBoundView) { + VersionView selectedAPIView = getSelectedAPIVersionView(); + LanguageVersion selectedAPIVersion = selectedAPIView.getVersion(); + LanguageVersion upperBound = upperBoundView.getVersion(); + List permittedAPIVersions = new ArrayList<>(LanguageVersion.values().length + 1); + if (isLessOrEqual(VersionView.LatestStable.INSTANCE.getVersion(), upperBound)) { + permittedAPIVersions.add(VersionView.LatestStable.INSTANCE); + } + ArraysKt.mapNotNullTo( + LanguageVersion.values(), + permittedAPIVersions, + version -> isLessOrEqual(version, upperBound) && !version.isUnsupported() ? new VersionView.Specific(version) : null + ); + apiVersionComboBox.setModel( + new DefaultComboBoxModel(permittedAPIVersions.toArray()) + ); + apiVersionComboBox.setSelectedItem( + VersionComparatorUtil.compare(selectedAPIVersion.getVersionString(), upperBound.getVersionString()) <= 0 + ? selectedAPIView + : upperBoundView + ); + } + + @SuppressWarnings("unchecked") + private void fillJvmVersionList() { + for (TargetPlatform jvm : JvmIdePlatformKind.INSTANCE.getPlatforms()) { + jvmVersionComboBox.addItem(PlatformUtilKt.subplatformOfType(jvm, JdkPlatform.class).getTargetVersion().getDescription()); + } + } + + private void fillLanguageAndAPIVersionList() { + languageVersionComboBox.addItem(VersionView.LatestStable.INSTANCE); + apiVersionComboBox.addItem(VersionView.LatestStable.INSTANCE); + + for (LanguageVersion version : LanguageVersion.values()) { + if (version.isUnsupported() || !version.isStable() && !ApplicationManager.getApplication().isInternal()) { + continue; + } + + VersionView.Specific specificVersion = new VersionView.Specific(version); + languageVersionComboBox.addItem(specificVersion); + apiVersionComboBox.addItem(specificVersion); + } + languageVersionComboBox.setRenderer(new DescriptionListCellRenderer()); + apiVersionComboBox.setRenderer(new DescriptionListCellRenderer()); + } + + @SuppressWarnings("unchecked") + private void fillCoroutineSupportList() { + for (LanguageFeature.State coroutineSupport : languageFeatureStates) { + coroutineSupportComboBox.addItem(coroutineSupport); + } + coroutineSupportComboBox.setRenderer(new DescriptionListCellRenderer()); + } + + public void setTargetPlatform(@Nullable IdePlatformKind targetPlatform) { + k2jsPanel.setVisible(JsIdePlatformUtil.isJavaScript(targetPlatform)); + scriptPanel.setVisible(JvmIdePlatformUtil.isJvm(targetPlatform)); + } + + @SuppressWarnings("unchecked") + private void fillModuleKindList() { + for (String moduleKind : moduleKindDescriptions.keySet()) { + moduleKindComboBox.addItem(moduleKind); + } + moduleKindComboBox.setRenderer(new ListCellRendererWrapper() { + @Override + public void customize(JList list, String value, int index, boolean selected, boolean hasFocus) { + setText(getModuleKindDescription(value)); + } + }); + } + + @SuppressWarnings("unchecked") + private void fillSourceMapSourceEmbeddingList() { + for (String moduleKind : soruceMapSourceEmbeddingDescriptions.keySet()) { + sourceMapEmbedSources.addItem(moduleKind); + } + sourceMapEmbedSources.setRenderer(new ListCellRendererWrapper() { + @Override + public void customize(JList list, String value, int index, boolean selected, boolean hasFocus) { + setText(value != null ? getSourceMapSourceEmbeddingDescription(value) : ""); + } + }); + } + + @NotNull + @Override + public String getId() { + return "project.kotlinCompiler"; + } + + @Nullable + @Override + public Runnable enableSearch(String option) { + return null; + } + + @Nullable + @Override + public JComponent createComponent() { + return contentPane; + } + + @Override + public boolean isModified() { + return isModified(reportWarningsCheckBox, !commonCompilerArguments.getSuppressWarnings()) || + isModified(enableNewInferenceInIDECheckBox, NewInferenceForIDEAnalysisComponent.isEnabled(project)) || + !getSelectedLanguageVersionView().equals(KotlinFacetSettingsKt.getLanguageVersionView(commonCompilerArguments)) || + !getSelectedAPIVersionView().equals(KotlinFacetSettingsKt.getApiVersionView(commonCompilerArguments)) || + !getSelectedCoroutineState().equals(commonCompilerArguments.getCoroutinesState()) || + !additionalArgsOptionsField.getText().equals(compilerSettings.getAdditionalArguments()) || + isModified(scriptTemplatesField, compilerSettings.getScriptTemplates()) || + isModified(scriptTemplatesClasspathField, compilerSettings.getScriptTemplatesClasspath()) || + isModified(copyRuntimeFilesCheckBox, compilerSettings.getCopyJsLibraryFiles()) || + isModified(outputDirectory, compilerSettings.getOutputDirectoryForJsLibraryFiles()) || + + (compilerWorkspaceSettings != null && + (isModified(enableIncrementalCompilationForJvmCheckBox, compilerWorkspaceSettings.getPreciseIncrementalEnabled()) || + isModified(enableIncrementalCompilationForJsCheckBox, compilerWorkspaceSettings.getIncrementalCompilationForJsEnabled()) || + isModified(keepAliveCheckBox, compilerWorkspaceSettings.getEnableDaemon()))) || + + isModified(generateSourceMapsCheckBox, k2jsCompilerArguments.getSourceMap()) || + isModifiedWithNullize(outputPrefixFile, k2jsCompilerArguments.getOutputPrefix()) || + isModifiedWithNullize(outputPostfixFile, k2jsCompilerArguments.getOutputPostfix()) || + !getSelectedModuleKind().equals(getModuleKindOrDefault(k2jsCompilerArguments.getModuleKind())) || + isModified(sourceMapPrefix, StringUtil.notNullize(k2jsCompilerArguments.getSourceMapPrefix())) || + !getSelectedSourceMapSourceEmbedding().equals( + getSourceMapSourceEmbeddingOrDefault(k2jsCompilerArguments.getSourceMapEmbedSources())) || + !getSelectedJvmVersion().equals(getJvmVersionOrDefault(k2jvmCompilerArguments.getJvmTarget())); + } + + @NotNull + private String getSelectedModuleKind() { + return getModuleKindOrDefault((String) moduleKindComboBox.getSelectedItem()); + } + + private String getSelectedSourceMapSourceEmbedding() { + return getSourceMapSourceEmbeddingOrDefault((String) sourceMapEmbedSources.getSelectedItem()); + } + + @NotNull + private String getSelectedJvmVersion() { + return getJvmVersionOrDefault((String) jvmVersionComboBox.getSelectedItem()); + } + + @NotNull + public VersionView getSelectedLanguageVersionView() { + Object item = languageVersionComboBox.getSelectedItem(); + return item != null ? (VersionView) item : VersionView.LatestStable.INSTANCE; + } + + @NotNull + private VersionView getSelectedAPIVersionView() { + Object item = apiVersionComboBox.getSelectedItem(); + return item != null ? (VersionView) item : VersionView.LatestStable.INSTANCE; + } + + @NotNull + private String getSelectedCoroutineState() { + if (getSelectedLanguageVersionView().getVersion().compareTo(LanguageVersion.KOTLIN_1_3) >= 0) { + return CommonCompilerArguments.DEFAULT; + } + + LanguageFeature.State state = (LanguageFeature.State) coroutineSupportComboBox.getSelectedItem(); + if (state == null) return CommonCompilerArguments.DEFAULT; + switch (state) { + case ENABLED: return CommonCompilerArguments.ENABLE; + case ENABLED_WITH_WARNING: return CommonCompilerArguments.WARN; + case ENABLED_WITH_ERROR: return CommonCompilerArguments.ERROR; + default: return CommonCompilerArguments.DEFAULT; + } + } + + public void applyTo( + CommonCompilerArguments commonCompilerArguments, + K2JVMCompilerArguments k2jvmCompilerArguments, + K2JSCompilerArguments k2jsCompilerArguments, + CompilerSettings compilerSettings + ) throws ConfigurationException { + if (isProjectSettings) { + boolean shouldInvalidateCaches = + !getSelectedLanguageVersionView().equals(KotlinFacetSettingsKt.getLanguageVersionView(commonCompilerArguments)) || + !getSelectedAPIVersionView().equals(KotlinFacetSettingsKt.getApiVersionView(commonCompilerArguments)) || + !getSelectedCoroutineState().equals(commonCompilerArguments.getCoroutinesState()) || + !additionalArgsOptionsField.getText().equals(compilerSettings.getAdditionalArguments()) || + enableNewInferenceInIDECheckBox.isSelected() != NewInferenceForIDEAnalysisComponent.isEnabled(project); + + if (shouldInvalidateCaches) { + ApplicationUtilsKt.runWriteAction( + new Function0() { + @Override + public Object invoke() { + RootUtilsKt.invalidateProjectRoots(project); + return null; + } + } + ); + } + } + + commonCompilerArguments.setSuppressWarnings(!reportWarningsCheckBox.isSelected()); + NewInferenceForIDEAnalysisComponent.setEnabled(project, enableNewInferenceInIDECheckBox.isSelected()); + KotlinFacetSettingsKt.setLanguageVersionView(commonCompilerArguments, getSelectedLanguageVersionView()); + KotlinFacetSettingsKt.setApiVersionView(commonCompilerArguments, getSelectedAPIVersionView()); + + commonCompilerArguments.setCoroutinesState(getSelectedCoroutineState()); + + compilerSettings.setAdditionalArguments(additionalArgsOptionsField.getText()); + compilerSettings.setScriptTemplates(scriptTemplatesField.getText()); + compilerSettings.setScriptTemplatesClasspath(scriptTemplatesClasspathField.getText()); + compilerSettings.setCopyJsLibraryFiles(copyRuntimeFilesCheckBox.isSelected()); + compilerSettings.setOutputDirectoryForJsLibraryFiles(outputDirectory.getText()); + + if (compilerWorkspaceSettings != null) { + compilerWorkspaceSettings.setPreciseIncrementalEnabled(enableIncrementalCompilationForJvmCheckBox.isSelected()); + compilerWorkspaceSettings.setIncrementalCompilationForJsEnabled(enableIncrementalCompilationForJsCheckBox.isSelected()); + + boolean oldEnableDaemon = compilerWorkspaceSettings.getEnableDaemon(); + compilerWorkspaceSettings.setEnableDaemon(keepAliveCheckBox.isSelected()); + if (keepAliveCheckBox.isSelected() != oldEnableDaemon) { + PluginStartupComponent.getInstance().resetAliveFlag(); + } + } + + k2jsCompilerArguments.setSourceMap(generateSourceMapsCheckBox.isSelected()); + k2jsCompilerArguments.setOutputPrefix(StringUtil.nullize(outputPrefixFile.getText(), true)); + k2jsCompilerArguments.setOutputPostfix(StringUtil.nullize(outputPostfixFile.getText(), true)); + k2jsCompilerArguments.setModuleKind(getSelectedModuleKind()); + + k2jsCompilerArguments.setSourceMapPrefix(sourceMapPrefix.getText()); + k2jsCompilerArguments.setSourceMapEmbedSources(generateSourceMapsCheckBox.isSelected() ? getSelectedSourceMapSourceEmbedding() : null); + + k2jvmCompilerArguments.setJvmTarget(getSelectedJvmVersion()); + + if (isProjectSettings) { + KotlinCommonCompilerArgumentsHolder.Companion.getInstance(project).setSettings(commonCompilerArguments); + Kotlin2JvmCompilerArgumentsHolder.Companion.getInstance(project).setSettings(k2jvmCompilerArguments); + Kotlin2JsCompilerArgumentsHolder.Companion.getInstance(project).setSettings(k2jsCompilerArguments); + KotlinCompilerSettings.Companion.getInstance(project).setSettings(compilerSettings); + } + + for (ClearBuildStateExtension extension : ClearBuildStateExtension.getExtensions()) { + extension.clearState(project); + } + } + + @Override + public void apply() throws ConfigurationException { + applyTo(commonCompilerArguments, k2jvmCompilerArguments, k2jsCompilerArguments, compilerSettings); + } + + @Override + public void reset() { + reportWarningsCheckBox.setSelected(!commonCompilerArguments.getSuppressWarnings()); + enableNewInferenceInIDECheckBox.setSelected(NewInferenceForIDEAnalysisComponent.isEnabled(project)); + languageVersionComboBox.setSelectedItem(KotlinFacetSettingsKt.getLanguageVersionView(commonCompilerArguments)); + onLanguageLevelChanged(getSelectedLanguageVersionView()); + apiVersionComboBox.setSelectedItem(KotlinFacetSettingsKt.getApiVersionView(commonCompilerArguments)); + coroutineSupportComboBox.setSelectedItem(CoroutineSupport.byCompilerArguments(commonCompilerArguments)); + additionalArgsOptionsField.setText(compilerSettings.getAdditionalArguments()); + scriptTemplatesField.setText(compilerSettings.getScriptTemplates()); + scriptTemplatesClasspathField.setText(compilerSettings.getScriptTemplatesClasspath()); + copyRuntimeFilesCheckBox.setSelected(compilerSettings.getCopyJsLibraryFiles()); + outputDirectory.setText(compilerSettings.getOutputDirectoryForJsLibraryFiles()); + + if (compilerWorkspaceSettings != null) { + enableIncrementalCompilationForJvmCheckBox.setSelected(compilerWorkspaceSettings.getPreciseIncrementalEnabled()); + enableIncrementalCompilationForJsCheckBox.setSelected(compilerWorkspaceSettings.getIncrementalCompilationForJsEnabled()); + keepAliveCheckBox.setSelected(compilerWorkspaceSettings.getEnableDaemon()); + } + + generateSourceMapsCheckBox.setSelected(k2jsCompilerArguments.getSourceMap()); + outputPrefixFile.setText(k2jsCompilerArguments.getOutputPrefix()); + outputPostfixFile.setText(k2jsCompilerArguments.getOutputPostfix()); + + moduleKindComboBox.setSelectedItem(getModuleKindOrDefault(k2jsCompilerArguments.getModuleKind())); + sourceMapPrefix.setText(k2jsCompilerArguments.getSourceMapPrefix()); + sourceMapPrefix.setEnabled(k2jsCompilerArguments.getSourceMap()); + sourceMapEmbedSources.setSelectedItem(getSourceMapSourceEmbeddingOrDefault(k2jsCompilerArguments.getSourceMapEmbedSources())); + + jvmVersionComboBox.setSelectedItem(getJvmVersionOrDefault(k2jvmCompilerArguments.getJvmTarget())); + } + + @Override + public void disposeUIResources() { + } + + @Nls + @Override + public String getDisplayName() { + return "Kotlin Compiler"; + } + + @Nullable + @Override + public String getHelpTopic() { + return "reference.compiler.kotlin"; + } + + public JPanel getContentPane() { + return contentPane; + } + + public ThreeStateCheckBox getReportWarningsCheckBox() { + return reportWarningsCheckBox; + } + + public ThreeStateCheckBox getEnableNewInferenceInIDECheckBox() { + return enableNewInferenceInIDECheckBox; + } + + public RawCommandLineEditor getAdditionalArgsOptionsField() { + return additionalArgsOptionsField; + } + + public ThreeStateCheckBox getGenerateSourceMapsCheckBox() { + return generateSourceMapsCheckBox; + } + + public TextFieldWithBrowseButton getOutputPrefixFile() { + return outputPrefixFile; + } + + public TextFieldWithBrowseButton getOutputPostfixFile() { + return outputPostfixFile; + } + + public TextFieldWithBrowseButton getOutputDirectory() { + return outputDirectory; + } + + public ThreeStateCheckBox getCopyRuntimeFilesCheckBox() { + return copyRuntimeFilesCheckBox; + } + + public ThreeStateCheckBox getKeepAliveCheckBox() { + return keepAliveCheckBox; + } + + public JComboBox getModuleKindComboBox() { + return moduleKindComboBox; + } + + public JTextField getScriptTemplatesField() { + return scriptTemplatesField; + } + + public JTextField getScriptTemplatesClasspathField() { + return scriptTemplatesClasspathField; + } + + public JComboBox getLanguageVersionComboBox() { + return languageVersionComboBox; + } + + public JComboBox getApiVersionComboBox() { + return apiVersionComboBox; + } + + public JComboBox getCoroutineSupportComboBox() { + return coroutineSupportComboBox; + } + + public void setEnabled(boolean value) { + isEnabled = value; + UIUtil.setEnabled(getContentPane(), value, true); + } + + public CommonCompilerArguments getCommonCompilerArguments() { + return commonCompilerArguments; + } + + public void setCommonCompilerArguments(CommonCompilerArguments commonCompilerArguments) { + this.commonCompilerArguments = commonCompilerArguments; + } + + public K2JSCompilerArguments getK2jsCompilerArguments() { + return k2jsCompilerArguments; + } + + public void setK2jsCompilerArguments(K2JSCompilerArguments k2jsCompilerArguments) { + this.k2jsCompilerArguments = k2jsCompilerArguments; + } + + public K2JVMCompilerArguments getK2jvmCompilerArguments() { + return k2jvmCompilerArguments; + } + + public void setK2jvmCompilerArguments(K2JVMCompilerArguments k2jvmCompilerArguments) { + this.k2jvmCompilerArguments = k2jvmCompilerArguments; + } + + public CompilerSettings getCompilerSettings() { + return compilerSettings; + } + + public void setCompilerSettings(CompilerSettings compilerSettings) { + this.compilerSettings = compilerSettings; + } + + private void createUIComponents() { + // Workaround: ThreeStateCheckBox doesn't send suitable notification on state change + // TODO: replace with PropertyChangerListener after fix is available in IDEA + copyRuntimeFilesCheckBox = new ThreeStateCheckBox() { + @Override + public void setState(State state) { + super.setState(state); + updateOutputDirEnabled(); + } + }; + } +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/hierarchy/AbstractHierarchyTest.java.191 b/idea/tests/org/jetbrains/kotlin/idea/hierarchy/AbstractHierarchyTest.java.191 new file mode 100644 index 00000000000..45dac8de527 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/hierarchy/AbstractHierarchyTest.java.191 @@ -0,0 +1,252 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.hierarchy; + +import com.intellij.ide.hierarchy.*; +import com.intellij.ide.hierarchy.actions.BrowseHierarchyActionBase; +import com.intellij.ide.hierarchy.call.CallerMethodsTreeStructure; +import com.intellij.ide.hierarchy.type.SubtypesHierarchyTreeStructure; +import com.intellij.ide.hierarchy.type.SupertypesHierarchyTreeStructure; +import com.intellij.ide.hierarchy.type.TypeHierarchyTreeStructure; +import com.intellij.lang.LanguageExtension; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.fileEditor.impl.text.TextEditorPsiDataProvider; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.psi.*; +import com.intellij.refactoring.util.CommonRefactoringUtil.RefactoringErrorHintException; +import com.intellij.rt.execution.junit.ComparisonDetailsExtractor; +import com.intellij.testFramework.LightProjectDescriptor; +import com.intellij.testFramework.MapDataContext; +import com.intellij.util.ArrayUtil; +import com.intellij.util.Processor; +import junit.framework.ComparisonFailure; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.idea.KotlinHierarchyViewTestBase; +import org.jetbrains.kotlin.idea.hierarchy.calls.KotlinCalleeTreeStructure; +import org.jetbrains.kotlin.idea.hierarchy.calls.KotlinCallerTreeStructure; +import org.jetbrains.kotlin.idea.hierarchy.overrides.KotlinOverrideTreeStructure; +import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor; +import org.jetbrains.kotlin.psi.KtCallableDeclaration; +import org.jetbrains.kotlin.psi.KtElement; +import org.jetbrains.kotlin.test.KotlinTestUtils; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/* +Test Hierarchy view +Format: test build hierarchy for element at caret, file with caret should be the first in the sorted list of files. +Test accept more than one file, file extension should be .java or .kt + */ +public abstract class AbstractHierarchyTest extends KotlinHierarchyViewTestBase { + + protected String folderName; + + protected void doTypeClassHierarchyTest(@NotNull String folderName) throws Exception { + this.folderName = folderName; + doHierarchyTest(getTypeHierarchyStructure(), getFilesToConfigure()); + } + + protected void doSuperClassHierarchyTest(@NotNull String folderName) throws Exception { + this.folderName = folderName; + doHierarchyTest(getSuperTypesHierarchyStructure(), getFilesToConfigure()); + } + + protected void doSubClassHierarchyTest(@NotNull String folderName) throws Exception { + this.folderName = folderName; + doHierarchyTest(getSubTypesHierarchyStructure(), getFilesToConfigure()); + } + + protected void doCallerHierarchyTest(@NotNull String folderName) throws Exception { + this.folderName = folderName; + doHierarchyTest(getCallerHierarchyStructure(), getFilesToConfigure()); + } + + protected void doCallerJavaHierarchyTest(@NotNull String folderName) throws Exception { + this.folderName = folderName; + doHierarchyTest(getCallerJavaHierarchyStructure(), getFilesToConfigure()); + } + + protected void doCalleeHierarchyTest(@NotNull String folderName) throws Exception { + this.folderName = folderName; + doHierarchyTest(getCalleeHierarchyStructure(), getFilesToConfigure()); + } + + protected void doOverrideHierarchyTest(@NotNull String folderName) throws Exception { + this.folderName = folderName; + doHierarchyTest(getOverrideHierarchyStructure(), getFilesToConfigure()); + } + + private Computable getSuperTypesHierarchyStructure() { + return new Computable() { + @Override + public HierarchyTreeStructure compute() { + return new SupertypesHierarchyTreeStructure( + getProject(), + (PsiClass) getElementAtCaret(LanguageTypeHierarchy.INSTANCE) + ); + } + }; + } + + private Computable getSubTypesHierarchyStructure() { + return new Computable() { + @Override + public HierarchyTreeStructure compute() { + return new SubtypesHierarchyTreeStructure( + getProject(), + (PsiClass) getElementAtCaret(LanguageTypeHierarchy.INSTANCE), + HierarchyBrowserBaseEx.SCOPE_PROJECT + ); + } + }; + } + + private Computable getTypeHierarchyStructure() { + return new Computable() { + @Override + public HierarchyTreeStructure compute() { + return new TypeHierarchyTreeStructure( + getProject(), + (PsiClass) getElementAtCaret(LanguageTypeHierarchy.INSTANCE), + HierarchyBrowserBaseEx.SCOPE_PROJECT + ); + } + }; + } + + private Computable getCallerHierarchyStructure() { + return new Computable() { + @Override + public HierarchyTreeStructure compute() { + return new KotlinCallerTreeStructure( + (KtElement) getElementAtCaret(LanguageCallHierarchy.INSTANCE), + HierarchyBrowserBaseEx.SCOPE_PROJECT + ); + } + }; + } + + private Computable getCallerJavaHierarchyStructure() { + return new Computable() { + @Override + public HierarchyTreeStructure compute() { + return new CallerMethodsTreeStructure( + getProject(), + (PsiMethod) getElementAtCaret(LanguageCallHierarchy.INSTANCE), + HierarchyBrowserBaseEx.SCOPE_PROJECT + ); + } + }; + } + + private Computable getCalleeHierarchyStructure() { + return new Computable() { + @Override + public HierarchyTreeStructure compute() { + return new KotlinCalleeTreeStructure( + (KtElement) getElementAtCaret(LanguageCallHierarchy.INSTANCE), + HierarchyBrowserBaseEx.SCOPE_PROJECT + ); + } + }; + } + + private Computable getOverrideHierarchyStructure() { + return new Computable() { + @Override + public HierarchyTreeStructure compute() { + return new KotlinOverrideTreeStructure( + getProject(), + (KtCallableDeclaration) getElementAtCaret(LanguageMethodHierarchy.INSTANCE) + ); + } + }; + } + + private PsiElement getElementAtCaret(LanguageExtension extension) { + PsiFile file = PsiDocumentManager.getInstance(getProject()).getPsiFile(getEditor().getDocument()); + HierarchyProvider provider = BrowseHierarchyActionBase.findProvider(extension, file, file, getDataContext()); + PsiElement target = provider != null ? provider.getTarget(getDataContext()) : null; + if (target == null) throw new RefactoringErrorHintException("Cannot apply action for element at caret"); + return target; + } + + private DataContext getDataContext() { + Editor editor = getEditor(); + + MapDataContext context = new MapDataContext(); + context.put(CommonDataKeys.PROJECT, getProject()); + context.put(CommonDataKeys.EDITOR, editor); + PsiElement targetElement = (PsiElement) new TextEditorPsiDataProvider().getData( + CommonDataKeys.PSI_ELEMENT.getName(), + editor, + editor.getCaretModel().getCurrentCaret() + ); + context.put(CommonDataKeys.PSI_ELEMENT, targetElement); + return context; + } + + protected String[] getFilesToConfigure() { + final List files = new ArrayList(2); + FileUtil.processFilesRecursively(new File(folderName), new Processor() { + @Override + public boolean process(File file) { + String fileName = file.getName(); + if (fileName.endsWith(".kt") || fileName.endsWith(".java")) { + files.add(fileName); + } + return true; + } + }); + Collections.sort(files); + return ArrayUtil.toStringArray(files); + } + + @Override + protected void doHierarchyTest( + @NotNull Computable treeStructureComputable, @NotNull String... fileNames + ) throws Exception { + try { + super.doHierarchyTest(treeStructureComputable, fileNames); + } + catch (RefactoringErrorHintException e) { + File file = new File(folderName, "messages.txt"); + if (file.exists()) { + String expectedMessage = FileUtil.loadFile(file, true); + assertEquals(expectedMessage, e.getLocalizedMessage()); + } + else { + fail("Unexpected error: " + e.getLocalizedMessage()); + } + } + catch (ComparisonFailure failure) { + String actual = ComparisonDetailsExtractor.getActual(failure); + String verificationFilePath = + getTestDataPath() + "/" + getTestName(false) + "_verification.xml"; + KotlinTestUtils.assertEqualsToFile(new File(verificationFilePath), actual); + } + } + + @Override + @NotNull + protected LightProjectDescriptor getProjectDescriptor() { + return KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE; + } + + @NotNull + @Override + protected String getTestDataPath() { + String testRoot = super.getTestDataPath(); + String testDir = KotlinTestUtils.getTestDataFileName(this.getClass(), getName()); + return testRoot + "/" + testDir; + } +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/hierarchy/AbstractHierarchyTest.java.192 b/idea/tests/org/jetbrains/kotlin/idea/hierarchy/AbstractHierarchyTest.java.192 new file mode 100644 index 00000000000..45dac8de527 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/hierarchy/AbstractHierarchyTest.java.192 @@ -0,0 +1,252 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.hierarchy; + +import com.intellij.ide.hierarchy.*; +import com.intellij.ide.hierarchy.actions.BrowseHierarchyActionBase; +import com.intellij.ide.hierarchy.call.CallerMethodsTreeStructure; +import com.intellij.ide.hierarchy.type.SubtypesHierarchyTreeStructure; +import com.intellij.ide.hierarchy.type.SupertypesHierarchyTreeStructure; +import com.intellij.ide.hierarchy.type.TypeHierarchyTreeStructure; +import com.intellij.lang.LanguageExtension; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.fileEditor.impl.text.TextEditorPsiDataProvider; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.psi.*; +import com.intellij.refactoring.util.CommonRefactoringUtil.RefactoringErrorHintException; +import com.intellij.rt.execution.junit.ComparisonDetailsExtractor; +import com.intellij.testFramework.LightProjectDescriptor; +import com.intellij.testFramework.MapDataContext; +import com.intellij.util.ArrayUtil; +import com.intellij.util.Processor; +import junit.framework.ComparisonFailure; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.idea.KotlinHierarchyViewTestBase; +import org.jetbrains.kotlin.idea.hierarchy.calls.KotlinCalleeTreeStructure; +import org.jetbrains.kotlin.idea.hierarchy.calls.KotlinCallerTreeStructure; +import org.jetbrains.kotlin.idea.hierarchy.overrides.KotlinOverrideTreeStructure; +import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor; +import org.jetbrains.kotlin.psi.KtCallableDeclaration; +import org.jetbrains.kotlin.psi.KtElement; +import org.jetbrains.kotlin.test.KotlinTestUtils; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/* +Test Hierarchy view +Format: test build hierarchy for element at caret, file with caret should be the first in the sorted list of files. +Test accept more than one file, file extension should be .java or .kt + */ +public abstract class AbstractHierarchyTest extends KotlinHierarchyViewTestBase { + + protected String folderName; + + protected void doTypeClassHierarchyTest(@NotNull String folderName) throws Exception { + this.folderName = folderName; + doHierarchyTest(getTypeHierarchyStructure(), getFilesToConfigure()); + } + + protected void doSuperClassHierarchyTest(@NotNull String folderName) throws Exception { + this.folderName = folderName; + doHierarchyTest(getSuperTypesHierarchyStructure(), getFilesToConfigure()); + } + + protected void doSubClassHierarchyTest(@NotNull String folderName) throws Exception { + this.folderName = folderName; + doHierarchyTest(getSubTypesHierarchyStructure(), getFilesToConfigure()); + } + + protected void doCallerHierarchyTest(@NotNull String folderName) throws Exception { + this.folderName = folderName; + doHierarchyTest(getCallerHierarchyStructure(), getFilesToConfigure()); + } + + protected void doCallerJavaHierarchyTest(@NotNull String folderName) throws Exception { + this.folderName = folderName; + doHierarchyTest(getCallerJavaHierarchyStructure(), getFilesToConfigure()); + } + + protected void doCalleeHierarchyTest(@NotNull String folderName) throws Exception { + this.folderName = folderName; + doHierarchyTest(getCalleeHierarchyStructure(), getFilesToConfigure()); + } + + protected void doOverrideHierarchyTest(@NotNull String folderName) throws Exception { + this.folderName = folderName; + doHierarchyTest(getOverrideHierarchyStructure(), getFilesToConfigure()); + } + + private Computable getSuperTypesHierarchyStructure() { + return new Computable() { + @Override + public HierarchyTreeStructure compute() { + return new SupertypesHierarchyTreeStructure( + getProject(), + (PsiClass) getElementAtCaret(LanguageTypeHierarchy.INSTANCE) + ); + } + }; + } + + private Computable getSubTypesHierarchyStructure() { + return new Computable() { + @Override + public HierarchyTreeStructure compute() { + return new SubtypesHierarchyTreeStructure( + getProject(), + (PsiClass) getElementAtCaret(LanguageTypeHierarchy.INSTANCE), + HierarchyBrowserBaseEx.SCOPE_PROJECT + ); + } + }; + } + + private Computable getTypeHierarchyStructure() { + return new Computable() { + @Override + public HierarchyTreeStructure compute() { + return new TypeHierarchyTreeStructure( + getProject(), + (PsiClass) getElementAtCaret(LanguageTypeHierarchy.INSTANCE), + HierarchyBrowserBaseEx.SCOPE_PROJECT + ); + } + }; + } + + private Computable getCallerHierarchyStructure() { + return new Computable() { + @Override + public HierarchyTreeStructure compute() { + return new KotlinCallerTreeStructure( + (KtElement) getElementAtCaret(LanguageCallHierarchy.INSTANCE), + HierarchyBrowserBaseEx.SCOPE_PROJECT + ); + } + }; + } + + private Computable getCallerJavaHierarchyStructure() { + return new Computable() { + @Override + public HierarchyTreeStructure compute() { + return new CallerMethodsTreeStructure( + getProject(), + (PsiMethod) getElementAtCaret(LanguageCallHierarchy.INSTANCE), + HierarchyBrowserBaseEx.SCOPE_PROJECT + ); + } + }; + } + + private Computable getCalleeHierarchyStructure() { + return new Computable() { + @Override + public HierarchyTreeStructure compute() { + return new KotlinCalleeTreeStructure( + (KtElement) getElementAtCaret(LanguageCallHierarchy.INSTANCE), + HierarchyBrowserBaseEx.SCOPE_PROJECT + ); + } + }; + } + + private Computable getOverrideHierarchyStructure() { + return new Computable() { + @Override + public HierarchyTreeStructure compute() { + return new KotlinOverrideTreeStructure( + getProject(), + (KtCallableDeclaration) getElementAtCaret(LanguageMethodHierarchy.INSTANCE) + ); + } + }; + } + + private PsiElement getElementAtCaret(LanguageExtension extension) { + PsiFile file = PsiDocumentManager.getInstance(getProject()).getPsiFile(getEditor().getDocument()); + HierarchyProvider provider = BrowseHierarchyActionBase.findProvider(extension, file, file, getDataContext()); + PsiElement target = provider != null ? provider.getTarget(getDataContext()) : null; + if (target == null) throw new RefactoringErrorHintException("Cannot apply action for element at caret"); + return target; + } + + private DataContext getDataContext() { + Editor editor = getEditor(); + + MapDataContext context = new MapDataContext(); + context.put(CommonDataKeys.PROJECT, getProject()); + context.put(CommonDataKeys.EDITOR, editor); + PsiElement targetElement = (PsiElement) new TextEditorPsiDataProvider().getData( + CommonDataKeys.PSI_ELEMENT.getName(), + editor, + editor.getCaretModel().getCurrentCaret() + ); + context.put(CommonDataKeys.PSI_ELEMENT, targetElement); + return context; + } + + protected String[] getFilesToConfigure() { + final List files = new ArrayList(2); + FileUtil.processFilesRecursively(new File(folderName), new Processor() { + @Override + public boolean process(File file) { + String fileName = file.getName(); + if (fileName.endsWith(".kt") || fileName.endsWith(".java")) { + files.add(fileName); + } + return true; + } + }); + Collections.sort(files); + return ArrayUtil.toStringArray(files); + } + + @Override + protected void doHierarchyTest( + @NotNull Computable treeStructureComputable, @NotNull String... fileNames + ) throws Exception { + try { + super.doHierarchyTest(treeStructureComputable, fileNames); + } + catch (RefactoringErrorHintException e) { + File file = new File(folderName, "messages.txt"); + if (file.exists()) { + String expectedMessage = FileUtil.loadFile(file, true); + assertEquals(expectedMessage, e.getLocalizedMessage()); + } + else { + fail("Unexpected error: " + e.getLocalizedMessage()); + } + } + catch (ComparisonFailure failure) { + String actual = ComparisonDetailsExtractor.getActual(failure); + String verificationFilePath = + getTestDataPath() + "/" + getTestName(false) + "_verification.xml"; + KotlinTestUtils.assertEqualsToFile(new File(verificationFilePath), actual); + } + } + + @Override + @NotNull + protected LightProjectDescriptor getProjectDescriptor() { + return KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE; + } + + @NotNull + @Override + protected String getTestDataPath() { + String testRoot = super.getTestDataPath(); + String testDir = KotlinTestUtils.getTestDataFileName(this.getClass(), getName()); + return testRoot + "/" + testDir; + } +}