as42: Additional fixes for AS42 and 202 platform
This commit is contained in:
committed by
Konstantin Tskhovrebov
parent
2df030f583
commit
5ba70b2cbb
+55
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* 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.cli.jvm.compiler;
|
||||||
|
|
||||||
|
import com.intellij.DynamicBundle;
|
||||||
|
import com.intellij.codeInsight.ContainerProvider;
|
||||||
|
import com.intellij.codeInsight.runner.JavaMainMethodProvider;
|
||||||
|
import com.intellij.core.JavaCoreApplicationEnvironment;
|
||||||
|
import com.intellij.lang.MetaLanguage;
|
||||||
|
import com.intellij.openapi.Disposable;
|
||||||
|
import com.intellij.openapi.extensions.Extensions;
|
||||||
|
import com.intellij.openapi.vfs.VirtualFileSystem;
|
||||||
|
import com.intellij.psi.FileContextProvider;
|
||||||
|
import com.intellij.psi.augment.PsiAugmentProvider;
|
||||||
|
import com.intellij.psi.compiled.ClassFileDecompilers;
|
||||||
|
import com.intellij.psi.meta.MetaDataContributor;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem;
|
||||||
|
|
||||||
|
public class KotlinCoreApplicationEnvironment extends JavaCoreApplicationEnvironment {
|
||||||
|
public static KotlinCoreApplicationEnvironment create(@NotNull Disposable parentDisposable, boolean unitTestMode) {
|
||||||
|
KotlinCoreApplicationEnvironment environment = new KotlinCoreApplicationEnvironment(parentDisposable, unitTestMode);
|
||||||
|
registerExtensionPoints();
|
||||||
|
return environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
private KotlinCoreApplicationEnvironment(@NotNull Disposable parentDisposable, boolean unitTestMode) {
|
||||||
|
super(parentDisposable, unitTestMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void registerExtensionPoints() {
|
||||||
|
registerApplicationExtensionPoint(DynamicBundle.LanguageBundleEP.EP_NAME, DynamicBundle.LanguageBundleEP.class);
|
||||||
|
registerApplicationExtensionPoint(FileContextProvider.EP_NAME, FileContextProvider.class);
|
||||||
|
|
||||||
|
registerApplicationExtensionPoint(MetaDataContributor.EP_NAME, MetaDataContributor.class);
|
||||||
|
registerApplicationExtensionPoint(PsiAugmentProvider.EP_NAME, PsiAugmentProvider.class);
|
||||||
|
registerApplicationExtensionPoint(JavaMainMethodProvider.EP_NAME, JavaMainMethodProvider.class);
|
||||||
|
|
||||||
|
registerApplicationExtensionPoint(ContainerProvider.EP_NAME, ContainerProvider.class);
|
||||||
|
registerApplicationExtensionPoint(ClassFileDecompilers.getInstance().EP_NAME, ClassFileDecompilers.Decompiler.class);
|
||||||
|
|
||||||
|
registerApplicationExtensionPoint(MetaLanguage.EP_NAME, MetaLanguage.class);
|
||||||
|
|
||||||
|
IdeaExtensionPoints.INSTANCE.registerVersionSpecificAppExtensionPoints(Extensions.getRootArea());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
protected VirtualFileSystem createJrtFileSystem() {
|
||||||
|
return new CoreJrtFileSystem();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,259 @@
|
|||||||
|
/*
|
||||||
|
* 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.actions
|
||||||
|
|
||||||
|
import com.intellij.ide.actions.CreateFileFromTemplateAction
|
||||||
|
import com.intellij.ide.actions.CreateFileFromTemplateDialog
|
||||||
|
import com.intellij.ide.actions.CreateFromTemplateAction
|
||||||
|
import com.intellij.ide.fileTemplates.FileTemplate
|
||||||
|
import com.intellij.ide.fileTemplates.FileTemplateManager
|
||||||
|
import com.intellij.ide.fileTemplates.actions.AttributesDefaults
|
||||||
|
import com.intellij.ide.fileTemplates.ui.CreateFromTemplateDialog
|
||||||
|
import com.intellij.openapi.actionSystem.DataContext
|
||||||
|
import com.intellij.openapi.actionSystem.LangDataKeys
|
||||||
|
import com.intellij.openapi.actionSystem.PlatformDataKeys
|
||||||
|
import com.intellij.openapi.editor.LogicalPosition
|
||||||
|
import com.intellij.openapi.extensions.ExtensionPointName
|
||||||
|
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||||
|
import com.intellij.openapi.module.Module
|
||||||
|
import com.intellij.openapi.module.ModuleUtilCore
|
||||||
|
import com.intellij.openapi.project.DumbAware
|
||||||
|
import com.intellij.openapi.project.DumbService
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.roots.ProjectRootManager
|
||||||
|
import com.intellij.openapi.ui.InputValidatorEx
|
||||||
|
import com.intellij.psi.PsiDirectory
|
||||||
|
import com.intellij.psi.PsiFile
|
||||||
|
import com.intellij.util.IncorrectOperationException
|
||||||
|
import org.jetbrains.annotations.TestOnly
|
||||||
|
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||||
|
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||||
|
import org.jetbrains.kotlin.idea.KotlinIcons
|
||||||
|
import org.jetbrains.kotlin.idea.statistics.FUSEventGroups
|
||||||
|
import org.jetbrains.kotlin.idea.statistics.KotlinFUSLogger
|
||||||
|
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||||
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
|
import org.jetbrains.kotlin.parsing.KotlinParserDefinition.Companion.STD_SCRIPT_SUFFIX
|
||||||
|
import org.jetbrains.kotlin.psi.KtClass
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class NewKotlinFileAction : CreateFileFromTemplateAction(
|
||||||
|
KotlinBundle.message("action.new.file.text"),
|
||||||
|
KotlinBundle.message("action.new.file.description"),
|
||||||
|
KotlinFileType.INSTANCE.icon
|
||||||
|
), DumbAware {
|
||||||
|
override fun postProcess(createdElement: PsiFile, templateName: String?, customProperties: Map<String, String>?) {
|
||||||
|
super.postProcess(createdElement, templateName, customProperties)
|
||||||
|
|
||||||
|
val module = ModuleUtilCore.findModuleForPsiElement(createdElement!!)
|
||||||
|
|
||||||
|
if (createdElement is KtFile) {
|
||||||
|
if (module != null) {
|
||||||
|
for (hook in NewKotlinFileHook.EP_NAME.extensions) {
|
||||||
|
hook.postProcess(createdElement, module)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val ktClass = createdElement.declarations.singleOrNull() as? KtNamedDeclaration
|
||||||
|
if (ktClass != null) {
|
||||||
|
CreateFromTemplateAction.moveCaretAfterNameIdentifier(ktClass)
|
||||||
|
} else {
|
||||||
|
val editor = FileEditorManager.getInstance(createdElement.project).selectedTextEditor ?: return
|
||||||
|
if (editor.document == createdElement.viewProvider.document) {
|
||||||
|
val lineCount = editor.document.lineCount
|
||||||
|
if (lineCount > 0) {
|
||||||
|
editor.caretModel.moveToLogicalPosition(LogicalPosition(lineCount - 1, 0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun buildDialog(project: Project, directory: PsiDirectory, builder: CreateFileFromTemplateDialog.Builder) {
|
||||||
|
builder.setTitle(KotlinBundle.message("action.new.file.dialog.title"))
|
||||||
|
.addKind(
|
||||||
|
KotlinBundle.message("action.new.file.dialog.file.title"),
|
||||||
|
KotlinFileType.INSTANCE.icon,
|
||||||
|
"Kotlin File"
|
||||||
|
)
|
||||||
|
.addKind(
|
||||||
|
KotlinBundle.message("action.new.file.dialog.class.title"),
|
||||||
|
KotlinIcons.CLASS,
|
||||||
|
"Kotlin Class"
|
||||||
|
)
|
||||||
|
.addKind(
|
||||||
|
KotlinBundle.message("action.new.file.dialog.interface.title"),
|
||||||
|
KotlinIcons.INTERFACE,
|
||||||
|
"Kotlin Interface"
|
||||||
|
)
|
||||||
|
.addKind(
|
||||||
|
KotlinBundle.message("action.new.file.dialog.enum.title"),
|
||||||
|
KotlinIcons.ENUM,
|
||||||
|
"Kotlin Enum"
|
||||||
|
)
|
||||||
|
.addKind(
|
||||||
|
KotlinBundle.message("action.new.file.dialog.object.title"),
|
||||||
|
KotlinIcons.OBJECT,
|
||||||
|
"Kotlin Object"
|
||||||
|
)
|
||||||
|
|
||||||
|
builder.setValidator(NameValidator)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getActionName(directory: PsiDirectory, newName: String, templateName: String): String =
|
||||||
|
KotlinBundle.message("action.new.file.text")
|
||||||
|
|
||||||
|
override fun isAvailable(dataContext: DataContext): Boolean {
|
||||||
|
if (super.isAvailable(dataContext)) {
|
||||||
|
val ideView = LangDataKeys.IDE_VIEW.getData(dataContext)!!
|
||||||
|
val project = PlatformDataKeys.PROJECT.getData(dataContext)!!
|
||||||
|
val projectFileIndex = ProjectRootManager.getInstance(project).fileIndex
|
||||||
|
return ideView.directories.any { projectFileIndex.isInSourceContent(it.virtualFile) }
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int = 0
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean = other is NewKotlinFileAction
|
||||||
|
|
||||||
|
override fun startInWriteAction() = false
|
||||||
|
|
||||||
|
override fun createFileFromTemplate(name: String, template: FileTemplate, dir: PsiDirectory) =
|
||||||
|
createFileFromTemplateWithStat(name, template, dir)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private object NameValidator : InputValidatorEx {
|
||||||
|
override fun getErrorText(inputString: String): String? {
|
||||||
|
if (inputString.trim().isEmpty()) {
|
||||||
|
return KotlinBundle.message("action.new.file.error.empty.name")
|
||||||
|
}
|
||||||
|
|
||||||
|
val parts: List<String> = inputString.split(*FQNAME_SEPARATORS)
|
||||||
|
if (parts.any { it.trim().isEmpty() }) {
|
||||||
|
return KotlinBundle.message("action.new.file.error.empty.name.part")
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun checkInput(inputString: String): Boolean = true
|
||||||
|
|
||||||
|
override fun canClose(inputString: String): Boolean = getErrorText(inputString) == null
|
||||||
|
}
|
||||||
|
|
||||||
|
@get:TestOnly
|
||||||
|
val nameValidator: InputValidatorEx
|
||||||
|
get() = NameValidator
|
||||||
|
|
||||||
|
private fun findOrCreateTarget(dir: PsiDirectory, name: String, directorySeparators: CharArray): Pair<String, PsiDirectory> {
|
||||||
|
var className = removeKotlinExtensionIfPresent(name)
|
||||||
|
var targetDir = dir
|
||||||
|
|
||||||
|
for (splitChar in directorySeparators) {
|
||||||
|
if (splitChar in className) {
|
||||||
|
val names = className.trim().split(splitChar)
|
||||||
|
|
||||||
|
for (dirName in names.dropLast(1)) {
|
||||||
|
targetDir = targetDir.findSubdirectory(dirName) ?: runWriteAction {
|
||||||
|
targetDir.createSubdirectory(dirName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
className = names.last()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Pair(className, targetDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun removeKotlinExtensionIfPresent(name: String): String = when {
|
||||||
|
name.endsWith(".$KOTLIN_WORKSHEET_EXTENSION") -> name.removeSuffix(".$KOTLIN_WORKSHEET_EXTENSION")
|
||||||
|
name.endsWith(".$STD_SCRIPT_SUFFIX") -> name.removeSuffix(".$STD_SCRIPT_SUFFIX")
|
||||||
|
name.endsWith(".${KotlinFileType.EXTENSION}") -> name.removeSuffix(".${KotlinFileType.EXTENSION}")
|
||||||
|
else -> name
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createFromTemplate(dir: PsiDirectory, className: String, template: FileTemplate): PsiFile? {
|
||||||
|
val project = dir.project
|
||||||
|
val defaultProperties = FileTemplateManager.getInstance(project).defaultProperties
|
||||||
|
|
||||||
|
val properties = Properties(defaultProperties)
|
||||||
|
|
||||||
|
val element = try {
|
||||||
|
CreateFromTemplateDialog(
|
||||||
|
project, dir, template,
|
||||||
|
AttributesDefaults(className).withFixedName(true),
|
||||||
|
properties
|
||||||
|
).create()
|
||||||
|
} catch (e: IncorrectOperationException) {
|
||||||
|
throw e
|
||||||
|
} catch (e: Exception) {
|
||||||
|
LOG.error(e)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return element?.containingFile
|
||||||
|
}
|
||||||
|
|
||||||
|
private val FILE_SEPARATORS = charArrayOf('/', '\\')
|
||||||
|
private val FQNAME_SEPARATORS = charArrayOf('/', '\\', '.')
|
||||||
|
|
||||||
|
fun createFileFromTemplateWithStat(name: String, template: FileTemplate, dir: PsiDirectory): PsiFile? {
|
||||||
|
KotlinFUSLogger.log(FUSEventGroups.NewFileTemplate, template.name)
|
||||||
|
return createFileFromTemplate(name, template, dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun createFileFromTemplate(name: String, template: FileTemplate, dir: PsiDirectory): PsiFile? {
|
||||||
|
val directorySeparators = when (template.name) {
|
||||||
|
"Kotlin File" -> FILE_SEPARATORS
|
||||||
|
else -> FQNAME_SEPARATORS
|
||||||
|
}
|
||||||
|
val (className, targetDir) = findOrCreateTarget(dir, name, directorySeparators)
|
||||||
|
|
||||||
|
val service = DumbService.getInstance(dir.project)
|
||||||
|
service.isAlternativeResolveEnabled = true
|
||||||
|
try {
|
||||||
|
val psiFile = createFromTemplate(targetDir, className, template)
|
||||||
|
if (psiFile is KtFile) {
|
||||||
|
val singleClass = psiFile.declarations.singleOrNull() as? KtClass
|
||||||
|
if (singleClass != null && !singleClass.isEnum() && !singleClass.isInterface() && name.contains("Abstract")) {
|
||||||
|
runWriteAction {
|
||||||
|
singleClass.addModifier(KtTokens.ABSTRACT_KEYWORD)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return psiFile
|
||||||
|
} finally {
|
||||||
|
service.isAlternativeResolveEnabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class NewKotlinFileHook {
|
||||||
|
companion object {
|
||||||
|
val EP_NAME: ExtensionPointName<NewKotlinFileHook> =
|
||||||
|
ExtensionPointName.create<NewKotlinFileHook>("org.jetbrains.kotlin.newFileHook")
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun postProcess(createdElement: KtFile, module: Module)
|
||||||
|
}
|
||||||
+227
@@ -0,0 +1,227 @@
|
|||||||
|
/*
|
||||||
|
* 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.roots
|
||||||
|
|
||||||
|
import com.intellij.conversion.*
|
||||||
|
import com.intellij.conversion.impl.ConversionContextImpl
|
||||||
|
import com.intellij.conversion.impl.ModuleSettingsImpl
|
||||||
|
import com.intellij.openapi.roots.ExternalProjectSystemRegistry
|
||||||
|
import com.intellij.openapi.roots.OrderRootType
|
||||||
|
import com.intellij.openapi.roots.impl.ContentEntryImpl
|
||||||
|
import com.intellij.openapi.roots.impl.SourceFolderImpl
|
||||||
|
import com.intellij.openapi.roots.impl.libraries.ApplicationLibraryTable
|
||||||
|
import com.intellij.openapi.roots.impl.libraries.LibraryEx
|
||||||
|
import com.intellij.openapi.roots.impl.libraries.LibraryImpl
|
||||||
|
import com.intellij.openapi.roots.libraries.Library
|
||||||
|
import com.intellij.openapi.roots.libraries.LibraryKind
|
||||||
|
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar
|
||||||
|
import com.intellij.openapi.roots.libraries.PersistentLibraryKind
|
||||||
|
import com.intellij.openapi.vfs.JarFileSystem
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import org.jdom.Element
|
||||||
|
import org.jetbrains.jps.model.JpsElement
|
||||||
|
import org.jetbrains.jps.model.JpsElementFactory
|
||||||
|
import org.jetbrains.jps.model.java.JavaResourceRootType
|
||||||
|
import org.jetbrains.jps.model.java.JavaSourceRootType
|
||||||
|
import org.jetbrains.jps.model.module.JpsModuleSourceRootType
|
||||||
|
import org.jetbrains.jps.model.module.JpsTypedModuleSourceRoot
|
||||||
|
import org.jetbrains.jps.model.serialization.facet.JpsFacetSerializer
|
||||||
|
import org.jetbrains.jps.model.serialization.library.JpsLibraryTableSerializer
|
||||||
|
import org.jetbrains.jps.model.serialization.module.JpsModuleRootModelSerializer.*
|
||||||
|
import org.jetbrains.kotlin.config.getFacetPlatformByConfigurationElement
|
||||||
|
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||||
|
import org.jetbrains.kotlin.idea.core.util.toVirtualFile
|
||||||
|
import org.jetbrains.kotlin.idea.facet.KotlinFacetType
|
||||||
|
import org.jetbrains.kotlin.idea.framework.JavaRuntimeDetectionUtil
|
||||||
|
import org.jetbrains.kotlin.idea.framework.JsLibraryStdDetectionUtil
|
||||||
|
import org.jetbrains.kotlin.idea.framework.getLibraryJar
|
||||||
|
import org.jetbrains.kotlin.platform.CommonPlatforms
|
||||||
|
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||||
|
import org.jetbrains.kotlin.platform.isCommon
|
||||||
|
import org.jetbrains.kotlin.platform.js.JsPlatforms
|
||||||
|
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
|
||||||
|
import org.jetbrains.kotlin.platform.jvm.isJvm
|
||||||
|
import org.jetbrains.kotlin.utils.PathUtil
|
||||||
|
|
||||||
|
class KotlinNonJvmSourceRootConverterProvider : ConverterProvider("kotlin-non-jvm-source-roots") {
|
||||||
|
companion object {
|
||||||
|
private val rootTypesToMigrate: List<JpsModuleSourceRootType<*>> = listOf(
|
||||||
|
JavaSourceRootType.SOURCE,
|
||||||
|
JavaSourceRootType.TEST_SOURCE,
|
||||||
|
JavaResourceRootType.RESOURCE,
|
||||||
|
JavaResourceRootType.TEST_RESOURCE
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO(dsavvinov): review how it behaves in HMPP environment
|
||||||
|
private val PLATFORM_TO_STDLIB_DETECTORS: Map<TargetPlatform, (Array<VirtualFile>) -> Boolean> = mapOf(
|
||||||
|
JvmPlatforms.unspecifiedJvmPlatform to { roots: Array<VirtualFile> -> JavaRuntimeDetectionUtil.getRuntimeJar(roots.toList()) != null },
|
||||||
|
JsPlatforms.defaultJsPlatform to { roots: Array<VirtualFile> -> JsLibraryStdDetectionUtil.getJsStdLibJar(roots.toList()) != null },
|
||||||
|
CommonPlatforms.defaultCommonPlatform to { roots: Array<VirtualFile> ->
|
||||||
|
getLibraryJar(roots, PathUtil.KOTLIN_STDLIB_COMMON_JAR_PATTERN) != null
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class LibInfo {
|
||||||
|
class ByXml(
|
||||||
|
private val element: Element,
|
||||||
|
private val conversionContext: ConversionContext,
|
||||||
|
private val moduleSettings: ModuleSettings
|
||||||
|
) : LibInfo() {
|
||||||
|
override val explicitKind: PersistentLibraryKind<*>?
|
||||||
|
get() = LibraryKind.findById(element.getAttributeValue("type")) as? PersistentLibraryKind<*>
|
||||||
|
|
||||||
|
override fun getRoots(): Array<VirtualFile> {
|
||||||
|
val contextImpl = conversionContext as? ConversionContextImpl ?: return VirtualFile.EMPTY_ARRAY
|
||||||
|
val moduleSettingsImpl = moduleSettings as? ModuleSettingsImpl ?: return VirtualFile.EMPTY_ARRAY
|
||||||
|
return contextImpl
|
||||||
|
.getClassRoots(element, moduleSettingsImpl)
|
||||||
|
.mapNotNull { it.toVirtualFile()?.let { file -> JarFileSystem.getInstance().getJarRootForLocalFile(file) } }
|
||||||
|
.toTypedArray()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ByLibrary(private val library: Library) : LibInfo() {
|
||||||
|
override val explicitKind: PersistentLibraryKind<*>?
|
||||||
|
get() = (library as? LibraryEx)?.kind
|
||||||
|
|
||||||
|
override fun getRoots(): Array<VirtualFile> = library.getFiles(OrderRootType.CLASSES)
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract val explicitKind: PersistentLibraryKind<*>?
|
||||||
|
abstract fun getRoots(): Array<VirtualFile>
|
||||||
|
|
||||||
|
val stdlibPlatform: TargetPlatform? by lazy {
|
||||||
|
val roots = getRoots()
|
||||||
|
for ((platform, detector) in PLATFORM_TO_STDLIB_DETECTORS) {
|
||||||
|
if (detector.invoke(roots)) {
|
||||||
|
return@lazy platform
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return@lazy null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConverterImpl(private val context: ConversionContext) : ProjectConverter() {
|
||||||
|
private val projectLibrariesByName by lazy {
|
||||||
|
context.projectLibrariesSettings.projectLibraries.groupBy { it.getAttributeValue(JpsLibraryTableSerializer.NAME_ATTRIBUTE) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findGlobalLibrary(name: String) = ApplicationLibraryTable.getApplicationTable().getLibraryByName(name)
|
||||||
|
|
||||||
|
private fun findProjectLibrary(name: String) = projectLibrariesByName[name]?.firstOrNull()
|
||||||
|
|
||||||
|
private fun createLibInfo(orderEntryElement: Element, moduleSettings: ModuleSettings): LibInfo? {
|
||||||
|
return when (orderEntryElement.getAttributeValue("type")) {
|
||||||
|
MODULE_LIBRARY_TYPE -> {
|
||||||
|
orderEntryElement.getChild(LIBRARY_TAG)?.let { LibInfo.ByXml(it, context, moduleSettings) }
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBRARY_TYPE -> {
|
||||||
|
val libraryName = orderEntryElement.getAttributeValue(NAME_ATTRIBUTE) ?: return null
|
||||||
|
when (orderEntryElement.getAttributeValue(LEVEL_ATTRIBUTE)) {
|
||||||
|
LibraryTablesRegistrar.PROJECT_LEVEL ->
|
||||||
|
findProjectLibrary(libraryName)?.let { LibInfo.ByXml(it, context, moduleSettings) }
|
||||||
|
LibraryTablesRegistrar.APPLICATION_LEVEL ->
|
||||||
|
findGlobalLibrary(libraryName)?.let { LibInfo.ByLibrary(it) }
|
||||||
|
else ->
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createModuleFileConverter(): ConversionProcessor<ModuleSettings> {
|
||||||
|
return object : ConversionProcessor<ModuleSettings>() {
|
||||||
|
private fun ModuleSettings.detectPlatformByFacet() =
|
||||||
|
getFacetElement(KotlinFacetType.ID)
|
||||||
|
?.getChild(JpsFacetSerializer.CONFIGURATION_TAG)
|
||||||
|
?.getFacetPlatformByConfigurationElement()
|
||||||
|
|
||||||
|
|
||||||
|
private fun ModuleSettings.detectPlatformByDependencies(): TargetPlatform? {
|
||||||
|
var hasCommonStdlib = false
|
||||||
|
|
||||||
|
orderEntries
|
||||||
|
.asSequence()
|
||||||
|
.mapNotNull { createLibInfo(it, this) }
|
||||||
|
.forEach {
|
||||||
|
val stdlibPlatform = it.stdlibPlatform
|
||||||
|
if (stdlibPlatform != null) {
|
||||||
|
if (stdlibPlatform.isCommon()) {
|
||||||
|
hasCommonStdlib = true
|
||||||
|
} else {
|
||||||
|
return stdlibPlatform
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (hasCommonStdlib) CommonPlatforms.defaultCommonPlatform else null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ModuleSettings.detectPlatform(): TargetPlatform {
|
||||||
|
return detectPlatformByFacet()
|
||||||
|
?: detectPlatformByDependencies()
|
||||||
|
?: JvmPlatforms.unspecifiedJvmPlatform
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ModuleSettings.getSourceFolderElements(): List<Element> {
|
||||||
|
val rootManagerElement = getComponentElement(ModuleSettings.MODULE_ROOT_MANAGER_COMPONENT) ?: return emptyList()
|
||||||
|
return rootManagerElement
|
||||||
|
.getChildren(ContentEntryImpl.ELEMENT_NAME)
|
||||||
|
.flatMap { it.getChildren(SourceFolderImpl.ELEMENT_NAME) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UnstableApiUsage")
|
||||||
|
private fun ModuleSettings.isExternalModule(): Boolean {
|
||||||
|
return when {
|
||||||
|
rootElement.getAttributeValue(ExternalProjectSystemRegistry.EXTERNAL_SYSTEM_ID_KEY) != null -> true
|
||||||
|
rootElement.getAttributeValue(ExternalProjectSystemRegistry.IS_MAVEN_MODULE_KEY)?.toBoolean() ?: false -> true
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isConversionNeeded(settings: ModuleSettings): Boolean {
|
||||||
|
if (settings.isExternalModule()) return false
|
||||||
|
|
||||||
|
val hasMigrationRoots = settings.getSourceFolderElements().any {
|
||||||
|
loadSourceRoot(it).rootType in rootTypesToMigrate
|
||||||
|
}
|
||||||
|
if (!hasMigrationRoots) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val targetPlatform = settings.detectPlatform()
|
||||||
|
return (!targetPlatform.isJvm())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun process(settings: ModuleSettings) {
|
||||||
|
for (sourceFolder in settings.getSourceFolderElements()) {
|
||||||
|
val contentRoot = sourceFolder.parent as? Element ?: continue
|
||||||
|
val oldSourceRoot = loadSourceRoot(sourceFolder)
|
||||||
|
val url = sourceFolder.getAttributeValue(URL_ATTRIBUTE)
|
||||||
|
|
||||||
|
val (newRootType, data) = oldSourceRoot.getMigratedSourceRootTypeWithProperties() ?: continue
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
val newSourceRoot = JpsElementFactory.getInstance().createModuleSourceRoot(url, newRootType, data)
|
||||||
|
as? JpsTypedModuleSourceRoot<JpsElement> ?: continue
|
||||||
|
|
||||||
|
contentRoot.removeContent(sourceFolder)
|
||||||
|
saveSourceRoot(contentRoot, url, newSourceRoot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getConversionDescription() =
|
||||||
|
KotlinBundle.message("roots.description.text.update.source.roots.for.non.jvm.modules.in.kotlin.project")
|
||||||
|
|
||||||
|
override fun createConverter(context: ConversionContext) = ConverterImpl(context)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user