diff --git a/Dockerfile b/Dockerfile index 890397ad0..f7da34a33 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,9 +30,6 @@ COPY --from=build /kotlin-compiler-server/${KOTLIN_LIB} /kotlin-compiler-server/ COPY --from=build /kotlin-compiler-server/${KOTLIN_LIB_JS} /kotlin-compiler-server/${KOTLIN_LIB_JS} COPY --from=build /kotlin-compiler-server/${KOTLIN_LIB_WASM} /kotlin-compiler-server/${KOTLIN_LIB_WASM} COPY --from=build /kotlin-compiler-server/executor.policy /kotlin-compiler-server/ -COPY --from=build /kotlin-compiler-server/indexes.json /kotlin-compiler-server/ -COPY --from=build /kotlin-compiler-server/indexesJs.json /kotlin-compiler-server/ -COPY --from=build /kotlin-compiler-server/indexesWasm.json /kotlin-compiler-server/ ENV PORT=8080 diff --git a/build.gradle.kts b/build.gradle.kts index 9341dfe8f..613a60742 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,12 +6,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.springframework.boot.gradle.tasks.bundling.BootJar val kotlinVersion = rootProject.properties["systemProp.kotlinVersion"] -val kotlinIdeVersion: String by System.getProperties() -val kotlinIdeVersionSuffix: String by System.getProperties() val policy: String by System.getProperties() -val indexes: String by System.getProperties() -val indexesJs: String by System.getProperties() -val indexesWasm: String by System.getProperties() group = "com.compiler.server" version = "$kotlinVersion-SNAPSHOT" @@ -84,21 +79,14 @@ allprojects { gradlePluginPortal() maven("https://repo.spring.io/snapshot") maven("https://repo.spring.io/milestone") - maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/kotlin-ide") maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev") - maven("https://cache-redirector.jetbrains.com/jetbrains.bintray.com/intellij-third-party-dependencies") - maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/kotlin-ide-plugin-dependencies") maven("https://www.myget.org/F/rd-snapshots/maven/") - maven("https://kotlin.jetbrains.space/p/kotlin/packages/maven/kotlin-ide") maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap") } afterEvaluate { dependencies { dependencies { implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.15.2") - implementation("org.jetbrains.kotlin:idea:231-$kotlinIdeVersion-$kotlinIdeVersionSuffix") { - isTransitive = false - } } } } @@ -126,7 +114,6 @@ dependencies { implementation("com.amazonaws.serverless:aws-serverless-java-container-springboot2:1.9.3") implementation("junit:junit:4.13.2") implementation("net.logstash.logback:logstash-logback-encoder:7.3") - implementation("org.jetbrains.intellij.deps:trove4j:1.0.20221201") implementation("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion") implementation("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion") @@ -134,10 +121,6 @@ dependencies { implementation("org.jetbrains.kotlin:kotlin-test:$kotlinVersion") implementation("org.jetbrains.kotlin:kotlin-compiler:$kotlinVersion") implementation("org.jetbrains.kotlin:kotlin-script-runtime:$kotlinVersion") - implementation("org.jetbrains.kotlin:kotlin-compiler-for-ide:$kotlinIdeVersion"){ - isTransitive = false - } - implementation("org.jetbrains.kotlin:core:231-$kotlinIdeVersion-$kotlinIdeVersionSuffix") implementation(project(":executors", configuration = "default")) implementation(project(":common", configuration = "default")) @@ -159,9 +142,6 @@ fun generateProperties(prefix: String = "") = """ # this file is autogenerated by build.gradle.kts kotlin.version=${kotlinVersion} policy.file=${prefix + policy} - indexes.file=${prefix + indexes} - indexesJs.file=${prefix + indexesJs} - indexesWasm.file=${prefix + indexesWasm} libraries.folder.jvm=${prefix + libJVMFolder} libraries.folder.js=${prefix + libJSFolder} libraries.folder.wasm=${prefix + libWasmFolder} @@ -185,7 +165,6 @@ tasks.withType { dependsOn(copyJSDependencies) dependsOn(copyWasmDependencies) dependsOn(":executors:jar") - dependsOn(":indexation:run") buildPropertyFile() } println("Using Kotlin compiler $kotlinVersion") @@ -204,9 +183,6 @@ val buildLambda by tasks.creating(Zip::class) { } } from(policy) - from(indexes) - from(indexesJs) - from(indexesWasm) from(libJSFolder) { into(libJSFolder) } from(libWasmFolder) { into(libWasmFolder) } from(libJVMFolder) { into(libJVMFolder) } diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 97aca1e5f..cbe6640fa 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -1,6 +1,4 @@ val kotlinVersion: String by System.getProperties() -val kotlinIdeVersion: String by System.getProperties() -val kotlinIdeVersionSuffix: String by System.getProperties() plugins { kotlin("jvm") @@ -8,6 +6,4 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-compiler:$kotlinVersion") - implementation("org.jetbrains.kotlin:kotlin-gradle-plugin-idea:$kotlinVersion") - implementation("org.jetbrains.kotlin:base-fe10-analysis:231-$kotlinIdeVersion-$kotlinIdeVersionSuffix") } diff --git a/common/src/main/kotlin/component/KotlinEnvironment.kt b/common/src/main/kotlin/component/KotlinEnvironment.kt index edd57f459..306a0d51c 100644 --- a/common/src/main/kotlin/component/KotlinEnvironment.kt +++ b/common/src/main/kotlin/component/KotlinEnvironment.kt @@ -1,24 +1,5 @@ package component -import com.intellij.openapi.util.Disposer -import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys -import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments -import org.jetbrains.kotlin.cli.common.arguments.parseCommandLineArguments -import org.jetbrains.kotlin.cli.common.messages.MessageCollector -import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles -import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment -import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots -import org.jetbrains.kotlin.cli.jvm.config.configureJdkClasspathRoots -import org.jetbrains.kotlin.cli.jvm.configureAdvancedJvmOptions -import org.jetbrains.kotlin.config.CommonConfigurationKeys -import org.jetbrains.kotlin.config.CompilerConfiguration -import org.jetbrains.kotlin.config.JVMConfigurationKeys -import org.jetbrains.kotlin.config.languageVersionSettings -import org.jetbrains.kotlin.js.config.JSConfigurationKeys -import org.jetbrains.kotlin.serialization.js.JsModuleDescriptor -import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil -import org.jetbrains.kotlin.serialization.js.ModuleKind -import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils import java.io.File class KotlinEnvironment( @@ -45,65 +26,7 @@ class KotlinEnvironment( ) } - val JS_METADATA_CACHE = - additionalJsClasspath.flatMap { - KotlinJavascriptMetadataUtils.loadMetadata(it.absolutePath).map { metadata -> - val parts = KotlinJavascriptSerializationUtil.readModuleAsProto(metadata.body, metadata.version) - JsModuleDescriptor(metadata.moduleName, parts.kind, parts.importedModules, parts) - } - } - val JS_LIBRARIES = additionalJsClasspath.map { it.absolutePath } val WASM_LIBRARIES = additionalWasmClasspath.map { it.absolutePath } - @Synchronized - fun environment(f: (KotlinCoreEnvironment) -> T): T { - return f(environment) - } - - private val configuration = createConfiguration() - val jsConfiguration: CompilerConfiguration = configuration.copy().apply { - put(CommonConfigurationKeys.MODULE_NAME, "moduleId") - put(JSConfigurationKeys.MODULE_KIND, ModuleKind.PLAIN) - put(JSConfigurationKeys.LIBRARIES, JS_LIBRARIES) - } - - val wasmConfiguration: CompilerConfiguration = configuration.copy().apply { - put(CommonConfigurationKeys.MODULE_NAME, "moduleId") - put(JSConfigurationKeys.LIBRARIES, WASM_LIBRARIES) - put(JSConfigurationKeys.WASM_ENABLE_ARRAY_RANGE_CHECKS, false) - put(JSConfigurationKeys.WASM_ENABLE_ASSERTS, false) - } - - private val environment = KotlinCoreEnvironment.createForProduction( - parentDisposable = Disposer.newDisposable(), - configuration = configuration.copy(), - configFiles = EnvironmentConfigFiles.JVM_CONFIG_FILES - ) - - private fun createConfiguration(): CompilerConfiguration { - val arguments = K2JVMCompilerArguments() - parseCommandLineArguments(additionalCompilerArguments, arguments) - return CompilerConfiguration().apply { - addJvmClasspathRoots(classpath.filter { it.exists() && it.isFile && it.extension == "jar" }) - val messageCollector = MessageCollector.NONE - put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector) - put(CommonConfigurationKeys.MODULE_NAME, "web-module") - put(JSConfigurationKeys.TYPED_ARRAYS_ENABLED, true) - put(JSConfigurationKeys.PROPERTY_LAZY_INITIALIZATION, true) - - languageVersionSettings = arguments.toLanguageVersionSettings(messageCollector) - - // it uses languageVersionSettings that was set above - configureAdvancedJvmOptions(arguments) - put(JVMConfigurationKeys.DO_NOT_CLEAR_BINDING_CONTEXT, true) - - configureJdkClasspathRoots() - val jdkHome = get(JVMConfigurationKeys.JDK_HOME) - if (jdkHome == null) { - val javaHome = File(System.getProperty("java.home")) - put(JVMConfigurationKeys.JDK_HOME, javaHome) - } - } - } } diff --git a/gradle.properties b/gradle.properties index 74da6b3d7..e2c482f6d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,2 @@ systemProp.kotlinVersion=1.9.20 -systemProp.kotlinIdeVersion=1.9.20-RC2-494 -systemProp.kotlinIdeVersionSuffix=IJ8109.175 systemProp.policy=executor.policy -systemProp.indexes=indexes.json -systemProp.indexesJs=indexesJs.json -systemProp.indexesWasm=indexesWasm.json diff --git a/indexation/build.gradle.kts b/indexation/build.gradle.kts deleted file mode 100644 index fb7ccbf64..000000000 --- a/indexation/build.gradle.kts +++ /dev/null @@ -1,31 +0,0 @@ -val kotlinVersion: String by System.getProperties() -val kotlinIdeVersion: String by System.getProperties() -val indexes: String by System.getProperties() -val indexesJs: String by System.getProperties() -val indexesWasm: String by System.getProperties() - -plugins { - kotlin("jvm") - application -} - -dependencies { - implementation(project(":common", configuration = "default")) - implementation("org.jetbrains.kotlin:kotlin-compiler-for-ide:$kotlinIdeVersion") { - isTransitive = false - } -} - -application { - mainClass.set("indexation.MainKt") -} - -tasks.withType { - val rootName = project.rootProject.projectDir.toString() - args = listOf( - "$rootName${File.separator}$kotlinVersion", - "$rootName${File.separator}$indexes", - "$rootName${File.separator}$indexesJs", - "$rootName${File.separator}$indexesWasm" - ) -} diff --git a/indexation/src/main/kotlin/DescriptorsUtils.kt b/indexation/src/main/kotlin/DescriptorsUtils.kt deleted file mode 100644 index 902445781..000000000 --- a/indexation/src/main/kotlin/DescriptorsUtils.kt +++ /dev/null @@ -1,99 +0,0 @@ -package indexation - -import model.ImportInfo -import model.Icon -import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.idea.imports.importableFqName -import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.renderer.ClassifierNamePolicy -import org.jetbrains.kotlin.renderer.ParameterNameRenderingPolicy -import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter -import org.jetbrains.kotlin.resolve.scopes.MemberScope -import org.jetbrains.kotlin.types.asFlexibleType -import org.jetbrains.kotlin.types.isFlexible - -internal val renderer = IdeDescriptorRenderers.SOURCE_CODE.withOptions { - classifierNamePolicy = ClassifierNamePolicy.SHORT - typeNormalizer = IdeDescriptorRenderers.APPROXIMATE_FLEXIBLE_TYPES - parameterNameRenderingPolicy = ParameterNameRenderingPolicy.ALL - typeNormalizer = { - if (it.isFlexible()) it.asFlexibleType().upperBound - else it - } -} - -internal fun DeclarationDescriptor.toImportInfo(): ImportInfo? { - val importName = importableFqName?.asString() ?: return null - if (name.asString() == "Companion") return null - return when (this) { - is FunctionDescriptor -> { - if (visibility.isPublicAPI) { - val returnTypeVal = if (returnType != null) renderer.renderType(returnType!!) - else {extensionReceiverParameter?.let { param -> - " for ${renderer.renderType(param.type)} in ${DescriptorUtils.getFqName(containingDeclaration)}" - } ?: "" } - ImportInfo( - importName = importName, - shortName = name.asString(), - fullName = name.asString() + renderer.renderFunctionParameters(this), - returnType = returnTypeVal, - icon = Icon.METHOD - ) } else null - } - - is ClassDescriptor -> { - if (visibility.isPublicAPI) { - ImportInfo( - importName = importName, - shortName = name.asString(), - fullName = name.asString(), - returnType = name.asString(), - icon = Icon.CLASS - ) - } else null - } - - is PropertyDescriptor -> { - ImportInfo( - importName = importName, - shortName = name.asString(), - fullName = name.asString(), - returnType = name.asString(), - icon = Icon.PROPERTY - ) - } - - else -> null - } -} - -internal fun DeclarationDescriptor.getInnerClassesAndAllStaticFunctions(): List? { - return if (this !is ClassDescriptor || !visibility.isPublicAPI) - null - else (unsubstitutedInnerClassesScope.getContributedDescriptors(DescriptorKindFilter.ALL, MemberScope.ALL_NAME_FILTER) + - staticScope.getContributedDescriptors(DescriptorKindFilter.ALL, MemberScope.ALL_NAME_FILTER)).distinct() -} - -internal fun ModuleDescriptor.allImportsInfo(): List { - val packages = allPackages() - return packages.flatMap { fqName -> - val packageViewDescriptor = getPackage(fqName) - val descriptors = packageViewDescriptor.memberScope - .getContributedDescriptors(DescriptorKindFilter.ALL, MemberScope.ALL_NAME_FILTER) - val allDescriptors = descriptors + descriptors.mapNotNull { it.getInnerClassesAndAllStaticFunctions() }.flatten() - allDescriptors.mapNotNull { it.toImportInfo() } - } -} - -internal fun ModuleDescriptor.allPackages(): Collection { - val result = mutableListOf() - fun impl(pkg: FqName) { - result += pkg - - getSubPackagesOf(pkg) { true }.forEach { impl(it) } - } - impl(FqName.ROOT) - return result -} diff --git a/indexation/src/main/kotlin/IndexationBuilder.kt b/indexation/src/main/kotlin/IndexationBuilder.kt deleted file mode 100644 index f0a8fca33..000000000 --- a/indexation/src/main/kotlin/IndexationBuilder.kt +++ /dev/null @@ -1,14 +0,0 @@ -package indexation - -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import model.ImportInfo -import java.io.File - -abstract class IndexationBuilder { - fun writeIndexesToFile(outputFilename: String) { - val indexes = getAllIndexes().groupBy { it.shortName } - File(outputFilename).writeText(jacksonObjectMapper().writeValueAsString(indexes)) - } - - abstract fun getAllIndexes(): List -} diff --git a/indexation/src/main/kotlin/JvmIndexationBuilder.kt b/indexation/src/main/kotlin/JvmIndexationBuilder.kt deleted file mode 100644 index f42db2e75..000000000 --- a/indexation/src/main/kotlin/JvmIndexationBuilder.kt +++ /dev/null @@ -1,31 +0,0 @@ -package indexation - -import model.ImportInfo -import component.KotlinEnvironment -import org.jetbrains.kotlin.cli.jvm.compiler.CliBindingTrace -import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM -import org.jetbrains.kotlin.container.getService -import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory - -class JvmIndexationBuilder(private val kotlinEnvironment: KotlinEnvironment): IndexationBuilder() { - override fun getAllIndexes(): List = - kotlinEnvironment.environment { coreEnvironment -> - val trace = CliBindingTrace() - val project = coreEnvironment.project - val componentProvider = TopDownAnalyzerFacadeForJVM.createContainer( - project = project, - files = emptyList(), - trace = trace, - configuration = coreEnvironment.configuration, - packagePartProvider = { globalSearchScope -> - coreEnvironment.createPackagePartProvider(globalSearchScope) - }, - declarationProviderFactory = { storageManager, ktFiles -> - FileBasedDeclarationProviderFactory(storageManager, ktFiles) - } - ) - val moduleDescriptor = componentProvider.getService(ModuleDescriptor::class.java) - return@environment moduleDescriptor.allImportsInfo().distinct() - } -} diff --git a/indexation/src/main/kotlin/KotlinEnvironmentConfiguration.kt b/indexation/src/main/kotlin/KotlinEnvironmentConfiguration.kt deleted file mode 100644 index c56ef4ff1..000000000 --- a/indexation/src/main/kotlin/KotlinEnvironmentConfiguration.kt +++ /dev/null @@ -1,23 +0,0 @@ -package indexation - -import component.KotlinEnvironment -import java.io.File - -class KotlinEnvironmentConfiguration(fileName: String) { - val kotlinEnvironment = run { - val jvmFile = File(fileName) - val jsFile = File("$fileName-js") - val wasmFile = File("$fileName-wasm") - val classPath = - listOfNotNull(jvmFile) - .flatMap { - it.listFiles()?.toList() - ?: error("No kotlin libraries found in: ${jvmFile.absolutePath}") - } - - val additionalJsClasspath = jsFile.listFiles()?.toList() ?: emptyList() - val additionalWasmClasspath = wasmFile.listFiles()?.toList() ?: emptyList() - - KotlinEnvironment(classPath, additionalJsClasspath, additionalWasmClasspath) - } -} diff --git a/indexation/src/main/kotlin/Main.kt b/indexation/src/main/kotlin/Main.kt deleted file mode 100644 index 5d72d9aba..000000000 --- a/indexation/src/main/kotlin/Main.kt +++ /dev/null @@ -1,24 +0,0 @@ -package indexation - -/** - * First argument is path to folder with jars - * Second argument is path to output file for jvm indexes - * Third argument is path to output file for js indexes - */ -fun main(args: Array) { - val (directory, outputPathJvm, outputPathJs, outputPathWasm) = args - val kotlinEnvironment = KotlinEnvironmentConfiguration(directory).kotlinEnvironment - JvmIndexationBuilder(kotlinEnvironment = kotlinEnvironment).writeIndexesToFile(outputPathJvm) - - WebIndexationBuilder( - kotlinEnvironment = kotlinEnvironment, - configuration = kotlinEnvironment.jsConfiguration, - libraries = kotlinEnvironment.JS_LIBRARIES - ).writeIndexesToFile(outputPathJs) - - WebIndexationBuilder( - kotlinEnvironment = kotlinEnvironment, - configuration = kotlinEnvironment.wasmConfiguration, - libraries = kotlinEnvironment.WASM_LIBRARIES - ).writeIndexesToFile(outputPathWasm) -} diff --git a/indexation/src/main/kotlin/WebIndexationBuilder.kt b/indexation/src/main/kotlin/WebIndexationBuilder.kt deleted file mode 100644 index 4c1005f1c..000000000 --- a/indexation/src/main/kotlin/WebIndexationBuilder.kt +++ /dev/null @@ -1,36 +0,0 @@ -package indexation - -import model.ImportInfo -import component.KotlinEnvironment -import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport -import org.jetbrains.kotlin.config.CompilerConfiguration -import org.jetbrains.kotlin.ir.backend.js.prepareAnalyzedSourceModule - -class WebIndexationBuilder( - private val kotlinEnvironment: KotlinEnvironment, - private val configuration: CompilerConfiguration, - private val libraries: List -): IndexationBuilder() { - - override fun getAllIndexes(): List = - kotlinEnvironment.environment { coreEnvironment -> - val project = coreEnvironment.project - - val sourceModule = prepareAnalyzedSourceModule( - project, - coreEnvironment.getSourceFiles(), - configuration, - libraries, - friendDependencies = emptyList(), - analyzer = AnalyzerWithCompilerReport(kotlinEnvironment.jsConfiguration), - ) - - val mds = sourceModule.allDependencies.map { - sourceModule.getModuleDescriptor(it) - } - - return@environment mds.flatMap { moduleDescriptor -> - moduleDescriptor.allImportsInfo() - }.distinct() - } -} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 596e169c0..cc44817c6 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,6 +1,5 @@ rootProject.name = "kotlin-compiler-server" include(":executors") -include(":indexation") include(":common") pluginManagement { diff --git a/src/main/kotlin/com/compiler/server/compiler/KotlinFile.kt b/src/main/kotlin/com/compiler/server/compiler/KotlinFile.kt deleted file mode 100644 index ba1de6bac..000000000 --- a/src/main/kotlin/com/compiler/server/compiler/KotlinFile.kt +++ /dev/null @@ -1,53 +0,0 @@ -package com.compiler.server.compiler - -import com.intellij.openapi.project.Project -import com.intellij.openapi.vfs.CharsetToolkit -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiFileFactory -import com.intellij.psi.impl.PsiFileFactoryImpl -import com.intellij.testFramework.LightVirtualFile -import org.jetbrains.kotlin.idea.KotlinLanguage -import org.jetbrains.kotlin.psi.KtExpression -import org.jetbrains.kotlin.psi.KtFile - -class KotlinFile(val kotlinFile: KtFile) { - - fun elementAt( - line: Int, - character: Int - ): PsiElement? = kotlinFile.findElementAt(offsetFor(line, character))?.let { expressionFor(it) } - - fun insert(content: String, atLine: Int, atCharacter: Int): KotlinFile { - val caretPositionOffset = offsetFor(atLine, atCharacter) - return if (caretPositionOffset != 0) { - from( - project = kotlinFile.project, - name = kotlinFile.name, - content = StringBuilder(kotlinFile.text.substring(0, caretPositionOffset)) - .append(content) - .append(kotlinFile.text.substring(caretPositionOffset)).toString() - ) - } else this - } - - private fun offsetFor(line: Int, character: Int) = - (kotlinFile.viewProvider.document?.getLineStartOffset(line) ?: 0) + character - - private tailrec fun expressionFor(element: PsiElement): PsiElement = - if (element is KtExpression) element else expressionFor(element.parent) - - companion object { - fun from(project: Project, name: String, content: String) = - KotlinFile( - (PsiFileFactory.getInstance(project) as PsiFileFactoryImpl) - .trySetupPsiForFile( - LightVirtualFile( - if (name.endsWith(".kt")) name else "$name.kt", - KotlinLanguage.INSTANCE, - content - ).apply { charset = CharsetToolkit.UTF8_CHARSET }, - KotlinLanguage.INSTANCE, true, false - ) as KtFile - ) - } -} diff --git a/src/main/kotlin/com/compiler/server/compiler/KotlinPlatform.kt b/src/main/kotlin/com/compiler/server/compiler/KotlinPlatform.kt deleted file mode 100644 index 84daae196..000000000 --- a/src/main/kotlin/com/compiler/server/compiler/KotlinPlatform.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.compiler.server.compiler - -enum class KotlinPlatform { - JS, - JVM, - WASM -} \ No newline at end of file diff --git a/src/main/kotlin/com/compiler/server/compiler/KotlinResolutionFacade.kt b/src/main/kotlin/com/compiler/server/compiler/KotlinResolutionFacade.kt deleted file mode 100644 index 36e92a2c0..000000000 --- a/src/main/kotlin/com/compiler/server/compiler/KotlinResolutionFacade.kt +++ /dev/null @@ -1,67 +0,0 @@ -package com.compiler.server.compiler - -import com.intellij.openapi.project.Project -import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.analyzer.AnalysisResult -import org.jetbrains.kotlin.analyzer.ModuleInfo -import org.jetbrains.kotlin.analyzer.ResolverForProject -import org.jetbrains.kotlin.container.ComponentProvider -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.diagnostics.DiagnosticSink -import org.jetbrains.kotlin.idea.FrontendInternals -import org.jetbrains.kotlin.idea.resolve.ResolutionFacade -import org.jetbrains.kotlin.psi.KtDeclaration -import org.jetbrains.kotlin.psi.KtElement -import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode - -@OptIn(FrontendInternals::class) -class KotlinResolutionFacade( - override val project: Project, - override val moduleDescriptor: ModuleDescriptor, - private val componentProvider: ComponentProvider -) : ResolutionFacade { - @Suppress("UNCHECKED_CAST") - override fun getFrontendService(serviceClass: Class) = - componentProvider.resolve(serviceClass)?.getValue() as T - - override fun analyze( - elements: Collection, - bodyResolveMode: BodyResolveMode - ): BindingContext = throw UnsupportedOperationException() - - override fun analyze( - element: KtElement, - bodyResolveMode: BodyResolveMode - ): BindingContext = throw UnsupportedOperationException() - - override fun analyzeWithAllCompilerChecks( - elements: Collection, - callback: DiagnosticSink.DiagnosticsCallback? - ): AnalysisResult = throw UnsupportedOperationException() - - override fun getFrontendService( - element: PsiElement, - serviceClass: Class - ): T = throw UnsupportedOperationException() - - override fun getFrontendService( - moduleDescriptor: ModuleDescriptor, - serviceClass: Class - ): T = throw UnsupportedOperationException() - - override fun getIdeService(serviceClass: Class): T = TODO("not implemented") - - override fun getResolverForProject(): ResolverForProject = throw UnsupportedOperationException() - - override fun resolveToDescriptor( - declaration: KtDeclaration, - bodyResolveMode: BodyResolveMode - ): DeclarationDescriptor = throw UnsupportedOperationException() - - override fun tryGetFrontendService( - element: PsiElement, - serviceClass: Class - ): T? = throw UnsupportedOperationException() -} \ No newline at end of file diff --git a/src/main/kotlin/com/compiler/server/compiler/components/CliUtils.kt b/src/main/kotlin/com/compiler/server/compiler/components/CliUtils.kt index 8c9a397f9..940565ef1 100644 --- a/src/main/kotlin/com/compiler/server/compiler/components/CliUtils.kt +++ b/src/main/kotlin/com/compiler/server/compiler/components/CliUtils.kt @@ -1,8 +1,8 @@ package com.compiler.server.compiler.components -import com.compiler.server.compiler.components.IndexationProvider.Companion.UNRESOLVED_REFERENCE_PREFIX import com.compiler.server.model.CompilerDiagnostics import com.compiler.server.model.ErrorDescriptor +import com.compiler.server.model.ProjectFile import com.compiler.server.model.ProjectSeveriry import com.compiler.server.model.TextInterval import org.jetbrains.kotlin.cli.common.CLICompiler @@ -11,7 +11,6 @@ import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.* import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSourceLocation import org.jetbrains.kotlin.cli.common.messages.MessageRenderer -import org.jetbrains.kotlin.psi.KtFile import java.nio.file.Path import java.nio.file.Paths import java.util.* @@ -19,6 +18,8 @@ import kotlin.io.path.* private fun minusOne(value: Int) = if (value > 0) value - 1 else value +private const val UNRESOLVED_REFERENCE_PREFIX = "Unresolved reference: " + sealed class CompilationResult { abstract val compilerDiagnostics: CompilerDiagnostics @@ -121,10 +122,10 @@ private fun getTempDirectory(): Path { return Paths.get(dir, sessionId) } -fun List.writeToIoFiles(inputDir: Path): List { +fun List.writeToIoFiles(inputDir: Path): List { val ioFiles = map { inputDir / it.name } - for ((ioFile, ktFile) in ioFiles zip this) { - ioFile.writeText(ktFile.text) + for ((ioFile, projectFile) in ioFiles zip this) { + ioFile.writeText(projectFile.text) } return ioFiles } diff --git a/src/main/kotlin/com/compiler/server/compiler/components/CompletionProvider.kt b/src/main/kotlin/com/compiler/server/compiler/components/CompletionProvider.kt deleted file mode 100644 index dad3094e1..000000000 --- a/src/main/kotlin/com/compiler/server/compiler/components/CompletionProvider.kt +++ /dev/null @@ -1,294 +0,0 @@ -package com.compiler.server.compiler.components - -import com.compiler.server.compiler.KotlinFile -import com.compiler.server.compiler.KotlinResolutionFacade -import com.compiler.server.model.Analysis -import com.compiler.server.model.CompilerDiagnostics -import com.compiler.server.model.ProjectType -import com.intellij.psi.PsiElement -import com.intellij.psi.tree.TokenSet -import model.Completion -import model.Icon -import model.completionTextFromFullName -import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment -import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor -import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl -import org.jetbrains.kotlin.idea.codeInsight.ReferenceVariantsHelper -import org.jetbrains.kotlin.idea.core.isVisible -import org.jetbrains.kotlin.idea.imports.importableFqName -import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers -import org.jetbrains.kotlin.idea.util.getResolutionScope -import org.jetbrains.kotlin.lexer.KtKeywordToken -import org.jetbrains.kotlin.lexer.KtTokens -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.renderer.ClassifierNamePolicy -import org.jetbrains.kotlin.renderer.ParameterNameRenderingPolicy -import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter -import org.jetbrains.kotlin.resolve.scopes.MemberScope -import org.jetbrains.kotlin.types.asFlexibleType -import org.jetbrains.kotlin.types.isFlexible -import org.springframework.stereotype.Component - -@Component -class CompletionProvider( - private val errorAnalyzer: ErrorAnalyzer, - private val indexationProvider: IndexationProvider -) { - companion object { - private val excludedFromCompletion: List = listOf( - "kotlin.jvm.internal", - "kotlin.coroutines.experimental.intrinsics", - "kotlin.coroutines.intrinsics", - "kotlin.coroutines.experimental.jvm.internal", - "kotlin.coroutines.jvm.internal", - "kotlin.reflect.jvm.internal" - ) - private val NAME_FILTER = { name: Name -> !name.isSpecial } - private const val COMPLETION_SUFFIX = "IntellijIdeaRulezzz" - } - - private data class DescriptorInfo( - val isTipsManagerCompletion: Boolean, - val descriptors: List - ) - - fun complete( - file: KotlinFile, - line: Int, - character: Int, - projectType: ProjectType, - coreEnvironment: KotlinCoreEnvironment - ): List = with(file.insert("$COMPLETION_SUFFIX ", line, character)) { - elementAt(line, character)?.let { element -> - val descriptorInfo = descriptorsFrom(this, element, projectType, coreEnvironment) - val prefix = (if (descriptorInfo.isTipsManagerCompletion) element.text else element.parent.text) - .substringBefore(COMPLETION_SUFFIX).let { if (it.endsWith(".")) "" else it } - val importCompletionVariants = if (indexationProvider.hasIndexes(projectType)) { - val (errors, _) = errorAnalyzer.errorsFrom(listOf(file.kotlinFile), coreEnvironment, projectType) - importVariants(file, prefix, errors, line, character, projectType) - } else emptyList() - descriptorInfo.descriptors.toMutableList().apply { - sortWith { a, b -> - val (a1, a2) = a.presentableName() - val (b1, b2) = b.presentableName() - ("$a1$a2").compareTo("$b1$b2", true) - } - }.mapNotNull { descriptor -> completionVariantFor(prefix, descriptor, element) } + - keywordsCompletionVariants(KtTokens.KEYWORDS, prefix) + - keywordsCompletionVariants(KtTokens.SOFT_KEYWORDS, prefix) + - importCompletionVariants - } ?: emptyList() - } - - private fun DeclarationDescriptor.presentableName(isCallableReferenceCompletion: Boolean = false): Pair { - var presentableText = if (this is ConstructorDescriptor) - this.constructedClass.name.asString() - else - this.name.asString() - return when (this) { - is FunctionDescriptor -> { - if (!isCallableReferenceCompletion) - presentableText += renderer.renderFunctionParameters(this) - presentableText to when { - returnType != null -> renderer.renderType(returnType!!) - else -> (extensionReceiverParameter?.let { param -> - " for ${renderer.renderType(param.type)} in ${DescriptorUtils.getFqName(containingDeclaration)}" - } ?: "") - } - } - - else -> presentableText to when (this) { - is VariableDescriptor -> renderer.renderType(type) - is ClassDescriptor -> " (${DescriptorUtils.getFqName(containingDeclaration)})" - is TypeAliasDescriptor -> renderer.renderType(expandedType) - else -> renderer.render(this) - } - } - } - - private fun importVariants( - file: KotlinFile, - prefix: String, - compilerDiagnostics: CompilerDiagnostics, - line: Int, - character: Int, - projectType: ProjectType - ): List { - val importCompletionVariants = indexationProvider.getClassesByName(prefix, projectType) - ?.map { it.toCompletion() } ?: emptyList() - val currentErrors = compilerDiagnostics.map[file.kotlinFile.name]?.filter { - it.interval != null && - it.interval.start.line == line && - it.interval.start.ch <= character && - it.interval.end.line == line && - it.interval.end.ch >= character && - it.message.startsWith(IndexationProvider.UNRESOLVED_REFERENCE_PREFIX) - } ?: emptyList() - if (currentErrors.isNotEmpty()) return importCompletionVariants - val oldImports = file.kotlinFile.importList?.imports?.mapNotNull { it.importPath.toString() } ?: emptyList() - val suggestions = importCompletionVariants.filter { !oldImports.contains(it.import) } - return suggestions.onEach { completion -> completion.hasOtherImports = true } - } - - private fun completionVariantFor( - prefix: String, - descriptor: DeclarationDescriptor, - element: PsiElement - ): Completion? { - val isCallableReference = (element as? KtElement)?.isCallableReference() ?: false - val (fullName, type) = descriptor.presentableName(isCallableReference) - return if (prefix.isEmpty() || fullName.startsWith(prefix)) { - Completion( - text = completionTextFromFullName(fullName), - displayText = fullName, - tail = type, - icon = iconFrom(descriptor) - ) - } else null - } - - private val renderer = IdeDescriptorRenderers.SOURCE_CODE.withOptions { - classifierNamePolicy = ClassifierNamePolicy.SHORT - typeNormalizer = IdeDescriptorRenderers.APPROXIMATE_FLEXIBLE_TYPES - parameterNameRenderingPolicy = ParameterNameRenderingPolicy.ALL - typeNormalizer = { - if (it.isFlexible()) it.asFlexibleType().upperBound - else it - } - } - - private fun Analysis.referenceVariantsFrom( - element: PsiElement, - coreEnvironment: KotlinCoreEnvironment - ): List? { - val elementKt = element as? KtElement ?: return emptyList() - val bindingContext = analysisResult.bindingContext - val resolutionFacade = KotlinResolutionFacade( - project = coreEnvironment.project, - componentProvider = componentProvider, - moduleDescriptor = analysisResult.moduleDescriptor - ) - val inDescriptor: DeclarationDescriptor = - elementKt.getResolutionScope(bindingContext, resolutionFacade).ownerDescriptor - return when (element) { - is KtSimpleNameExpression -> ReferenceVariantsHelper( - bindingContext = analysisResult.bindingContext, - resolutionFacade = resolutionFacade, - moduleDescriptor = analysisResult.moduleDescriptor, - visibilityFilter = VisibilityFilter(inDescriptor, bindingContext, element, resolutionFacade) - ).getReferenceVariants( - expression = element, - kindFilter = DescriptorKindFilter.ALL, - nameFilter = NAME_FILTER, - filterOutJavaGettersAndSetters = true, - filterOutShadowed = true, - excludeNonInitializedVariable = true, - useReceiverType = null - ).toList() - - else -> null - } - } - - private fun descriptorsFrom( - file: KotlinFile, - element: PsiElement, - projectType: ProjectType, - coreEnvironment: KotlinCoreEnvironment - ): DescriptorInfo { - val files = listOf(file.kotlinFile) - val analysis = when { - projectType.isJvmRelated() -> errorAnalyzer.analysisOf(files, coreEnvironment) - projectType.isJsRelated() -> errorAnalyzer.analyzeFileForJs(files, coreEnvironment) - projectType == ProjectType.WASM -> errorAnalyzer.analyzeFileForWasm(files, coreEnvironment) - else -> throw IllegalArgumentException("Unknown project type $projectType") - } - return with(analysis) { - (referenceVariantsFrom(element, coreEnvironment) - ?: referenceVariantsFrom(element.parent, coreEnvironment))?.let { descriptors -> - DescriptorInfo(true, descriptors) - } ?: element.parent.let { parent -> - DescriptorInfo( - isTipsManagerCompletion = false, - descriptors = when (parent) { - is KtQualifiedExpression -> { - analysisResult.bindingContext.get(BindingContext.EXPRESSION_TYPE_INFO, parent.receiverExpression) - ?.type?.let { expressionType -> - analysisResult.bindingContext.get(BindingContext.LEXICAL_SCOPE, parent.receiverExpression)?.let { - expressionType.memberScope.getContributedDescriptors( - DescriptorKindFilter.ALL, - MemberScope.ALL_NAME_FILTER - ) - } - }?.toList() ?: emptyList() - } - - else -> analysisResult.bindingContext.get(BindingContext.LEXICAL_SCOPE, element as KtExpression) - ?.getContributedDescriptors(DescriptorKindFilter.ALL, MemberScope.ALL_NAME_FILTER) - ?.toList() ?: emptyList() - } - ) - } - } - } - - private fun keywordsCompletionVariants(keywords: TokenSet, prefix: String) = keywords.types.mapNotNull { - if (it is KtKeywordToken && it.value.startsWith(prefix)) - Completion(it.value, it.value) else null - } - - private fun iconFrom(descriptor: DeclarationDescriptor) = when (descriptor) { - is FunctionDescriptor -> Icon.METHOD - is PropertyDescriptor -> Icon.PROPERTY - is LocalVariableDescriptor -> Icon.PROPERTY - is ClassDescriptor -> Icon.CLASS - is PackageFragmentDescriptor -> Icon.PACKAGE - is PackageViewDescriptor -> Icon.PACKAGE - is ValueParameterDescriptor -> Icon.GENERIC_VALUE - is TypeParameterDescriptorImpl -> Icon.CLASS - else -> null - } - - private fun KtElement.isCallableReference() = - parent is KtCallableReferenceExpression && this == (parent as KtCallableReferenceExpression).callableReference - - // This code is a fragment of org.jetbrains.kotlin.idea.completion.CompletionSession from Kotlin IDE Plugin - // with a few simplifications which were possible because webdemo has very restricted environment (and well, - // because requirements on completion' quality in web-demo are lower) - private inner class VisibilityFilter( - private val inDescriptor: DeclarationDescriptor, - private val bindingContext: BindingContext, - private val element: KtElement, - private val resolutionFacade: KotlinResolutionFacade - ) : (DeclarationDescriptor) -> Boolean { - override fun invoke(descriptor: DeclarationDescriptor): Boolean { - if (descriptor is TypeParameterDescriptor && !isTypeParameterVisible(descriptor)) return false - - if (descriptor is DeclarationDescriptorWithVisibility) { - return descriptor.isVisible(element, null, bindingContext, resolutionFacade) - } - - if (descriptor.isInternalImplementationDetail()) return false - - return true - } - - private fun isTypeParameterVisible(typeParameter: TypeParameterDescriptor): Boolean { - val owner = typeParameter.containingDeclaration - var parent: DeclarationDescriptor? = inDescriptor - while (parent != null) { - if (parent == owner) return true - if (parent is ClassDescriptor && !parent.isInner) return false - parent = parent.containingDeclaration - } - return true - } - - private fun DeclarationDescriptor.isInternalImplementationDetail(): Boolean = - importableFqName?.asString() in excludedFromCompletion - } -} diff --git a/src/main/kotlin/com/compiler/server/compiler/components/ErrorAnalyzer.kt b/src/main/kotlin/com/compiler/server/compiler/components/ErrorAnalyzer.kt deleted file mode 100644 index 6b94c0505..000000000 --- a/src/main/kotlin/com/compiler/server/compiler/components/ErrorAnalyzer.kt +++ /dev/null @@ -1,353 +0,0 @@ -package com.compiler.server.compiler.components - -import com.compiler.server.model.* -import com.intellij.openapi.util.Pair -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiElementVisitor -import com.intellij.psi.PsiErrorElement -import com.intellij.psi.PsiFile -import component.KotlinEnvironment -import model.Completion -import org.jetbrains.kotlin.analyzer.AnalysisResult -import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport -import org.jetbrains.kotlin.cli.js.klib.TopDownAnalyzerFacadeForJSIR -import org.jetbrains.kotlin.cli.js.klib.TopDownAnalyzerFacadeForWasmJs -import org.jetbrains.kotlin.cli.jvm.compiler.CliBindingTrace -import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment -import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM -import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl -import org.jetbrains.kotlin.container.* -import org.jetbrains.kotlin.context.ContextForNewModule -import org.jetbrains.kotlin.context.ModuleContext -import org.jetbrains.kotlin.context.ProjectContext -import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl -import org.jetbrains.kotlin.diagnostics.Diagnostic -import org.jetbrains.kotlin.diagnostics.Errors -import org.jetbrains.kotlin.diagnostics.Severity -import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages -import org.jetbrains.kotlin.frontend.di.configureModule -import org.jetbrains.kotlin.incremental.components.InlineConstTracker -import org.jetbrains.kotlin.incremental.components.LookupTracker -import org.jetbrains.kotlin.ir.backend.js.MainModule -import org.jetbrains.kotlin.ir.backend.js.ModulesStructure -import org.jetbrains.kotlin.js.config.JsConfig -import org.jetbrains.kotlin.js.resolve.JsPlatformAnalyzerServices -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.platform.TargetPlatform -import org.jetbrains.kotlin.platform.js.JsPlatforms -import org.jetbrains.kotlin.platform.wasm.WasmPlatforms -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.resolve.* -import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension -import org.jetbrains.kotlin.resolve.lazy.FileScopeProviderImpl -import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer -import org.jetbrains.kotlin.resolve.lazy.ResolveSession -import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory -import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory -import org.jetbrains.kotlin.wasm.resolve.WasmPlatformAnalyzerServices -import org.springframework.stereotype.Component - -@Component -class ErrorAnalyzer( - private val kotlinEnvironment: KotlinEnvironment, - private val indexationProvider: IndexationProvider -) { - fun errorsFrom( - files: List, - coreEnvironment: KotlinCoreEnvironment, - projectType: ProjectType - ): ErrorsAndAnalysis { - val analysis = when { - projectType.isJvmRelated() -> analysisOf(files, coreEnvironment) - projectType.isJsRelated() -> analyzeFileForJs(files, coreEnvironment) - projectType == ProjectType.WASM -> analyzeFileForWasm(files, coreEnvironment) - else -> throw IllegalArgumentException("Unknown platform: $projectType") - } - return ErrorsAndAnalysis( - errorsFrom( - analysis.analysisResult.bindingContext.diagnostics.all(), - CompilerDiagnostics(files.associate { it.name to analyzeErrorsFrom(it, projectType) }), - projectType - ), - analysis - ) - } - - fun analysisOf(files: List, coreEnvironment: KotlinCoreEnvironment): Analysis { - val trace = CliBindingTrace() - val project = files.first().project - val componentProvider = TopDownAnalyzerFacadeForJVM.createContainer( - project = project, - files = files, - trace = trace, - configuration = coreEnvironment.configuration, - packagePartProvider = { globalSearchScope -> - coreEnvironment.createPackagePartProvider(globalSearchScope) - }, - declarationProviderFactory = { storageManager, ktFiles -> - FileBasedDeclarationProviderFactory(storageManager, ktFiles) - } - ) - componentProvider.getService(LazyTopDownAnalyzer::class.java) - .analyzeDeclarations( - topDownAnalysisMode = TopDownAnalysisMode.TopLevelDeclarations, - declarations = files - ) - val moduleDescriptor = componentProvider.getService(ModuleDescriptor::class.java) - AnalysisHandlerExtension.getInstances(project) - .find { - it.analysisCompleted( - project = project, - module = moduleDescriptor, - bindingTrace = trace, - files = files - ) != null - } - return AnalysisJvm( - componentProvider = componentProvider, - analysisResult = AnalysisResult.success(trace.bindingContext, moduleDescriptor) - ) - } - - fun analyzeFileForJs(files: List, coreEnvironment: KotlinCoreEnvironment): Analysis { - val project = coreEnvironment.project - val configuration = JsConfig( - project, - kotlinEnvironment.jsConfiguration, - CompilerEnvironment, - kotlinEnvironment.JS_METADATA_CACHE, - kotlinEnvironment.JS_LIBRARIES.toSet() - ) - - val mainModule = MainModule.SourceFiles(files) - val sourceModule = ModulesStructure( - project, - mainModule, - kotlinEnvironment.jsConfiguration, - kotlinEnvironment.JS_LIBRARIES, - emptyList() - ) - - val mds = sourceModule.allDependencies.map { - sourceModule.getModuleDescriptor(it) as ModuleDescriptorImpl - } - - val builtInModuleDescriptor = sourceModule.builtInModuleDescriptor - - val analyzer = AnalyzerWithCompilerReport(kotlinEnvironment.jsConfiguration) - val analyzerFacade = TopDownAnalyzerFacadeForJSIR - val analysisResult = analyzerFacade.analyzeFiles( - mainModule.files, - project, - kotlinEnvironment.jsConfiguration, - mds, - emptyList(), - analyzer.targetEnvironment, - thisIsBuiltInsModule = builtInModuleDescriptor == null, - customBuiltInsModule = builtInModuleDescriptor - ) - - val context = ContextForNewModule( - projectContext = ProjectContext(project, "COMPILER-SERVER-JS"), - moduleName = Name.special("<" + configuration.moduleId + ">"), - builtIns = JsPlatformAnalyzerServices.builtIns, platform = null - ) - val dependencies = mutableSetOf(context.module) + mds + JsPlatformAnalyzerServices.builtIns.builtInsModule - context.module.setDependencies(dependencies.toList()) - val trace = CliBindingTrace() - val providerFactory = FileBasedDeclarationProviderFactory(context.storageManager, files) - val analyzerAndProvider = createContainerForTopDownAnalyzerForJs(context, trace, providerFactory, JsPlatforms.defaultJsPlatform, JsPlatformAnalyzerServices) - - val hasErrors = analyzer.hasErrors() - - sourceModule.jsFrontEndResult = ModulesStructure.JsFrontEndResult(analysisResult, hasErrors) - - return AnalysisJs( - sourceModule = sourceModule, - componentProvider = analyzerAndProvider.second, - analysisResult = analysisResult - ) - } - - fun analyzeFileForWasm(files: List, coreEnvironment: KotlinCoreEnvironment): Analysis { - val project = coreEnvironment.project - val configuration = JsConfig( - project, - kotlinEnvironment.wasmConfiguration, - CompilerEnvironment, - emptyList(), - kotlinEnvironment.WASM_LIBRARIES.toSet() - ) - - val mainModule = MainModule.SourceFiles(files) - val sourceModule = ModulesStructure( - project, - mainModule, - kotlinEnvironment.wasmConfiguration, - kotlinEnvironment.WASM_LIBRARIES, - emptyList() - ) - - val mds = sourceModule.allDependencies.map { - sourceModule.getModuleDescriptor(it) as ModuleDescriptorImpl - } - - val builtInModuleDescriptor = sourceModule.builtInModuleDescriptor - - val analyzer = AnalyzerWithCompilerReport(kotlinEnvironment.jsConfiguration) - val analyzerFacade = TopDownAnalyzerFacadeForWasmJs - val analysisResult = analyzerFacade.analyzeFiles( - mainModule.files, - project, - kotlinEnvironment.wasmConfiguration, - mds, - emptyList(), - analyzer.targetEnvironment, - thisIsBuiltInsModule = builtInModuleDescriptor == null, - customBuiltInsModule = builtInModuleDescriptor - ) - - val context = ContextForNewModule( - projectContext = ProjectContext(project, "COMPILER-SERVER-JS"), - moduleName = Name.special("<" + configuration.moduleId + ">"), - builtIns = WasmPlatformAnalyzerServices.builtIns, platform = null - ) - val dependencies = mutableSetOf(context.module) + mds + WasmPlatformAnalyzerServices.builtIns.builtInsModule - context.module.setDependencies(dependencies.toList()) - val trace = CliBindingTrace() - val providerFactory = FileBasedDeclarationProviderFactory(context.storageManager, files) - val analyzerAndProvider = createContainerForTopDownAnalyzerForJs(context, trace, providerFactory, WasmPlatforms.Default, WasmPlatformAnalyzerServices) - - val hasErrors = analyzer.hasErrors() - - sourceModule.jsFrontEndResult = ModulesStructure.JsFrontEndResult(analysisResult, hasErrors) - - return AnalysisJs( - sourceModule = sourceModule, - componentProvider = analyzerAndProvider.second, - analysisResult = analysisResult - ) - } - - fun errorsFrom( - diagnostics: Collection, - compilerDiagnostics: CompilerDiagnostics, - projectType: ProjectType - ): CompilerDiagnostics = (compilerDiagnostics.map and errorsFrom(diagnostics, projectType)).map { (fileName, errors) -> - fileName to errors.sortedWith(Comparator.comparing({ it.interval?.start }, nullsFirst())) - }.toMap().let(::CompilerDiagnostics) - - private fun analyzeErrorsFrom(file: PsiFile, projectType: ProjectType): List { - class Visitor : PsiElementVisitor() { - val errors = mutableListOf() - override fun visitElement(element: PsiElement) { - element.acceptChildren(this) - } - - override fun visitErrorElement(element: PsiErrorElement) { - errors.add(element) - } - } - return Visitor().apply { visitFile(file) }.errors.map { - ErrorDescriptor( - interval = TextInterval.from( - start = it.textRange.startOffset, - end = it.textRange.endOffset, - currentDocument = file.viewProvider.document!! - ), - message = it.errorDescription, - severity = ProjectSeveriry.ERROR, - className = "red_wavy_line", - imports = completionsForErrorMessage(it.errorDescription, projectType) - ) - } - } - - private fun createContainerForTopDownAnalyzerForJs( - moduleContext: ModuleContext, - bindingTrace: BindingTrace, - declarationProviderFactory: DeclarationProviderFactory, - platform: TargetPlatform, - analyzerServices: PlatformDependentAnalyzerServices - ): Pair { - val container = composeContainer( - "TopDownAnalyzerForJs", - analyzerServices.platformConfigurator.platformSpecificContainer - ) { - configureModule( - moduleContext = moduleContext, - platform = platform, - analyzerServices = analyzerServices, - trace = bindingTrace, - languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT, - optimizingOptions = null, - absentDescriptorHandlerClass = null - ) - useInstance(declarationProviderFactory) - registerSingleton(AnnotationResolverImpl::class.java) - registerSingleton(FileScopeProviderImpl::class.java) - CompilerEnvironment.configure(this) - useInstance(LookupTracker.DO_NOTHING) - useInstance(InlineConstTracker.DoNothing) - registerSingleton(ResolveSession::class.java) - registerSingleton(LazyTopDownAnalyzer::class.java) - } - - container.getService(ModuleDescriptorImpl::class.java) - .initialize(container.getService(KotlinCodeAnalyzer::class.java).packageFragmentProvider) - return Pair(container.getService(LazyTopDownAnalyzer::class.java), container) - } - - private fun errorsFrom( - diagnostics: Collection, - projectType: ProjectType - ) = diagnostics.mapNotNull { diagnostic -> - diagnostic.psiFile.virtualFile?.let { - val render = DefaultErrorMessages.render(diagnostic) - if (!render.contains("This cast can never succeed")) { - if (diagnostic.severity != Severity.INFO) { - val textRanges = diagnostic.textRanges.iterator() - if (textRanges.hasNext()) { - var className = diagnostic.severity.name - val imports = if (diagnostic.factory === Errors.UNRESOLVED_REFERENCE) { - completionsForErrorMessage(render, projectType) - } else null - if (!(diagnostic.factory === Errors.UNRESOLVED_REFERENCE) && diagnostic.severity == Severity.ERROR) { - className = "red_wavy_line" - } - val firstRange = textRanges.next() - val interval = TextInterval.from( - firstRange.startOffset, - firstRange.endOffset, - diagnostic.psiFile.viewProvider.document!! - ) - diagnostic.psiFile.name to ErrorDescriptor( - interval = interval, - message = render, - severity = ProjectSeveriry.from(diagnostic.severity), - className = className, - imports = imports - ) - } else null - } else null - } else null - } - }.groupBy { it.first }.map { it.key to it.value.map { (_, error) -> error } }.toMap() - - private infix fun Map>.and(errors: Map>) = - (this.toList() + errors.toList()) - .groupBy { it.first } - .map { it.key to it.value.fold(emptyList()) { acc, (_, errors) -> acc + errors } } - .toMap() - - private fun completionsForErrorMessage(message: String, projectType: ProjectType): List? { - if (!indexationProvider.hasIndexes(projectType) || - !message.startsWith(IndexationProvider.UNRESOLVED_REFERENCE_PREFIX) - ) return null - val name = message.removePrefix(IndexationProvider.UNRESOLVED_REFERENCE_PREFIX) - return indexationProvider.getClassesByName(name, projectType)?.map { suggest -> suggest.toCompletion() } - } -} - -data class ErrorsAndAnalysis(val compilerDiagnostics: CompilerDiagnostics, val analysis: Analysis) diff --git a/src/main/kotlin/com/compiler/server/compiler/components/IndexationProvider.kt b/src/main/kotlin/com/compiler/server/compiler/components/IndexationProvider.kt deleted file mode 100644 index 3888de89e..000000000 --- a/src/main/kotlin/com/compiler/server/compiler/components/IndexationProvider.kt +++ /dev/null @@ -1,67 +0,0 @@ -package com.compiler.server.compiler.components - -import com.compiler.server.model.ProjectType -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import com.fasterxml.jackson.module.kotlin.readValue -import model.ImportInfo -import org.apache.commons.logging.LogFactory -import org.springframework.beans.factory.annotation.Value -import org.springframework.stereotype.Component -import java.io.File - -@Component -class IndexationProvider( - @Value("\${indexes.file}") private val indexesFileName: String, - @Value("\${indexesJs.file}") private val indexesJsFileName: String, - @Value("\${indexesWasm.file}") private val indexesWasmFileName: String -) { - companion object { - const val UNRESOLVED_REFERENCE_PREFIX = "Unresolved reference: " - private val log = LogFactory.getLog(IndexationProvider::class.java) - } - - private val jvmIndexes: Map>? by lazy { - initIndexes(indexesFileName) - } - - private val jsIndexes: Map>? by lazy { - initIndexes(indexesJsFileName) - } - - private val wasmIndexes: Map>? by lazy { - initIndexes(indexesWasmFileName) - } - - fun hasIndexes(projectType: ProjectType) = when { - projectType.isJsRelated() -> jsIndexes != null - projectType.isJvmRelated() -> jvmIndexes != null - projectType == ProjectType.WASM -> wasmIndexes != null - else -> throw IllegalArgumentException("Platform $projectType not found") - } - - fun getClassesByName(name: String, projectType: ProjectType): List? { - val indexes = when { - projectType.isJsRelated() -> jsIndexes - projectType.isJvmRelated() -> jvmIndexes - projectType == ProjectType.WASM -> wasmIndexes - else -> throw IllegalArgumentException("Platform $projectType not found") - } - return indexes?.get(name) - } - - private fun initIndexes(fileName: String): Map>? { - val file = File(fileName) - if (file.exists().not()) { - log.warn("No file was found at path: $fileName") - return null - } - val indexes = runCatching { readIndexesFromJson(file) }.getOrNull() - if (indexes == null) { - log.warn("Can not parse file=$fileName with indexes") - } - return indexes - } - - private fun readIndexesFromJson(file: File): Map> = - jacksonObjectMapper().readValue(file.readText()) -} \ No newline at end of file diff --git a/src/main/kotlin/com/compiler/server/compiler/components/KotlinCompiler.kt b/src/main/kotlin/com/compiler/server/compiler/components/KotlinCompiler.kt index a969ea1c8..5aeae0bb9 100644 --- a/src/main/kotlin/com/compiler/server/compiler/components/KotlinCompiler.kt +++ b/src/main/kotlin/com/compiler/server/compiler/components/KotlinCompiler.kt @@ -4,13 +4,13 @@ import com.compiler.server.executor.CommandLineArgument import com.compiler.server.executor.JavaExecutor import com.compiler.server.model.ExecutionResult import com.compiler.server.model.OutputDirectory +import com.compiler.server.model.ProjectFile import com.compiler.server.model.bean.LibrariesFile import com.compiler.server.model.toExceptionDescriptor import component.KotlinEnvironment import executors.JUnitExecutors import executors.JavaRunnerExecutor import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler -import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.org.objectweb.asm.ClassReader import org.jetbrains.org.objectweb.asm.ClassReader.* import org.jetbrains.org.objectweb.asm.ClassVisitor @@ -38,7 +38,7 @@ class KotlinCompiler( val mainClasses: Set = emptySet() ) - fun run(files: List, args: String): ExecutionResult { + fun run(files: List, args: String): ExecutionResult { return execute(files) { output, compiled -> val mainClass = JavaRunnerExecutor::class.java.name val compiledMainClass = when (compiled.mainClasses.size) { @@ -59,7 +59,7 @@ class KotlinCompiler( } } - fun test(files: List): ExecutionResult { + fun test(files: List): ExecutionResult { return execute(files) { output, _ -> val mainClass = JUnitExecutors::class.java.name javaExecutor.execute(argsFrom(mainClass, output, listOf(output.path.toString()))) @@ -68,7 +68,7 @@ class KotlinCompiler( } @OptIn(ExperimentalPathApi::class) - fun compile(files: List): CompilationResult = usingTempDirectory { inputDir -> + fun compile(files: List): CompilationResult = usingTempDirectory { inputDir -> val ioFiles = files.writeToIoFiles(inputDir) usingTempDirectory { outputDir -> val arguments = ioFiles.map { it.absolutePathString() } + KotlinEnvironment.additionalCompilerArguments + listOf( @@ -116,7 +116,7 @@ class KotlinCompiler( }.toSet() private fun execute( - files: List, + files: List, block: (output: OutputDirectory, compilation: JvmClasses) -> ExecutionResult ): ExecutionResult = try { when (val compilationResult = compile(files)) { diff --git a/src/main/kotlin/com/compiler/server/compiler/components/KotlinToJSTranslator.kt b/src/main/kotlin/com/compiler/server/compiler/components/KotlinToJSTranslator.kt index b98c17ea9..54f08138d 100644 --- a/src/main/kotlin/com/compiler/server/compiler/components/KotlinToJSTranslator.kt +++ b/src/main/kotlin/com/compiler/server/compiler/components/KotlinToJSTranslator.kt @@ -4,7 +4,6 @@ import com.compiler.server.model.* import com.fasterxml.jackson.databind.ObjectMapper import component.KotlinEnvironment import org.jetbrains.kotlin.cli.js.K2JsIrCompiler -import org.jetbrains.kotlin.psi.KtFile import org.springframework.stereotype.Service import kotlin.io.path.div import kotlin.io.path.readBytes @@ -29,9 +28,9 @@ class KotlinToJSTranslator( } fun translateJs( - files: List, + files: List, arguments: List, - translate: (List, List) -> CompilationResult + translate: (List, List) -> CompilationResult ): TranslationJSResult = try { val compilationResult = translate(files, arguments) val jsCode = when (compilationResult) { @@ -44,8 +43,8 @@ class KotlinToJSTranslator( } fun translateWasm( - files: List, - translate: (List) -> CompilationResult + files: List, + translate: (List) -> CompilationResult ): TranslationResultWithJsCode { return try { val compilationResult = translate(files) @@ -65,7 +64,7 @@ class KotlinToJSTranslator( } } - fun doTranslateWithIr(files: List, arguments: List): CompilationResult = + fun doTranslateWithIr(files: List, arguments: List): CompilationResult = usingTempDirectory { inputDir -> val moduleName = "moduleId" usingTempDirectory { outputDir -> @@ -109,7 +108,7 @@ class KotlinToJSTranslator( } - fun doTranslateWithWasm(files: List): CompilationResult = + fun doTranslateWithWasm(files: List): CompilationResult = usingTempDirectory { inputDir -> val moduleName = "moduleId" usingTempDirectory { outputDir -> diff --git a/src/main/kotlin/com/compiler/server/executor/ExecutorMessages.kt b/src/main/kotlin/com/compiler/server/executor/ExecutorMessages.kt index d0fbc6451..dcd5cade2 100644 --- a/src/main/kotlin/com/compiler/server/executor/ExecutorMessages.kt +++ b/src/main/kotlin/com/compiler/server/executor/ExecutorMessages.kt @@ -3,5 +3,4 @@ package com.compiler.server.executor object ExecutorMessages { const val TIMEOUT_MESSAGE = "Evaluation stopped while it's taking too long️" const val TOO_LONG_OUTPUT_MESSAGE = "Evaluation stopped while log size exceeded max size" - const val NO_COMPILERS_FILE_FOUND = "No compilation files found!" } \ No newline at end of file diff --git a/src/main/kotlin/com/compiler/server/model/Analysis.kt b/src/main/kotlin/com/compiler/server/model/Analysis.kt deleted file mode 100644 index 51a0a8f10..000000000 --- a/src/main/kotlin/com/compiler/server/model/Analysis.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.compiler.server.model - -import org.jetbrains.kotlin.analyzer.AnalysisResult -import org.jetbrains.kotlin.container.ComponentProvider -import org.jetbrains.kotlin.ir.backend.js.ModulesStructure - -interface Analysis { - val componentProvider: ComponentProvider - val analysisResult: AnalysisResult -} - -data class AnalysisJvm( - override val componentProvider: ComponentProvider, - override val analysisResult: AnalysisResult -) : Analysis - -data class AnalysisJs( - val sourceModule: ModulesStructure, - override val componentProvider: ComponentProvider, - override val analysisResult: AnalysisResult -) : Analysis \ No newline at end of file diff --git a/src/main/kotlin/com/compiler/server/model/Project.kt b/src/main/kotlin/com/compiler/server/model/Project.kt index b2a5bf86c..b0894d756 100644 --- a/src/main/kotlin/com/compiler/server/model/Project.kt +++ b/src/main/kotlin/com/compiler/server/model/Project.kt @@ -20,8 +20,4 @@ enum class ProjectType(@JsonValue val id: String) { CANVAS("canvas"), JS_IR("js-ir"), WASM("wasm"); - - fun isJvmRelated(): Boolean = this == JAVA || this == JUNIT - - fun isJsRelated(): Boolean = this == JS_IR || this == JS || this == CANVAS } \ No newline at end of file diff --git a/src/main/kotlin/com/compiler/server/service/KotlinProjectExecutor.kt b/src/main/kotlin/com/compiler/server/service/KotlinProjectExecutor.kt index ced520536..4e16b4641 100644 --- a/src/main/kotlin/com/compiler/server/service/KotlinProjectExecutor.kt +++ b/src/main/kotlin/com/compiler/server/service/KotlinProjectExecutor.kt @@ -1,40 +1,28 @@ package com.compiler.server.service -import com.compiler.server.compiler.KotlinFile import com.compiler.server.compiler.components.* import com.compiler.server.model.* import com.compiler.server.model.bean.VersionInfo -import component.KotlinEnvironment import model.Completion -import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment -import org.jetbrains.kotlin.psi.KtFile import org.slf4j.LoggerFactory import org.springframework.stereotype.Component @Component class KotlinProjectExecutor( private val kotlinCompiler: KotlinCompiler, - private val completionProvider: CompletionProvider, private val version: VersionInfo, private val kotlinToJSTranslator: KotlinToJSTranslator, - private val kotlinEnvironment: KotlinEnvironment, private val loggerDetailsStreamer: LoggerDetailsStreamer? = null, ) { private val log = LoggerFactory.getLogger(KotlinProjectExecutor::class.java) fun run(project: Project): ExecutionResult { - return kotlinEnvironment.environment { environment -> - val files = getFilesFrom(project, environment).map { it.kotlinFile } - kotlinCompiler.run(files, project.args) - }.also { logExecutionResult(project, it) } + return kotlinCompiler.run(project.files, project.args).also { logExecutionResult(project, it) } } fun test(project: Project): ExecutionResult { - return kotlinEnvironment.environment { environment -> - val files = getFilesFrom(project, environment).map { it.kotlinFile } - kotlinCompiler.test(files) - }.also { logExecutionResult(project, it) } + return kotlinCompiler.test(project.files).also { logExecutionResult(project, it) } } fun convertToJsIr(project: Project): TranslationJSResult { @@ -42,26 +30,16 @@ class KotlinProjectExecutor( } fun compileToJvm(project: Project): CompilationResult { - val files = kotlinEnvironment.environment { environment -> - getFilesFrom(project, environment).map { it.kotlinFile } - } - return kotlinCompiler.compile(files) + return kotlinCompiler.compile(project.files) } fun convertToWasm(project: Project): TranslationResultWithJsCode { return convertWasmWithConverter(project, kotlinToJSTranslator::doTranslateWithWasm) } + @Suppress("unused") fun complete(project: Project, line: Int, character: Int): List { - return kotlinEnvironment.environment { - val file = getFilesFrom(project, it).first() - try { - completionProvider.complete(file, line, character, project.confType, it) - } catch (e: Exception) { - log.warn("Exception in getting completions. Project: $project", e) - emptyList() - } - } + return emptyList() } fun highlight(project: Project): CompilerDiagnostics = try { @@ -79,22 +57,18 @@ class KotlinProjectExecutor( private fun convertJsWithConverter( project: Project, - converter: (List, List) -> CompilationResult + converter: (List, List) -> CompilationResult ): TranslationJSResult { - return kotlinEnvironment.environment { environment -> - val files = getFilesFrom(project, environment).map { it.kotlinFile } - kotlinToJSTranslator.translateJs(files, project.args.split(" "), converter) - }.also { logExecutionResult(project, it) } + return kotlinToJSTranslator.translateJs(project.files, project.args.split(" "), converter) + .also { logExecutionResult(project, it) } } private fun convertWasmWithConverter( project: Project, - converter: (List) -> CompilationResult + converter: (List) -> CompilationResult ): TranslationResultWithJsCode { - return kotlinEnvironment.environment { environment -> - val files = getFilesFrom(project, environment).map { it.kotlinFile } - kotlinToJSTranslator.translateWasm(files, converter) - }.also { logExecutionResult(project, it) } + return kotlinToJSTranslator.translateWasm(project.files, converter) + .also { logExecutionResult(project, it) } } private fun logExecutionResult(project: Project, executionResult: ExecutionResult) { @@ -104,8 +78,4 @@ class KotlinProjectExecutor( getVersion().version ) } - - private fun getFilesFrom(project: Project, coreEnvironment: KotlinCoreEnvironment) = project.files.map { - KotlinFile.from(coreEnvironment.project, it.name, it.text) - } } diff --git a/src/test/kotlin/com/compiler/server/CompletionTest.kt b/src/test/kotlin/com/compiler/server/CompletionTest.kt index 9737aae17..1c1efa106 100644 --- a/src/test/kotlin/com/compiler/server/CompletionTest.kt +++ b/src/test/kotlin/com/compiler/server/CompletionTest.kt @@ -2,7 +2,9 @@ package com.compiler.server import com.compiler.server.base.BaseExecutorTest import org.junit.jupiter.api.Test +import kotlin.test.Ignore +@Ignore class CompletionTest : BaseExecutorTest() { @Test fun `variable completion test`() { diff --git a/src/test/kotlin/com/compiler/server/ConcurrencyRunnerTest.kt b/src/test/kotlin/com/compiler/server/ConcurrencyRunnerTest.kt index 0b5a8fecb..db56445ca 100644 --- a/src/test/kotlin/com/compiler/server/ConcurrencyRunnerTest.kt +++ b/src/test/kotlin/com/compiler/server/ConcurrencyRunnerTest.kt @@ -5,6 +5,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import org.junit.jupiter.api.Test +import kotlin.test.Ignore class ConcurrencyRunnerTest : BaseExecutorTest() { @Test @@ -17,6 +18,7 @@ class ConcurrencyRunnerTest : BaseExecutorTest() { } } + @Ignore @Test fun `a lot of complete test`() { runManyTest { @@ -31,6 +33,7 @@ class ConcurrencyRunnerTest : BaseExecutorTest() { } } + @Ignore @Test fun `a lot of complete test JS`() { runManyTest { diff --git a/src/test/kotlin/com/compiler/server/ImportTest.kt b/src/test/kotlin/com/compiler/server/ImportTest.kt index 75271c999..f4e8182b6 100644 --- a/src/test/kotlin/com/compiler/server/ImportTest.kt +++ b/src/test/kotlin/com/compiler/server/ImportTest.kt @@ -4,7 +4,9 @@ import com.compiler.server.base.BaseExecutorTest import model.Completion import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test +import kotlin.test.Ignore +@Ignore class ImportTest : BaseExecutorTest() { @Test fun `import class`() {