Reformat module 'cli', fix warnings/inspections

This commit is contained in:
Alexander Udalov
2018-07-26 18:28:18 +02:00
parent 21a7561271
commit 2d875a9cb4
77 changed files with 848 additions and 935 deletions
@@ -17,15 +17,17 @@
package org.jetbrains.kotlin.cli.common package org.jetbrains.kotlin.cli.common
import org.fusesource.jansi.AnsiConsole import org.fusesource.jansi.AnsiConsole
import org.jetbrains.kotlin.cli.common.arguments.* import org.jetbrains.kotlin.cli.common.arguments.CommonToolArguments
import org.jetbrains.kotlin.cli.common.arguments.ManualLanguageFeatureSetting
import org.jetbrains.kotlin.cli.common.arguments.parseCommandLineArguments
import org.jetbrains.kotlin.cli.common.arguments.validateArguments
import org.jetbrains.kotlin.cli.common.messages.* import org.jetbrains.kotlin.cli.common.messages.*
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.INFO import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.INFO
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.STRONG_WARNING import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.STRONG_WARNING
import org.jetbrains.kotlin.cli.jvm.compiler.CompileEnvironmentException import org.jetbrains.kotlin.cli.jvm.compiler.CompileEnvironmentException
import org.jetbrains.kotlin.config.KotlinCompilerVersion import org.jetbrains.kotlin.config.KotlinCompilerVersion
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature.Kind.BUG_FIX
import org.jetbrains.kotlin.config.LanguageFeature.Kind.* import org.jetbrains.kotlin.config.LanguageFeature.State.ENABLED
import org.jetbrains.kotlin.config.LanguageFeature.State.*
import org.jetbrains.kotlin.config.Services import org.jetbrains.kotlin.config.Services
import java.io.PrintStream import java.io.PrintStream
import java.net.URL import java.net.URL
@@ -196,13 +198,11 @@ abstract class CLITool<A : CommonToolArguments> {
} }
@JvmStatic @JvmStatic
fun doMainNoExit(compiler: CLITool<*>, args: Array<String>): ExitCode { fun doMainNoExit(compiler: CLITool<*>, args: Array<String>): ExitCode = try {
try { compiler.exec(System.err, *args)
return compiler.exec(System.err, *args) } catch (e: CompileEnvironmentException) {
} catch (e: CompileEnvironmentException) { System.err.println(e.message)
System.err.println(e.message) ExitCode.INTERNAL_ERROR
return ExitCode.INTERNAL_ERROR
}
} }
} }
} }
@@ -11,6 +11,7 @@ import java.lang.management.ManagementFactory
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
abstract class CommonCompilerPerformanceManager(private val presentableName: String) { abstract class CommonCompilerPerformanceManager(private val presentableName: String) {
@Suppress("MemberVisibilityCanBePrivate")
protected val measurements: MutableList<PerformanceMeasurement> = mutableListOf() protected val measurements: MutableList<PerformanceMeasurement> = mutableListOf()
protected var isEnabled: Boolean = false protected var isEnabled: Boolean = false
private var initStartNanos = PerformanceCounter.currentTime() private var initStartNanos = PerformanceCounter.currentTime()
@@ -50,13 +50,19 @@ class AnalyzerWithCompilerReport(
val bindingContext = analysisResult.bindingContext val bindingContext = analysisResult.bindingContext
val classes = bindingContext.getKeys(TraceBasedErrorReporter.INCOMPLETE_HIERARCHY) val classes = bindingContext.getKeys(TraceBasedErrorReporter.INCOMPLETE_HIERARCHY)
if (!classes.isEmpty()) { if (!classes.isEmpty()) {
val message = StringBuilder("Supertypes of the following classes cannot be resolved. " + val message = StringBuilder(
"Please make sure you have the required dependencies in the classpath:\n") "Supertypes of the following classes cannot be resolved. " +
"Please make sure you have the required dependencies in the classpath:\n"
)
for (descriptor in classes) { for (descriptor in classes) {
val fqName = DescriptorUtils.getFqName(descriptor).asString() val fqName = DescriptorUtils.getFqName(descriptor).asString()
val unresolved = bindingContext.get(TraceBasedErrorReporter.INCOMPLETE_HIERARCHY, descriptor) val unresolved = bindingContext.get(TraceBasedErrorReporter.INCOMPLETE_HIERARCHY, descriptor)
assert(unresolved != null && !unresolved.isEmpty()) { "Incomplete hierarchy should be reported with names of unresolved superclasses: " + fqName } assert(unresolved != null && !unresolved.isEmpty()) {
message.append(" class ").append(fqName).append(", unresolved supertypes: ").append(unresolved!!.joinToString()).append("\n") "Incomplete hierarchy should be reported with names of unresolved superclasses: $fqName"
}
message.append(" class ").append(fqName)
.append(", unresolved supertypes: ").append(unresolved!!.joinToString())
.append("\n")
} }
messageCollector.report(ERROR, message.toString()) messageCollector.report(ERROR, message.toString())
} }
@@ -110,8 +116,9 @@ class AnalyzerWithCompilerReport(
reportAlternativeSignatureErrors() reportAlternativeSignatureErrors()
} }
private class MyDiagnostic<E : PsiElement>(psiElement: E, factory: DiagnosticFactory0<E>, private class MyDiagnostic<E : PsiElement>(
val message: String) : SimpleDiagnostic<E>(psiElement, factory, Severity.ERROR) { psiElement: E, factory: DiagnosticFactory0<E>, val message: String
) : SimpleDiagnostic<E>(psiElement, factory, Severity.ERROR) {
override fun isValid(): Boolean = true override fun isValid(): Boolean = true
} }
@@ -122,7 +129,7 @@ class AnalyzerWithCompilerReport(
Severity.INFO -> INFO Severity.INFO -> INFO
Severity.ERROR -> ERROR Severity.ERROR -> ERROR
Severity.WARNING -> WARNING Severity.WARNING -> WARNING
else -> throw IllegalStateException("Unknown severity: " + severity) else -> throw IllegalStateException("Unknown severity: $severity")
} }
private val SYNTAX_ERROR_FACTORY = DiagnosticFactory0.create<PsiErrorElement>(Severity.ERROR) private val SYNTAX_ERROR_FACTORY = DiagnosticFactory0.create<PsiErrorElement>(Severity.ERROR)
@@ -131,9 +138,9 @@ class AnalyzerWithCompilerReport(
if (!diagnostic.isValid) return false if (!diagnostic.isValid) return false
reporter.report( reporter.report(
diagnostic, diagnostic,
diagnostic.psiFile, diagnostic.psiFile,
(diagnostic as? MyDiagnostic<*>)?.message ?: DefaultErrorMessages.render(diagnostic) (diagnostic as? MyDiagnostic<*>)?.message ?: DefaultErrorMessages.render(diagnostic)
) )
return diagnostic.severity == Severity.ERROR return diagnostic.severity == Severity.ERROR
@@ -159,9 +166,9 @@ class AnalyzerWithCompilerReport(
if (hasIncompatibleClassErrors) { if (hasIncompatibleClassErrors) {
messageCollector.report( messageCollector.report(
ERROR, ERROR,
"Incompatible classes were found in dependencies. " + "Incompatible classes were found in dependencies. " +
"Remove them from the classpath or use '-Xskip-metadata-version-check' to suppress errors" "Remove them from the classpath or use '-Xskip-metadata-version-check' to suppress errors"
) )
} }
@@ -192,8 +199,10 @@ class AnalyzerWithCompilerReport(
override fun visitErrorElement(element: PsiErrorElement) { override fun visitErrorElement(element: PsiErrorElement) {
val description = element.errorDescription val description = element.errorDescription
reportDiagnostic(element, SYNTAX_ERROR_FACTORY, reportDiagnostic(
if (StringUtil.isEmpty(description)) "Syntax error" else description) element, SYNTAX_ERROR_FACTORY,
if (StringUtil.isEmpty(description)) "Syntax error" else description
)
} }
} }
@@ -210,29 +219,29 @@ class AnalyzerWithCompilerReport(
fun reportBytecodeVersionErrors(bindingContext: BindingContext, messageCollector: MessageCollector) { fun reportBytecodeVersionErrors(bindingContext: BindingContext, messageCollector: MessageCollector) {
val severity = val severity =
if (System.getProperty("kotlin.jvm.disable.bytecode.version.error") == "true") STRONG_WARNING if (System.getProperty("kotlin.jvm.disable.bytecode.version.error") == "true") STRONG_WARNING
else ERROR else ERROR
val locations = bindingContext.getKeys(IncompatibleClassTrackerImpl.BYTECODE_VERSION_ERRORS) val locations = bindingContext.getKeys(IncompatibleClassTrackerImpl.BYTECODE_VERSION_ERRORS)
if (locations.isEmpty()) return if (locations.isEmpty()) return
for (location in locations) { for (location in locations) {
val data = bindingContext.get(IncompatibleClassTrackerImpl.BYTECODE_VERSION_ERRORS, location) val data = bindingContext.get(IncompatibleClassTrackerImpl.BYTECODE_VERSION_ERRORS, location)
?: error("Value is missing for key in binding context: " + location) ?: error("Value is missing for key in binding context: $location")
reportIncompatibleBinaryVersion(messageCollector, data, severity) reportIncompatibleBinaryVersion(messageCollector, data, severity)
} }
} }
private fun reportIncompatibleBinaryVersion( private fun reportIncompatibleBinaryVersion(
messageCollector: MessageCollector, messageCollector: MessageCollector,
data: IncompatibleVersionErrorData<JvmBytecodeBinaryVersion>, data: IncompatibleVersionErrorData<JvmBytecodeBinaryVersion>,
severity: CompilerMessageSeverity severity: CompilerMessageSeverity
) { ) {
messageCollector.report( messageCollector.report(
severity, severity,
"Class '" + JvmClassName.byClassId(data.classId) + "' was compiled with an incompatible version of Kotlin. " + "Class '" + JvmClassName.byClassId(data.classId) + "' was compiled with an incompatible version of Kotlin. " +
"The binary version of its bytecode is " + data.actualVersion + ", expected version is " + data.expectedVersion, "The binary version of its bytecode is " + data.actualVersion + ", expected version is " + data.expectedVersion,
CompilerMessageLocation.create(toSystemDependentName(data.filePath)) CompilerMessageLocation.create(toSystemDependentName(data.filePath))
) )
} }
} }
@@ -26,12 +26,11 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticUtils
class DefaultDiagnosticReporter(override val messageCollector: MessageCollector) : MessageCollectorBasedReporter class DefaultDiagnosticReporter(override val messageCollector: MessageCollector) : MessageCollectorBasedReporter
interface MessageCollectorBasedReporter : DiagnosticMessageReporter { interface MessageCollectorBasedReporter : DiagnosticMessageReporter {
val messageCollector: MessageCollector val messageCollector: MessageCollector
override fun report(diagnostic: Diagnostic, file: PsiFile, render: String) = messageCollector.report( override fun report(diagnostic: Diagnostic, file: PsiFile, render: String) = messageCollector.report(
AnalyzerWithCompilerReport.convertSeverity(diagnostic.severity), AnalyzerWithCompilerReport.convertSeverity(diagnostic.severity),
render, render,
MessageUtil.psiFileToMessageLocation(file, file.name, DiagnosticUtils.getLineAndColumn(diagnostic)) MessageUtil.psiFileToMessageLocation(file, file.name, DiagnosticUtils.getLineAndColumn(diagnostic))
) )
} }
@@ -29,15 +29,13 @@ import org.jetbrains.kotlin.util.ModuleVisibilityHelper
import java.io.File import java.io.File
class ModuleVisibilityHelperImpl : ModuleVisibilityHelper { class ModuleVisibilityHelperImpl : ModuleVisibilityHelper {
override fun isInFriendModule(what: DeclarationDescriptor, from: DeclarationDescriptor): Boolean { override fun isInFriendModule(what: DeclarationDescriptor, from: DeclarationDescriptor): Boolean {
val fromSource = getSourceElement(from) val fromSource = getSourceElement(from)
// We should check accessibility of 'from' in current module (some set of source files, which are compiled together), // We should check accessibility of 'from' in current module (some set of source files, which are compiled together),
// so we can assume that 'from' should have sources or is a LazyPackageDescriptor with some package files. // so we can assume that 'from' should have sources or is a LazyPackageDescriptor with some package files.
val project: Project = if (fromSource is KotlinSourceElement) { val project: Project = if (fromSource is KotlinSourceElement) {
fromSource.psi.project fromSource.psi.project
} } else {
else {
(from as? LazyPackageDescriptor)?.declarationProvider?.getPackageFiles()?.firstOrNull()?.project ?: return true (from as? LazyPackageDescriptor)?.declarationProvider?.getPackageFiles()?.firstOrNull()?.project ?: return true
} }
@@ -70,11 +68,10 @@ class ModuleVisibilityHelperImpl : ModuleVisibilityHelper {
val sourceElement = getSourceElement(descriptor) val sourceElement = getSourceElement(descriptor)
return if (sourceElement is KotlinSourceElement) { return if (sourceElement is KotlinSourceElement) {
modules.singleOrNull() ?: modules.firstOrNull { sourceElement.psi.containingKtFile.virtualFile.path in it.getSourceFiles() } modules.singleOrNull() ?: modules.firstOrNull { sourceElement.psi.containingKtFile.virtualFile.path in it.getSourceFiles() }
} } else {
else {
modules.firstOrNull { module -> modules.firstOrNull { module ->
isContainedByCompiledPartOfOurModule(descriptor, File(module.getOutputDirectory())) || isContainedByCompiledPartOfOurModule(descriptor, File(module.getOutputDirectory())) ||
module.getFriendPaths().any { isContainedByCompiledPartOfOurModule(descriptor, File(it)) } module.getFriendPaths().any { isContainedByCompiledPartOfOurModule(descriptor, File(it)) }
} }
} }
} }
@@ -86,7 +83,7 @@ class ModuleVisibilityHelperImpl : ModuleVisibilityHelper {
*/ */
class CliModuleVisibilityManagerImpl(override val enabled: Boolean) : ModuleVisibilityManager, Disposable { class CliModuleVisibilityManagerImpl(override val enabled: Boolean) : ModuleVisibilityManager, Disposable {
override val chunk: MutableList<Module> = arrayListOf() override val chunk: MutableList<Module> = arrayListOf()
override val friendPaths: MutableList <String> = arrayListOf() override val friendPaths: MutableList<String> = arrayListOf()
override fun addModule(module: Module) { override fun addModule(module: Module) {
chunk.add(module) chunk.add(module)
@@ -27,10 +27,7 @@ import kotlin.concurrent.read
import kotlin.concurrent.write import kotlin.concurrent.write
import kotlin.script.experimental.dependencies.ScriptDependencies import kotlin.script.experimental.dependencies.ScriptDependencies
class CliScriptDependenciesProvider( class CliScriptDependenciesProvider(private val project: Project) : ScriptDependenciesProvider {
private val project: Project
) : ScriptDependenciesProvider {
private val cacheLock = ReentrantReadWriteLock() private val cacheLock = ReentrantReadWriteLock()
private val cache = hashMapOf<String, ScriptDependencies?>() private val cache = hashMapOf<String, ScriptDependencies?>()
private val scriptContentLoader = ScriptContentLoader(project) private val scriptContentLoader = ScriptContentLoader(project)
@@ -59,8 +56,7 @@ class CliScriptDependenciesProvider(
cache.put(path, deps) cache.put(path, deps)
} }
deps deps
} } else null
else null
} }
} }
} }
@@ -36,7 +36,7 @@ class CliScriptReportSink(private val messageCollector: MessageCollector) : Scri
return CompilerMessageLocation.create(scriptFile.path, position.startLine, position.startColumn, null) return CompilerMessageLocation.create(scriptFile.path, position.startLine, position.startColumn, null)
} }
private fun ScriptReport.Severity.convertSeverity(): CompilerMessageSeverity = when(this) { private fun ScriptReport.Severity.convertSeverity(): CompilerMessageSeverity = when (this) {
ScriptReport.Severity.FATAL -> CompilerMessageSeverity.ERROR ScriptReport.Severity.FATAL -> CompilerMessageSeverity.ERROR
ScriptReport.Severity.ERROR -> CompilerMessageSeverity.ERROR ScriptReport.Severity.ERROR -> CompilerMessageSeverity.ERROR
ScriptReport.Severity.WARNING -> CompilerMessageSeverity.WARNING ScriptReport.Severity.WARNING -> CompilerMessageSeverity.WARNING
@@ -44,4 +44,3 @@ class CliScriptReportSink(private val messageCollector: MessageCollector) : Scri
ScriptReport.Severity.DEBUG -> CompilerMessageSeverity.LOGGING ScriptReport.Severity.DEBUG -> CompilerMessageSeverity.LOGGING
} }
} }
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.messages.MessageUtil import org.jetbrains.kotlin.cli.common.messages.MessageUtil
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.isSubpackageOf import org.jetbrains.kotlin.name.isSubpackageOf
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
@@ -30,15 +29,16 @@ fun checkKotlinPackageUsage(environment: KotlinCoreEnvironment, files: Collectio
return true return true
} }
val messageCollector = environment.configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollector.NONE) val messageCollector = environment.configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollector.NONE)
val kotlinPackage = FqName.topLevel(Name.identifier("kotlin")) val kotlinPackage = FqName("kotlin")
files.forEach { for (file in files) {
if (it.packageFqName.isSubpackageOf(kotlinPackage)) { if (file.packageFqName.isSubpackageOf(kotlinPackage)) {
messageCollector.report(CompilerMessageSeverity.ERROR, messageCollector.report(
"Only the Kotlin standard library is allowed to use the 'kotlin' package", CompilerMessageSeverity.ERROR,
MessageUtil.psiElementToMessageLocation(it.packageDirective!!)) "Only the Kotlin standard library is allowed to use the 'kotlin' package",
MessageUtil.psiElementToMessageLocation(file.packageDirective!!)
)
return false return false
} }
} }
return true return true
} }
@@ -24,7 +24,6 @@ import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ExceptionUtil; import com.intellij.util.ExceptionUtil;
import com.intellij.util.SmartList; import com.intellij.util.SmartList;
import com.intellij.util.containers.HashMap;
import kotlin.collections.ArraysKt; import kotlin.collections.ArraysKt;
import kotlin.collections.CollectionsKt; import kotlin.collections.CollectionsKt;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -106,7 +105,7 @@ public class K2JSCompiler extends CLICompiler<K2JSCompilerArguments> {
} }
@NotNull @NotNull
protected TranslationResult translate( private static TranslationResult translate(
@NotNull JsConfig.Reporter reporter, @NotNull JsConfig.Reporter reporter,
@NotNull List<KtFile> allKotlinFiles, @NotNull List<KtFile> allKotlinFiles,
@NotNull JsAnalysisResult jsAnalysisResult, @NotNull JsAnalysisResult jsAnalysisResult,
@@ -116,7 +115,7 @@ public class K2JSCompiler extends CLICompiler<K2JSCompilerArguments> {
K2JSTranslator translator = new K2JSTranslator(config); K2JSTranslator translator = new K2JSTranslator(config);
IncrementalDataProvider incrementalDataProvider = config.getConfiguration().get(JSConfigurationKeys.INCREMENTAL_DATA_PROVIDER); IncrementalDataProvider incrementalDataProvider = config.getConfiguration().get(JSConfigurationKeys.INCREMENTAL_DATA_PROVIDER);
if (incrementalDataProvider != null) { if (incrementalDataProvider != null) {
Map<File, KtFile> nonCompiledSources = new HashMap<File, KtFile>(allKotlinFiles.size()); Map<File, KtFile> nonCompiledSources = new HashMap<>(allKotlinFiles.size());
for (KtFile ktFile : allKotlinFiles) { for (KtFile ktFile : allKotlinFiles) {
nonCompiledSources.put(VfsUtilCore.virtualToIoFile(ktFile.getVirtualFile()), ktFile); nonCompiledSources.put(VfsUtilCore.virtualToIoFile(ktFile.getVirtualFile()), ktFile);
} }
@@ -169,7 +168,8 @@ public class K2JSCompiler extends CLICompiler<K2JSCompilerArguments> {
return COMPILATION_ERROR; return COMPILATION_ERROR;
} }
ExitCode pluginLoadResult = PluginCliParser.loadPluginsSafe(arguments.getPluginClasspaths(), arguments.getPluginOptions(), configuration); ExitCode pluginLoadResult =
PluginCliParser.loadPluginsSafe(arguments.getPluginClasspaths(), arguments.getPluginOptions(), configuration);
if (pluginLoadResult != ExitCode.OK) return pluginLoadResult; if (pluginLoadResult != ExitCode.OK) return pluginLoadResult;
configuration.put(JSConfigurationKeys.LIBRARIES, configureLibraries(arguments, paths, messageCollector)); configuration.put(JSConfigurationKeys.LIBRARIES, configureLibraries(arguments, paths, messageCollector));
@@ -20,11 +20,9 @@ import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
object BundledCompilerPlugins { object BundledCompilerPlugins {
val componentRegistrars: List<ComponentRegistrar> val componentRegistrars: List<ComponentRegistrar>
get() = emptyList() get() = emptyList()
val commandLineProcessors: List<CommandLineProcessor> val commandLineProcessors: List<CommandLineProcessor>
get() = emptyList() get() = emptyList()
} }
@@ -32,10 +32,10 @@ object JvmRuntimeVersionsConsistencyChecker {
private val LOG = Logger.getInstance(JvmRuntimeVersionsConsistencyChecker::class.java) private val LOG = Logger.getInstance(JvmRuntimeVersionsConsistencyChecker::class.java)
private fun <T> T?.assertNotNull(lazyMessage: () -> String): T = private fun <T> T?.assertNotNull(lazyMessage: () -> String): T =
this ?: lazyMessage().let { message -> this ?: lazyMessage().let { message ->
LOG.error(message) LOG.error(message)
throw AssertionError(message) throw AssertionError(message)
} }
private const val META_INF = "META-INF" private const val META_INF = "META-INF"
private const val MANIFEST_MF = "$META_INF/MANIFEST.MF" private const val MANIFEST_MF = "$META_INF/MANIFEST.MF"
@@ -51,7 +51,7 @@ object JvmRuntimeVersionsConsistencyChecker {
private const val KOTLIN_REFLECT_MODULE = "$META_INF/kotlin-reflection.kotlin_module" private const val KOTLIN_REFLECT_MODULE = "$META_INF/kotlin-reflection.kotlin_module"
private val RUNTIME_IMPLEMENTATION_TITLES = setOf( private val RUNTIME_IMPLEMENTATION_TITLES = setOf(
"kotlin-runtime", "kotlin-stdlib", "kotlin-reflect", "Kotlin Runtime", "Kotlin Standard Library", "Kotlin Reflect" "kotlin-runtime", "kotlin-stdlib", "kotlin-reflect", "Kotlin Runtime", "Kotlin Standard Library", "Kotlin Reflect"
) )
private val KOTLIN_VERSION_ATTRIBUTE: String private val KOTLIN_VERSION_ATTRIBUTE: String
@@ -62,44 +62,43 @@ object JvmRuntimeVersionsConsistencyChecker {
init { init {
val manifestProperties: Properties = try { val manifestProperties: Properties = try {
JvmRuntimeVersionsConsistencyChecker::class.java JvmRuntimeVersionsConsistencyChecker::class.java
.getResourceAsStream("/kotlinManifest.properties") .getResourceAsStream("/kotlinManifest.properties")
.let { input -> Properties().apply { load(input) } } .let { input -> Properties().apply { load(input) } }
} } catch (e: Exception) {
catch (e: Exception) {
LOG.error(e) LOG.error(e)
throw e throw e
} }
KOTLIN_VERSION_ATTRIBUTE = manifestProperties.getProperty(MANIFEST_KOTLIN_VERSION_ATTRIBUTE) KOTLIN_VERSION_ATTRIBUTE = manifestProperties.getProperty(MANIFEST_KOTLIN_VERSION_ATTRIBUTE)
.assertNotNull { "$MANIFEST_KOTLIN_VERSION_ATTRIBUTE not found in kotlinManifest.properties" } .assertNotNull { "$MANIFEST_KOTLIN_VERSION_ATTRIBUTE not found in kotlinManifest.properties" }
KOTLIN_RUNTIME_COMPONENT_ATTRIBUTE = manifestProperties.getProperty(MANIFEST_KOTLIN_RUNTIME_COMPONENT) KOTLIN_RUNTIME_COMPONENT_ATTRIBUTE = manifestProperties.getProperty(MANIFEST_KOTLIN_RUNTIME_COMPONENT)
.assertNotNull { "$MANIFEST_KOTLIN_RUNTIME_COMPONENT not found in kotlinManifest.properties" } .assertNotNull { "$MANIFEST_KOTLIN_RUNTIME_COMPONENT not found in kotlinManifest.properties" }
KOTLIN_RUNTIME_COMPONENT_CORE = manifestProperties.getProperty(MANIFEST_KOTLIN_RUNTIME_COMPONENT_CORE) KOTLIN_RUNTIME_COMPONENT_CORE = manifestProperties.getProperty(MANIFEST_KOTLIN_RUNTIME_COMPONENT_CORE)
.assertNotNull { "$MANIFEST_KOTLIN_RUNTIME_COMPONENT_CORE not found in kotlinManifest.properties" } .assertNotNull { "$MANIFEST_KOTLIN_RUNTIME_COMPONENT_CORE not found in kotlinManifest.properties" }
KOTLIN_RUNTIME_COMPONENT_MAIN = manifestProperties.getProperty(MANIFEST_KOTLIN_RUNTIME_COMPONENT_MAIN) KOTLIN_RUNTIME_COMPONENT_MAIN = manifestProperties.getProperty(MANIFEST_KOTLIN_RUNTIME_COMPONENT_MAIN)
.assertNotNull { "$MANIFEST_KOTLIN_RUNTIME_COMPONENT_MAIN not found in kotlinManifest.properties" } .assertNotNull { "$MANIFEST_KOTLIN_RUNTIME_COMPONENT_MAIN not found in kotlinManifest.properties" }
} }
private class KotlinLibraryFile(val file: VirtualFile, val version: MavenComparableVersion) { private class KotlinLibraryFile(val file: VirtualFile, val version: MavenComparableVersion) {
override fun toString(): String = override fun toString(): String =
"${file.name}:$version" "${file.name}:$version"
} }
private class RuntimeJarsInfo( private class RuntimeJarsInfo(
// Runtime jars with components "Main" and "Core" // Runtime jars with components "Main" and "Core"
val jars: List<KotlinLibraryFile>, val jars: List<KotlinLibraryFile>,
// Runtime jars with components "Core" only (a subset of [jars]) // Runtime jars with components "Core" only (a subset of [jars])
val coreJars: List<KotlinLibraryFile>, val coreJars: List<KotlinLibraryFile>,
// Library jars which have some Kotlin Runtime library bundled into them // Library jars which have some Kotlin Runtime library bundled into them
val otherLibrariesWithBundledRuntime: List<VirtualFile>, val otherLibrariesWithBundledRuntime: List<VirtualFile>,
val stdlibJre7: List<KotlinLibraryFile>, val stdlibJre7: List<KotlinLibraryFile>,
val stdlibJre8: List<KotlinLibraryFile> val stdlibJre8: List<KotlinLibraryFile>
) )
fun checkCompilerClasspathConsistency( fun checkCompilerClasspathConsistency(
messageCollector: MessageCollector, messageCollector: MessageCollector,
configuration: CompilerConfiguration, configuration: CompilerConfiguration,
classpathJarRoots: List<VirtualFile> classpathJarRoots: List<VirtualFile>
) { ) {
val runtimeJarsInfo = collectRuntimeJarsInfo(classpathJarRoots) val runtimeJarsInfo = collectRuntimeJarsInfo(classpathJarRoots)
if (runtimeJarsInfo.jars.isEmpty()) return if (runtimeJarsInfo.jars.isEmpty()) return
@@ -114,11 +113,11 @@ object JvmRuntimeVersionsConsistencyChecker {
messageCollector.issue( messageCollector.issue(
null, null,
"Runtime JAR files in the classpath have the version $actualRuntimeVersion, " + "Runtime JAR files in the classpath have the version $actualRuntimeVersion, " +
"which is older than the API version ${currentApi.version}. " + "which is older than the API version ${currentApi.version}. " +
"Consider using the runtime of version ${currentApi.version}, or pass '-api-version $actualRuntimeVersion' " + "Consider using the runtime of version ${currentApi.version}, or pass '-api-version $actualRuntimeVersion' " +
"explicitly to restrict the available APIs to the runtime of version $actualRuntimeVersion. " + "explicitly to restrict the available APIs to the runtime of version $actualRuntimeVersion. " +
"You can also pass '-language-version $actualRuntimeVersion' instead, which will restrict " + "You can also pass '-language-version $actualRuntimeVersion' instead, which will restrict " +
"not only the APIs to the specified version, but also the language features" "not only the APIs to the specified version, but also the language features"
) )
for (jar in consistency.incompatibleJars) { for (jar in consistency.incompatibleJars) {
@@ -141,17 +140,18 @@ object JvmRuntimeVersionsConsistencyChecker {
override val apiVersion: ApiVersion get() = actualApi override val apiVersion: ApiVersion get() = actualApi
} }
messageCollector.issue(null, "Old runtime has been found in the classpath. " + messageCollector.issue(
"Initial language version settings: $languageVersionSettings. " + null, "Old runtime has been found in the classpath. " +
"Updated language version settings: $newSettings", CompilerMessageSeverity.LOGGING) "Initial language version settings: $languageVersionSettings. " +
"Updated language version settings: $newSettings", CompilerMessageSeverity.LOGGING
)
configuration.languageVersionSettings = newSettings configuration.languageVersionSettings = newSettings
} }
} } else if (consistency != ClasspathConsistency.Consistent) {
else if (consistency != ClasspathConsistency.Consistent) {
messageCollector.issue( messageCollector.issue(
null, null,
"Some runtime JAR files in the classpath have an incompatible version. Consider removing them from the classpath" "Some runtime JAR files in the classpath have an incompatible version. Consider removing them from the classpath"
) )
} }
@@ -167,10 +167,10 @@ object JvmRuntimeVersionsConsistencyChecker {
val librariesWithBundled = runtimeJarsInfo.otherLibrariesWithBundledRuntime val librariesWithBundled = runtimeJarsInfo.otherLibrariesWithBundledRuntime
if (librariesWithBundled.isNotEmpty()) { if (librariesWithBundled.isNotEmpty()) {
messageCollector.issue( messageCollector.issue(
null, null,
"Some JAR files in the classpath have the Kotlin Runtime library bundled into them. " + "Some JAR files in the classpath have the Kotlin Runtime library bundled into them. " +
"This may cause difficult to debug problems if there's a different version of the Kotlin Runtime library in the classpath. " + "This may cause difficult to debug problems if there's a different version of the Kotlin Runtime library in the classpath. " +
"Consider removing these libraries from the classpath" "Consider removing these libraries from the classpath"
) )
for (library in librariesWithBundled) { for (library in librariesWithBundled) {
@@ -185,14 +185,15 @@ object JvmRuntimeVersionsConsistencyChecker {
val actualRuntimeVersion: MavenComparableVersion, val actualRuntimeVersion: MavenComparableVersion,
val incompatibleJars: List<KotlinLibraryFile> val incompatibleJars: List<KotlinLibraryFile>
) : ClasspathConsistency() ) : ClasspathConsistency()
object InconsistentWithCompilerVersion : ClasspathConsistency() object InconsistentWithCompilerVersion : ClasspathConsistency()
object InconsistentBecauseOfRuntimesWithDifferentVersions : ClasspathConsistency() object InconsistentBecauseOfRuntimesWithDifferentVersions : ClasspathConsistency()
} }
private fun checkCompilerClasspathConsistency( private fun checkCompilerClasspathConsistency(
messageCollector: MessageCollector, messageCollector: MessageCollector,
apiVersion: MavenComparableVersion, apiVersion: MavenComparableVersion,
runtimeJarsInfo: RuntimeJarsInfo runtimeJarsInfo: RuntimeJarsInfo
): ClasspathConsistency { ): ClasspathConsistency {
// The "Core" jar files should not be newer than the compiler. This behavior is reserved for the future if we realise that we're // The "Core" jar files should not be newer than the compiler. This behavior is reserved for the future if we realise that we're
// going to break language/library compatibility in such a way that it's easier to make the old compiler just report an error // going to break language/library compatibility in such a way that it's easier to make the old compiler just report an error
@@ -206,7 +207,7 @@ object JvmRuntimeVersionsConsistencyChecker {
if (jars.isEmpty()) return ClasspathConsistency.Consistent if (jars.isEmpty()) return ClasspathConsistency.Consistent
val runtimeVersion = checkMatchingVersionsAndGetRuntimeVersion(messageCollector, jars) val runtimeVersion = checkMatchingVersionsAndGetRuntimeVersion(messageCollector, jars)
?: return ClasspathConsistency.InconsistentBecauseOfRuntimesWithDifferentVersions ?: return ClasspathConsistency.InconsistentBecauseOfRuntimesWithDifferentVersions
val jarsIncompatibleWithApiVersion = jars.filter { it.version < apiVersion } val jarsIncompatibleWithApiVersion = jars.filter { it.version < apiVersion }
if (jarsIncompatibleWithApiVersion.isNotEmpty()) { if (jarsIncompatibleWithApiVersion.isNotEmpty()) {
@@ -219,9 +220,9 @@ object JvmRuntimeVersionsConsistencyChecker {
private fun checkNotNewerThanCompiler(messageCollector: MessageCollector, jar: KotlinLibraryFile): Boolean { private fun checkNotNewerThanCompiler(messageCollector: MessageCollector, jar: KotlinLibraryFile): Boolean {
if (jar.version > ApiVersion.LATEST_STABLE.version) { if (jar.version > ApiVersion.LATEST_STABLE.version) {
messageCollector.issue( messageCollector.issue(
jar.file, jar.file,
"Runtime JAR file has version ${jar.version} which is newer than compiler version ${ApiVersion.LATEST_STABLE.version}", "Runtime JAR file has version ${jar.version} which is newer than compiler version ${ApiVersion.LATEST_STABLE.version}",
CompilerMessageSeverity.ERROR CompilerMessageSeverity.ERROR
) )
return true return true
} }
@@ -230,8 +231,8 @@ object JvmRuntimeVersionsConsistencyChecker {
// Returns the version if it's the same across all jars, or null if versions of some jars differ. // Returns the version if it's the same across all jars, or null if versions of some jars differ.
private fun checkMatchingVersionsAndGetRuntimeVersion( private fun checkMatchingVersionsAndGetRuntimeVersion(
messageCollector: MessageCollector, messageCollector: MessageCollector,
jars: List<KotlinLibraryFile> jars: List<KotlinLibraryFile>
): MavenComparableVersion? { ): MavenComparableVersion? {
assert(jars.isNotEmpty()) { "'jars' must not be empty" } assert(jars.isNotEmpty()) { "'jars' must not be empty" }
val oldestVersion = jars.minBy { it.version }!!.version val oldestVersion = jars.minBy { it.version }!!.version
@@ -251,13 +252,13 @@ object JvmRuntimeVersionsConsistencyChecker {
// we suggest to provide an explicit dependency on version X. // we suggest to provide an explicit dependency on version X.
// TODO: report this depending on the content of the jars instead // TODO: report this depending on the content of the jars instead
val minReflectJar = val minReflectJar =
jars.filter { it.file.name.startsWith("kotlin-reflect") }.minBy { it.version } jars.filter { it.file.name.startsWith("kotlin-reflect") }.minBy { it.version }
val maxStdlibJar = val maxStdlibJar =
jars.filter { it.file.name.startsWith("kotlin-runtime") || it.file.name.startsWith("kotlin-stdlib") }.maxBy { it.version } jars.filter { it.file.name.startsWith("kotlin-runtime") || it.file.name.startsWith("kotlin-stdlib") }.maxBy { it.version }
if (minReflectJar != null && maxStdlibJar != null && minReflectJar.version < maxStdlibJar.version) { if (minReflectJar != null && maxStdlibJar != null && minReflectJar.version < maxStdlibJar.version) {
messageCollector.issue( messageCollector.issue(
null, null,
"Consider providing an explicit dependency on kotlin-reflect ${maxStdlibJar.version} to prevent strange errors" "Consider providing an explicit dependency on kotlin-reflect ${maxStdlibJar.version} to prevent strange errors"
) )
} }
@@ -265,9 +266,9 @@ object JvmRuntimeVersionsConsistencyChecker {
} }
private fun MessageCollector.issue( private fun MessageCollector.issue(
file: VirtualFile?, file: VirtualFile?,
message: String, message: String,
severity: CompilerMessageSeverity = CompilerMessageSeverity.STRONG_WARNING severity: CompilerMessageSeverity = CompilerMessageSeverity.STRONG_WARNING
) { ) {
report(severity, message, CompilerMessageLocation.create(file?.let(VfsUtilCore::virtualToIoFile)?.path)) report(severity, message, CompilerMessageLocation.create(file?.let(VfsUtilCore::virtualToIoFile)?.path))
} }
@@ -330,8 +331,7 @@ object JvmRuntimeVersionsConsistencyChecker {
val manifestFile = jarRoot.findFileByRelativePath(MANIFEST_MF) val manifestFile = jarRoot.findFileByRelativePath(MANIFEST_MF)
val manifest = try { val manifest = try {
manifestFile?.let { Manifest(it.inputStream) } manifestFile?.let { Manifest(it.inputStream) }
} } catch (e: IOException) {
catch (e: IOException) {
return FileKind.Irrelevant return FileKind.Irrelevant
} }
@@ -345,7 +345,7 @@ object JvmRuntimeVersionsConsistencyChecker {
FileKind.Runtime(manifest.getKotlinLanguageVersion(), isStdlibJre7, isStdlibJre8, isCoreComponent = true) FileKind.Runtime(manifest.getKotlinLanguageVersion(), isStdlibJre7, isStdlibJre8, isCoreComponent = true)
null -> when { null -> when {
jarRoot.findFileByRelativePath(KOTLIN_STDLIB_MODULE) == null && jarRoot.findFileByRelativePath(KOTLIN_STDLIB_MODULE) == null &&
jarRoot.findFileByRelativePath(KOTLIN_REFLECT_MODULE) == null -> FileKind.Irrelevant jarRoot.findFileByRelativePath(KOTLIN_REFLECT_MODULE) == null -> FileKind.Irrelevant
isGenuineKotlinRuntime(manifest) -> FileKind.OldRuntime isGenuineKotlinRuntime(manifest) -> FileKind.OldRuntime
else -> FileKind.LibraryWithBundledRuntime else -> FileKind.LibraryWithBundledRuntime
} }
@@ -356,9 +356,9 @@ object JvmRuntimeVersionsConsistencyChecker {
// Returns true if the manifest is from the original Kotlin Runtime jar, false if it's from a library with a bundled runtime // Returns true if the manifest is from the original Kotlin Runtime jar, false if it's from a library with a bundled runtime
private fun isGenuineKotlinRuntime(manifest: Manifest?): Boolean { private fun isGenuineKotlinRuntime(manifest: Manifest?): Boolean {
return manifest != null && return manifest != null &&
manifest.mainAttributes.getValue(Attributes.Name.IMPLEMENTATION_TITLE) in RUNTIME_IMPLEMENTATION_TITLES manifest.mainAttributes.getValue(Attributes.Name.IMPLEMENTATION_TITLE) in RUNTIME_IMPLEMENTATION_TITLES
} }
private fun Manifest.getKotlinLanguageVersion(): MavenComparableVersion = private fun Manifest.getKotlinLanguageVersion(): MavenComparableVersion =
(mainAttributes.getValue(KOTLIN_VERSION_ATTRIBUTE)?.let((ApiVersion)::parse) ?: ApiVersion.KOTLIN_1_0).version (mainAttributes.getValue(KOTLIN_VERSION_ATTRIBUTE)?.let((ApiVersion)::parse) ?: ApiVersion.KOTLIN_1_0).version
} }
@@ -150,7 +150,7 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
KotlinToJVMBytecodeCompiler.configureSourceRoots(configuration, moduleChunk.modules, buildFile) KotlinToJVMBytecodeCompiler.configureSourceRoots(configuration, moduleChunk.modules, buildFile)
val environment = createCoreEnvironment(rootDisposable, configuration, messageCollector) val environment = createCoreEnvironment(rootDisposable, configuration, messageCollector)
?: return COMPILATION_ERROR ?: return COMPILATION_ERROR
registerJavacIfNeeded(environment, arguments).let { registerJavacIfNeeded(environment, arguments).let {
if (!it) return COMPILATION_ERROR if (!it) return COMPILATION_ERROR
@@ -164,7 +164,7 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true) configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true)
val environment = createCoreEnvironment(rootDisposable, configuration, messageCollector) val environment = createCoreEnvironment(rootDisposable, configuration, messageCollector)
?: return COMPILATION_ERROR ?: return COMPILATION_ERROR
val scriptDefinitionProvider = ScriptDefinitionProvider.getInstance(environment.project) val scriptDefinitionProvider = ScriptDefinitionProvider.getInstance(environment.project)
val scriptFile = File(sourcePath) val scriptFile = File(sourcePath)
@@ -188,7 +188,7 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
} }
val environment = createCoreEnvironment(rootDisposable, configuration, messageCollector) val environment = createCoreEnvironment(rootDisposable, configuration, messageCollector)
?: return COMPILATION_ERROR ?: return COMPILATION_ERROR
registerJavacIfNeeded(environment, arguments).let { registerJavacIfNeeded(environment, arguments).let {
if (!it) return COMPILATION_ERROR if (!it) return COMPILATION_ERROR
@@ -243,7 +243,7 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
val jars = arrayOf( val jars = arrayOf(
KOTLIN_SCRIPTING_COMPILER_PLUGIN_JAR, KOTLIN_SCRIPTING_COMMON_JAR, KOTLIN_SCRIPTING_COMPILER_PLUGIN_JAR, KOTLIN_SCRIPTING_COMMON_JAR,
KOTLIN_SCRIPTING_JVM_JAR, KOTLIN_SCRIPTING_MISC_JAR KOTLIN_SCRIPTING_JVM_JAR, KOTLIN_SCRIPTING_MISC_JAR
).mapNotNull { File(libPath, it).takeIf { it.exists() }?.canonicalPath } ).mapNotNull { File(libPath, it).takeIf(File::exists)?.canonicalPath }
if (jars.size == 4) { if (jars.size == 4) {
pluginClasspaths = jars + pluginClasspaths pluginClasspaths = jars + pluginClasspaths
} }
@@ -308,19 +308,19 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
configuration: CompilerConfiguration, arguments: K2JVMCompilerArguments, services: Services configuration: CompilerConfiguration, arguments: K2JVMCompilerArguments, services: Services
) { ) {
if (IncrementalCompilation.isEnabledForJvm()) { if (IncrementalCompilation.isEnabledForJvm()) {
services.get(LookupTracker::class.java)?.let { services[LookupTracker::class.java]?.let {
configuration.put(CommonConfigurationKeys.LOOKUP_TRACKER, it) configuration.put(CommonConfigurationKeys.LOOKUP_TRACKER, it)
} }
services.get(ExpectActualTracker::class.java)?.let { services[ExpectActualTracker::class.java]?.let {
configuration.put(CommonConfigurationKeys.EXPECT_ACTUAL_TRACKER, it) configuration.put(CommonConfigurationKeys.EXPECT_ACTUAL_TRACKER, it)
} }
services.get(IncrementalCompilationComponents::class.java)?.let { services[IncrementalCompilationComponents::class.java]?.let {
configuration.put(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS, it) configuration.put(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS, it)
} }
services.get(JavaClassesTracker::class.java)?.let { services[JavaClassesTracker::class.java]?.let {
configuration.put(JVMConfigurationKeys.JAVA_CLASSES_TRACKER, it) configuration.put(JVMConfigurationKeys.JAVA_CLASSES_TRACKER, it)
} }
} }
@@ -46,13 +46,13 @@ import java.util.jar.Manifest
import kotlin.LazyThreadSafetyMode.NONE import kotlin.LazyThreadSafetyMode.NONE
class ClasspathRootsResolver( class ClasspathRootsResolver(
private val psiManager: PsiManager, private val psiManager: PsiManager,
private val messageCollector: MessageCollector?, private val messageCollector: MessageCollector?,
private val additionalModules: List<String>, private val additionalModules: List<String>,
private val contentRootToVirtualFile: (JvmContentRoot) -> VirtualFile?, private val contentRootToVirtualFile: (JvmContentRoot) -> VirtualFile?,
private val javaModuleFinder: CliJavaModuleFinder, private val javaModuleFinder: CliJavaModuleFinder,
private val requireStdlibModule: Boolean, private val requireStdlibModule: Boolean,
private val outputDirectory: VirtualFile? private val outputDirectory: VirtualFile?
) { ) {
val javaModuleGraph = JavaModuleGraph(javaModuleFinder) val javaModuleGraph = JavaModuleGraph(javaModuleFinder)
@@ -80,9 +80,9 @@ class ClasspathRootsResolver(
} }
private fun computeRoots( private fun computeRoots(
javaSourceRoots: List<RootWithPrefix>, javaSourceRoots: List<RootWithPrefix>,
jvmClasspathRoots: List<VirtualFile>, jvmClasspathRoots: List<VirtualFile>,
jvmModulePathRoots: List<VirtualFile> jvmModulePathRoots: List<VirtualFile>
): RootsAndModules { ): RootsAndModules {
val result = mutableListOf<JavaRoot>() val result = mutableListOf<JavaRoot>()
val modules = mutableListOf<JavaModule>() val modules = mutableListOf<JavaModule>()
@@ -93,8 +93,7 @@ class ClasspathRootsResolver(
val modularRoot = modularSourceRoot(root, hasOutputDirectoryInClasspath) val modularRoot = modularSourceRoot(root, hasOutputDirectoryInClasspath)
if (modularRoot != null) { if (modularRoot != null) {
modules += modularRoot modules += modularRoot
} } else {
else {
result += JavaRoot(root, JavaRoot.RootType.SOURCE, packagePrefix?.let { prefix -> result += JavaRoot(root, JavaRoot.RootType.SOURCE, packagePrefix?.let { prefix ->
if (isValidJavaFqName(prefix)) FqName(prefix) if (isValidJavaFqName(prefix)) FqName(prefix)
else null.also { else null.also {
@@ -128,11 +127,11 @@ class ClasspathRootsResolver(
private fun findSourceModuleInfo(root: VirtualFile): Pair<VirtualFile, PsiJavaModule>? { private fun findSourceModuleInfo(root: VirtualFile): Pair<VirtualFile, PsiJavaModule>? {
val moduleInfoFile = val moduleInfoFile =
when { when {
root.isDirectory -> root.findChild(PsiJavaModule.MODULE_INFO_FILE) root.isDirectory -> root.findChild(PsiJavaModule.MODULE_INFO_FILE)
root.name == PsiJavaModule.MODULE_INFO_FILE -> root root.name == PsiJavaModule.MODULE_INFO_FILE -> root
else -> null else -> null
} ?: return null } ?: return null
val psiFile = psiManager.findFile(moduleInfoFile) ?: return null val psiFile = psiManager.findFile(moduleInfoFile) ?: return null
val psiJavaModule = psiFile.children.singleOrNull { it is PsiJavaModule } as? PsiJavaModule ?: return null val psiJavaModule = psiFile.children.singleOrNull { it is PsiJavaModule } as? PsiJavaModule ?: return null
@@ -144,9 +143,9 @@ class ClasspathRootsResolver(
val (moduleInfoFile, psiJavaModule) = findSourceModuleInfo(root) ?: return null val (moduleInfoFile, psiJavaModule) = findSourceModuleInfo(root) ?: return null
val sourceRoot = JavaModule.Root(root, isBinary = false) val sourceRoot = JavaModule.Root(root, isBinary = false)
val roots = val roots =
if (hasOutputDirectoryInClasspath) if (hasOutputDirectoryInClasspath)
listOf(sourceRoot, JavaModule.Root(outputDirectory!!, isBinary = true)) listOf(sourceRoot, JavaModule.Root(outputDirectory!!, isBinary = true))
else listOf(sourceRoot) else listOf(sourceRoot)
return JavaModule.Explicit(JavaModuleInfo.create(psiJavaModule), roots, moduleInfoFile) return JavaModule.Explicit(JavaModuleInfo.create(psiJavaModule), roots, moduleInfoFile)
} }
@@ -155,7 +154,7 @@ class ClasspathRootsResolver(
val manifest: Attributes? by lazy(NONE) { readManifestAttributes(root) } val manifest: Attributes? by lazy(NONE) { readManifestAttributes(root) }
val moduleInfoFile = val moduleInfoFile =
root.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE) root.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE)
?: root.takeIf { isJar }?.findFileByRelativePath(MULTI_RELEASE_MODULE_INFO_CLS_FILE)?.takeIf { ?: root.takeIf { isJar }?.findFileByRelativePath(MULTI_RELEASE_MODULE_INFO_CLS_FILE)?.takeIf {
manifest?.getValue(IS_MULTI_RELEASE)?.equals("true", ignoreCase = true) == true manifest?.getValue(IS_MULTI_RELEASE)?.equals("true", ignoreCase = true) == true
} }
@@ -190,8 +189,7 @@ class ClasspathRootsResolver(
val manifestFile = jarRoot.findChild("META-INF")?.findChild("MANIFEST.MF") val manifestFile = jarRoot.findChild("META-INF")?.findChild("MANIFEST.MF")
return try { return try {
manifestFile?.inputStream?.let(::Manifest)?.mainAttributes manifestFile?.inputStream?.let(::Manifest)?.mainAttributes
} } catch (e: IOException) {
catch (e: IOException) {
null null
} }
} }
@@ -211,16 +209,17 @@ class ClasspathRootsResolver(
val existing = javaModuleFinder.findModule(module.name) val existing = javaModuleFinder.findModule(module.name)
if (existing == null) { if (existing == null) {
javaModuleFinder.addUserModule(module) javaModuleFinder.addUserModule(module)
} } else if (module.moduleRoots != existing.moduleRoots) {
else if (module.moduleRoots != existing.moduleRoots) {
fun JavaModule.getRootFile() = fun JavaModule.getRootFile() =
moduleRoots.firstOrNull()?.file?.let { VfsUtilCore.getVirtualFileForJar(it) ?: it } moduleRoots.firstOrNull()?.file?.let { VfsUtilCore.getVirtualFileForJar(it) ?: it }
val thisFile = module.getRootFile() val thisFile = module.getRootFile()
val existingFile = existing.getRootFile() val existingFile = existing.getRootFile()
val atExistingPath = if (existingFile == null) "" else " at: ${existingFile.path}" val atExistingPath = if (existingFile == null) "" else " at: ${existingFile.path}"
report(STRONG_WARNING, "The root is ignored because a module with the same name '${module.name}' " + report(
"has been found earlier on the module path$atExistingPath", thisFile) STRONG_WARNING, "The root is ignored because a module with the same name '${module.name}' " +
"has been found earlier on the module path$atExistingPath", thisFile
)
} }
} }
@@ -257,8 +256,7 @@ class ClasspathRootsResolver(
val module = javaModuleFinder.findModule(moduleName) val module = javaModuleFinder.findModule(moduleName)
if (module == null) { if (module == null) {
report(ERROR, "Module $moduleName cannot be found in the module graph") report(ERROR, "Module $moduleName cannot be found in the module graph")
} } else {
else {
for ((root, isBinary) in module.moduleRoots) { for ((root, isBinary) in module.moduleRoots) {
result.add(JavaRoot(root, if (isBinary) JavaRoot.RootType.BINARY else JavaRoot.RootType.SOURCE)) result.add(JavaRoot(root, if (isBinary) JavaRoot.RootType.BINARY else JavaRoot.RootType.SOURCE))
} }
@@ -267,10 +265,10 @@ class ClasspathRootsResolver(
if (requireStdlibModule && sourceModule != null && !javaModuleGraph.reads(sourceModule.name, KOTLIN_STDLIB_MODULE_NAME)) { if (requireStdlibModule && sourceModule != null && !javaModuleGraph.reads(sourceModule.name, KOTLIN_STDLIB_MODULE_NAME)) {
report( report(
ERROR, ERROR,
"The Kotlin standard library is not found in the module graph. " + "The Kotlin standard library is not found in the module graph. " +
"Please ensure you have the 'requires $KOTLIN_STDLIB_MODULE_NAME' clause in your module definition", "Please ensure you have the 'requires $KOTLIN_STDLIB_MODULE_NAME' clause in your module definition",
sourceModule.moduleInfoFile sourceModule.moduleInfoFile
) )
} }
} }
@@ -314,8 +312,8 @@ class ClasspathRootsResolver(
throw IllegalStateException("${if (file != null) file.path + ":" else ""}$severity: $message (no MessageCollector configured)") throw IllegalStateException("${if (file != null) file.path + ":" else ""}$severity: $message (no MessageCollector configured)")
} }
messageCollector.report( messageCollector.report(
severity, message, severity, message,
if (file == null) null else CompilerMessageLocation.create(MessageUtil.virtualFileToPath(file)) if (file == null) null else CompilerMessageLocation.create(MessageUtil.virtualFileToPath(file))
) )
} }
@@ -20,7 +20,6 @@ import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.openapi.vfs.VfsUtilCore import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiJavaModule import com.intellij.psi.PsiJavaModule
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.psi.PsiManager import com.intellij.psi.PsiManager
import com.intellij.psi.impl.light.LightJavaModule import com.intellij.psi.impl.light.LightJavaModule
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
@@ -47,13 +46,13 @@ import java.util.jar.Manifest
import kotlin.LazyThreadSafetyMode.NONE import kotlin.LazyThreadSafetyMode.NONE
class ClasspathRootsResolver( class ClasspathRootsResolver(
private val psiManager: PsiManager, private val psiManager: PsiManager,
private val messageCollector: MessageCollector?, private val messageCollector: MessageCollector?,
private val additionalModules: List<String>, private val additionalModules: List<String>,
private val contentRootToVirtualFile: (JvmContentRoot) -> VirtualFile?, private val contentRootToVirtualFile: (JvmContentRoot) -> VirtualFile?,
private val javaModuleFinder: CliJavaModuleFinder, private val javaModuleFinder: CliJavaModuleFinder,
private val requireStdlibModule: Boolean, private val requireStdlibModule: Boolean,
private val outputDirectory: VirtualFile? private val outputDirectory: VirtualFile?
) { ) {
val javaModuleGraph = JavaModuleGraph(javaModuleFinder) val javaModuleGraph = JavaModuleGraph(javaModuleFinder)
@@ -81,9 +80,9 @@ class ClasspathRootsResolver(
} }
private fun computeRoots( private fun computeRoots(
javaSourceRoots: List<RootWithPrefix>, javaSourceRoots: List<RootWithPrefix>,
jvmClasspathRoots: List<VirtualFile>, jvmClasspathRoots: List<VirtualFile>,
jvmModulePathRoots: List<VirtualFile> jvmModulePathRoots: List<VirtualFile>
): RootsAndModules { ): RootsAndModules {
val result = mutableListOf<JavaRoot>() val result = mutableListOf<JavaRoot>()
val modules = mutableListOf<JavaModule>() val modules = mutableListOf<JavaModule>()
@@ -92,22 +91,21 @@ class ClasspathRootsResolver(
for ((root, packagePrefix) in javaSourceRoots) { for ((root, packagePrefix) in javaSourceRoots) {
val modularRoot = modularSourceRoot(root, hasOutputDirectoryInClasspath) val modularRoot = modularSourceRoot(root, hasOutputDirectoryInClasspath)
if (modularRoot != null) { if (modularRoot != null) {
modules += modularRoot modules += modularRoot
} } else {
else {
result += JavaRoot(root, JavaRoot.RootType.SOURCE, packagePrefix?.let { prefix -> result += JavaRoot(root, JavaRoot.RootType.SOURCE, packagePrefix?.let { prefix ->
if (isValidJavaFqName(prefix)) FqName(prefix) if (isValidJavaFqName(prefix)) FqName(prefix)
else null.also { else null.also {
report(STRONG_WARNING, "Invalid package prefix name is ignored: $prefix") report(STRONG_WARNING, "Invalid package prefix name is ignored: $prefix")
}
})
} }
} })
}
}
for (root in jvmClasspathRoots) { for (root in jvmClasspathRoots) {
result += JavaRoot(root, JavaRoot.RootType.BINARY) result += JavaRoot(root, JavaRoot.RootType.BINARY)
} }
val outputDirectoryAddedAsPartOfModule = modules.any { module -> module.moduleRoots.any { it.file == outputDirectory } } val outputDirectoryAddedAsPartOfModule = modules.any { module -> module.moduleRoots.any { it.file == outputDirectory } }
@@ -117,24 +115,24 @@ class ClasspathRootsResolver(
if (outputDirectoryAddedAsPartOfModule && root == outputDirectory) continue if (outputDirectoryAddedAsPartOfModule && root == outputDirectory) continue
val module = modularBinaryRoot(root) val module = modularBinaryRoot(root)
if (module != null) { if (module != null) {
modules += module modules += module
} }
} }
addModularRoots(modules, result) addModularRoots(modules, result)
return RootsAndModules(result, modules) return RootsAndModules(result, modules)
} }
/* /*
private fun findSourceModuleInfo(root: VirtualFile): Pair<VirtualFile, PsiJavaModule>? { private fun findSourceModuleInfo(root: VirtualFile): Pair<VirtualFile, PsiJavaModule>? {
val moduleInfoFile = val moduleInfoFile =
when { when {
root.isDirectory -> root.findChild(PsiJavaModule.MODULE_INFO_FILE) root.isDirectory -> root.findChild(PsiJavaModule.MODULE_INFO_FILE)
root.name == PsiJavaModule.MODULE_INFO_FILE -> root root.name == PsiJavaModule.MODULE_INFO_FILE -> root
else -> null else -> null
} ?: return null } ?: return null
val psiFile = psiManager.findFile(moduleInfoFile) ?: return null val psiFile = psiManager.findFile(moduleInfoFile) ?: return null
val psiJavaModule = psiFile.children.singleOrNull { it is PsiJavaModule } as? PsiJavaModule ?: return null val psiJavaModule = psiFile.children.singleOrNull { it is PsiJavaModule } as? PsiJavaModule ?: return null
@@ -148,9 +146,9 @@ class ClasspathRootsResolver(
val (moduleInfoFile, psiJavaModule) = findSourceModuleInfo(root) ?: return null val (moduleInfoFile, psiJavaModule) = findSourceModuleInfo(root) ?: return null
val sourceRoot = JavaModule.Root(root, isBinary = false) val sourceRoot = JavaModule.Root(root, isBinary = false)
val roots = val roots =
if (hasOutputDirectoryInClasspath) if (hasOutputDirectoryInClasspath)
listOf(sourceRoot, JavaModule.Root(outputDirectory!!, isBinary = true)) listOf(sourceRoot, JavaModule.Root(outputDirectory!!, isBinary = true))
else listOf(sourceRoot) else listOf(sourceRoot)
return JavaModule.Explicit(JavaModuleInfo.create(psiJavaModule), roots, moduleInfoFile) return JavaModule.Explicit(JavaModuleInfo.create(psiJavaModule), roots, moduleInfoFile)
*/ */
return null return null
@@ -162,7 +160,7 @@ class ClasspathRootsResolver(
/* /*
val moduleInfoFile = val moduleInfoFile =
root.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE) root.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE)
?: root.takeIf { isJar }?.findFileByRelativePath(MULTI_RELEASE_MODULE_INFO_CLS_FILE)?.takeIf { ?: root.takeIf { isJar }?.findFileByRelativePath(MULTI_RELEASE_MODULE_INFO_CLS_FILE)?.takeIf {
manifest?.getValue(IS_MULTI_RELEASE)?.equals("true", ignoreCase = true) == true manifest?.getValue(IS_MULTI_RELEASE)?.equals("true", ignoreCase = true) == true
} }
@@ -198,8 +196,7 @@ class ClasspathRootsResolver(
val manifestFile = jarRoot.findChild("META-INF")?.findChild("MANIFEST.MF") val manifestFile = jarRoot.findChild("META-INF")?.findChild("MANIFEST.MF")
return try { return try {
manifestFile?.inputStream?.let(::Manifest)?.mainAttributes manifestFile?.inputStream?.let(::Manifest)?.mainAttributes
} } catch (e: IOException) {
catch (e: IOException) {
null null
} }
} }
@@ -219,16 +216,17 @@ class ClasspathRootsResolver(
val existing = javaModuleFinder.findModule(module.name) val existing = javaModuleFinder.findModule(module.name)
if (existing == null) { if (existing == null) {
javaModuleFinder.addUserModule(module) javaModuleFinder.addUserModule(module)
} } else if (module.moduleRoots != existing.moduleRoots) {
else if (module.moduleRoots != existing.moduleRoots) {
fun JavaModule.getRootFile() = fun JavaModule.getRootFile() =
moduleRoots.firstOrNull()?.file?.let { VfsUtilCore.getVirtualFileForJar(it) ?: it } moduleRoots.firstOrNull()?.file?.let { VfsUtilCore.getVirtualFileForJar(it) ?: it }
val thisFile = module.getRootFile() val thisFile = module.getRootFile()
val existingFile = existing.getRootFile() val existingFile = existing.getRootFile()
val atExistingPath = if (existingFile == null) "" else " at: ${existingFile.path}" val atExistingPath = if (existingFile == null) "" else " at: ${existingFile.path}"
report(STRONG_WARNING, "The root is ignored because a module with the same name '${module.name}' " + report(
"has been found earlier on the module path$atExistingPath", thisFile) STRONG_WARNING, "The root is ignored because a module with the same name '${module.name}' " +
"has been found earlier on the module path$atExistingPath", thisFile
)
} }
} }
@@ -265,8 +263,7 @@ class ClasspathRootsResolver(
val module = javaModuleFinder.findModule(moduleName) val module = javaModuleFinder.findModule(moduleName)
if (module == null) { if (module == null) {
report(ERROR, "Module $moduleName cannot be found in the module graph") report(ERROR, "Module $moduleName cannot be found in the module graph")
} } else {
else {
for ((root, isBinary) in module.moduleRoots) { for ((root, isBinary) in module.moduleRoots) {
result.add(JavaRoot(root, if (isBinary) JavaRoot.RootType.BINARY else JavaRoot.RootType.SOURCE)) result.add(JavaRoot(root, if (isBinary) JavaRoot.RootType.BINARY else JavaRoot.RootType.SOURCE))
} }
@@ -275,10 +272,10 @@ class ClasspathRootsResolver(
if (requireStdlibModule && sourceModule != null && !javaModuleGraph.reads(sourceModule.name, KOTLIN_STDLIB_MODULE_NAME)) { if (requireStdlibModule && sourceModule != null && !javaModuleGraph.reads(sourceModule.name, KOTLIN_STDLIB_MODULE_NAME)) {
report( report(
ERROR, ERROR,
"The Kotlin standard library is not found in the module graph. " + "The Kotlin standard library is not found in the module graph. " +
"Please ensure you have the 'requires $KOTLIN_STDLIB_MODULE_NAME' clause in your module definition", "Please ensure you have the 'requires $KOTLIN_STDLIB_MODULE_NAME' clause in your module definition",
sourceModule.moduleInfoFile sourceModule.moduleInfoFile
) )
} }
} }
@@ -322,8 +319,8 @@ class ClasspathRootsResolver(
throw IllegalStateException("${if (file != null) file.path + ":" else ""}$severity: $message (no MessageCollector configured)") throw IllegalStateException("${if (file != null) file.path + ":" else ""}$severity: $message (no MessageCollector configured)")
} }
messageCollector.report( messageCollector.report(
severity, message, severity, message,
if (file == null) null else CompilerMessageLocation.create(MessageUtil.virtualFileToPath(file)) if (file == null) null else CompilerMessageLocation.create(MessageUtil.virtualFileToPath(file))
) )
} }
@@ -20,7 +20,6 @@ import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.openapi.vfs.VfsUtilCore import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiJavaModule import com.intellij.psi.PsiJavaModule
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.psi.PsiManager import com.intellij.psi.PsiManager
import com.intellij.psi.impl.light.LightJavaModule import com.intellij.psi.impl.light.LightJavaModule
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
@@ -47,13 +46,13 @@ import java.util.jar.Manifest
import kotlin.LazyThreadSafetyMode.NONE import kotlin.LazyThreadSafetyMode.NONE
class ClasspathRootsResolver( class ClasspathRootsResolver(
private val psiManager: PsiManager, private val psiManager: PsiManager,
private val messageCollector: MessageCollector?, private val messageCollector: MessageCollector?,
private val additionalModules: List<String>, private val additionalModules: List<String>,
private val contentRootToVirtualFile: (JvmContentRoot) -> VirtualFile?, private val contentRootToVirtualFile: (JvmContentRoot) -> VirtualFile?,
private val javaModuleFinder: CliJavaModuleFinder, private val javaModuleFinder: CliJavaModuleFinder,
private val requireStdlibModule: Boolean, private val requireStdlibModule: Boolean,
private val outputDirectory: VirtualFile? private val outputDirectory: VirtualFile?
) { ) {
val javaModuleGraph = JavaModuleGraph(javaModuleFinder) val javaModuleGraph = JavaModuleGraph(javaModuleFinder)
@@ -81,9 +80,9 @@ class ClasspathRootsResolver(
} }
private fun computeRoots( private fun computeRoots(
javaSourceRoots: List<RootWithPrefix>, javaSourceRoots: List<RootWithPrefix>,
jvmClasspathRoots: List<VirtualFile>, jvmClasspathRoots: List<VirtualFile>,
jvmModulePathRoots: List<VirtualFile> jvmModulePathRoots: List<VirtualFile>
): RootsAndModules { ): RootsAndModules {
val result = mutableListOf<JavaRoot>() val result = mutableListOf<JavaRoot>()
val modules = mutableListOf<JavaModule>() val modules = mutableListOf<JavaModule>()
@@ -92,22 +91,21 @@ class ClasspathRootsResolver(
for ((root, packagePrefix) in javaSourceRoots) { for ((root, packagePrefix) in javaSourceRoots) {
val modularRoot = modularSourceRoot(root, hasOutputDirectoryInClasspath) val modularRoot = modularSourceRoot(root, hasOutputDirectoryInClasspath)
if (modularRoot != null) { if (modularRoot != null) {
modules += modularRoot modules += modularRoot
} } else {
else {
result += JavaRoot(root, JavaRoot.RootType.SOURCE, packagePrefix?.let { prefix -> result += JavaRoot(root, JavaRoot.RootType.SOURCE, packagePrefix?.let { prefix ->
if (isValidJavaFqName(prefix)) FqName(prefix) if (isValidJavaFqName(prefix)) FqName(prefix)
else null.also { else null.also {
report(STRONG_WARNING, "Invalid package prefix name is ignored: $prefix") report(STRONG_WARNING, "Invalid package prefix name is ignored: $prefix")
}
})
} }
} })
}
}
for (root in jvmClasspathRoots) { for (root in jvmClasspathRoots) {
result += JavaRoot(root, JavaRoot.RootType.BINARY) result += JavaRoot(root, JavaRoot.RootType.BINARY)
} }
val outputDirectoryAddedAsPartOfModule = modules.any { module -> module.moduleRoots.any { it.file == outputDirectory } } val outputDirectoryAddedAsPartOfModule = modules.any { module -> module.moduleRoots.any { it.file == outputDirectory } }
@@ -117,24 +115,24 @@ class ClasspathRootsResolver(
if (outputDirectoryAddedAsPartOfModule && root == outputDirectory) continue if (outputDirectoryAddedAsPartOfModule && root == outputDirectory) continue
val module = modularBinaryRoot(root) val module = modularBinaryRoot(root)
if (module != null) { if (module != null) {
modules += module modules += module
} }
} }
addModularRoots(modules, result) addModularRoots(modules, result)
return RootsAndModules(result, modules) return RootsAndModules(result, modules)
} }
/* /*
private fun findSourceModuleInfo(root: VirtualFile): Pair<VirtualFile, PsiJavaModule>? { private fun findSourceModuleInfo(root: VirtualFile): Pair<VirtualFile, PsiJavaModule>? {
val moduleInfoFile = val moduleInfoFile =
when { when {
root.isDirectory -> root.findChild(PsiJavaModule.MODULE_INFO_FILE) root.isDirectory -> root.findChild(PsiJavaModule.MODULE_INFO_FILE)
root.name == PsiJavaModule.MODULE_INFO_FILE -> root root.name == PsiJavaModule.MODULE_INFO_FILE -> root
else -> null else -> null
} ?: return null } ?: return null
val psiFile = psiManager.findFile(moduleInfoFile) ?: return null val psiFile = psiManager.findFile(moduleInfoFile) ?: return null
val psiJavaModule = psiFile.children.singleOrNull { it is PsiJavaModule } as? PsiJavaModule ?: return null val psiJavaModule = psiFile.children.singleOrNull { it is PsiJavaModule } as? PsiJavaModule ?: return null
@@ -148,9 +146,9 @@ class ClasspathRootsResolver(
val (moduleInfoFile, psiJavaModule) = findSourceModuleInfo(root) ?: return null val (moduleInfoFile, psiJavaModule) = findSourceModuleInfo(root) ?: return null
val sourceRoot = JavaModule.Root(root, isBinary = false) val sourceRoot = JavaModule.Root(root, isBinary = false)
val roots = val roots =
if (hasOutputDirectoryInClasspath) if (hasOutputDirectoryInClasspath)
listOf(sourceRoot, JavaModule.Root(outputDirectory!!, isBinary = true)) listOf(sourceRoot, JavaModule.Root(outputDirectory!!, isBinary = true))
else listOf(sourceRoot) else listOf(sourceRoot)
return JavaModule.Explicit(JavaModuleInfo.create(psiJavaModule), roots, moduleInfoFile) return JavaModule.Explicit(JavaModuleInfo.create(psiJavaModule), roots, moduleInfoFile)
*/ */
return null return null
@@ -162,7 +160,7 @@ class ClasspathRootsResolver(
/* /*
val moduleInfoFile = val moduleInfoFile =
root.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE) root.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE)
?: root.takeIf { isJar }?.findFileByRelativePath(MULTI_RELEASE_MODULE_INFO_CLS_FILE)?.takeIf { ?: root.takeIf { isJar }?.findFileByRelativePath(MULTI_RELEASE_MODULE_INFO_CLS_FILE)?.takeIf {
manifest?.getValue(IS_MULTI_RELEASE)?.equals("true", ignoreCase = true) == true manifest?.getValue(IS_MULTI_RELEASE)?.equals("true", ignoreCase = true) == true
} }
@@ -198,8 +196,7 @@ class ClasspathRootsResolver(
val manifestFile = jarRoot.findChild("META-INF")?.findChild("MANIFEST.MF") val manifestFile = jarRoot.findChild("META-INF")?.findChild("MANIFEST.MF")
return try { return try {
manifestFile?.inputStream?.let(::Manifest)?.mainAttributes manifestFile?.inputStream?.let(::Manifest)?.mainAttributes
} } catch (e: IOException) {
catch (e: IOException) {
null null
} }
} }
@@ -219,16 +216,17 @@ class ClasspathRootsResolver(
val existing = javaModuleFinder.findModule(module.name) val existing = javaModuleFinder.findModule(module.name)
if (existing == null) { if (existing == null) {
javaModuleFinder.addUserModule(module) javaModuleFinder.addUserModule(module)
} } else if (module.moduleRoots != existing.moduleRoots) {
else if (module.moduleRoots != existing.moduleRoots) {
fun JavaModule.getRootFile() = fun JavaModule.getRootFile() =
moduleRoots.firstOrNull()?.file?.let { VfsUtilCore.getVirtualFileForJar(it) ?: it } moduleRoots.firstOrNull()?.file?.let { VfsUtilCore.getVirtualFileForJar(it) ?: it }
val thisFile = module.getRootFile() val thisFile = module.getRootFile()
val existingFile = existing.getRootFile() val existingFile = existing.getRootFile()
val atExistingPath = if (existingFile == null) "" else " at: ${existingFile.path}" val atExistingPath = if (existingFile == null) "" else " at: ${existingFile.path}"
report(STRONG_WARNING, "The root is ignored because a module with the same name '${module.name}' " + report(
"has been found earlier on the module path$atExistingPath", thisFile) STRONG_WARNING, "The root is ignored because a module with the same name '${module.name}' " +
"has been found earlier on the module path$atExistingPath", thisFile
)
} }
} }
@@ -265,8 +263,7 @@ class ClasspathRootsResolver(
val module = javaModuleFinder.findModule(moduleName) val module = javaModuleFinder.findModule(moduleName)
if (module == null) { if (module == null) {
report(ERROR, "Module $moduleName cannot be found in the module graph") report(ERROR, "Module $moduleName cannot be found in the module graph")
} } else {
else {
for ((root, isBinary) in module.moduleRoots) { for ((root, isBinary) in module.moduleRoots) {
result.add(JavaRoot(root, if (isBinary) JavaRoot.RootType.BINARY else JavaRoot.RootType.SOURCE)) result.add(JavaRoot(root, if (isBinary) JavaRoot.RootType.BINARY else JavaRoot.RootType.SOURCE))
} }
@@ -275,10 +272,10 @@ class ClasspathRootsResolver(
if (requireStdlibModule && sourceModule != null && !javaModuleGraph.reads(sourceModule.name, KOTLIN_STDLIB_MODULE_NAME)) { if (requireStdlibModule && sourceModule != null && !javaModuleGraph.reads(sourceModule.name, KOTLIN_STDLIB_MODULE_NAME)) {
report( report(
ERROR, ERROR,
"The Kotlin standard library is not found in the module graph. " + "The Kotlin standard library is not found in the module graph. " +
"Please ensure you have the 'requires $KOTLIN_STDLIB_MODULE_NAME' clause in your module definition", "Please ensure you have the 'requires $KOTLIN_STDLIB_MODULE_NAME' clause in your module definition",
sourceModule.moduleInfoFile sourceModule.moduleInfoFile
) )
} }
} }
@@ -322,8 +319,8 @@ class ClasspathRootsResolver(
throw IllegalStateException("${if (file != null) file.path + ":" else ""}$severity: $message (no MessageCollector configured)") throw IllegalStateException("${if (file != null) file.path + ":" else ""}$severity: $message (no MessageCollector configured)")
} }
messageCollector.report( messageCollector.report(
severity, message, severity, message,
if (file == null) null else CompilerMessageLocation.create(MessageUtil.virtualFileToPath(file)) if (file == null) null else CompilerMessageLocation.create(MessageUtil.virtualFileToPath(file))
) )
} }
@@ -10,15 +10,12 @@ import com.intellij.psi.PsiClass
import com.intellij.psi.PsiManager import com.intellij.psi.PsiManager
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.PsiSearchScopeUtil import com.intellij.psi.search.PsiSearchScopeUtil
import com.intellij.util.Function
import com.intellij.util.SmartList import com.intellij.util.SmartList
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport
import org.jetbrains.kotlin.asJava.classes.KtLightClass import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
import org.jetbrains.kotlin.asJava.classes.KtLightClassForScript import org.jetbrains.kotlin.asJava.classes.KtLightClassForScript
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
import org.jetbrains.kotlin.load.java.components.FilesByFacadeFqNameIndexer import org.jetbrains.kotlin.load.java.components.FilesByFacadeFqNameIndexer
@@ -35,19 +32,14 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope
class CliKotlinAsJavaSupport( class CliKotlinAsJavaSupport(
project: Project, project: Project,
private val traceHolder: CliTraceHolder private val traceHolder: CliTraceHolder
): KotlinAsJavaSupport() { ) : KotlinAsJavaSupport() {
private val psiManager = PsiManager.getInstance(project) private val psiManager = PsiManager.getInstance(project)
override fun getFacadeClassesInPackage(packageFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> { override fun getFacadeClassesInPackage(packageFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {
return findFacadeFilesInPackage(packageFqName, scope) return findFacadeFilesInPackage(packageFqName, scope)
.groupBy { it.javaFileFacadeFqName } .groupBy { it.javaFileFacadeFqName }
.mapNotNull { .mapNotNull { (facadeClassFqName, files) ->
KtLightClassForFacade.createForFacade( KtLightClassForFacade.createForFacade(psiManager, facadeClassFqName, scope, files)
psiManager,
it.key,
scope,
it.value
)
} }
} }
@@ -67,13 +59,8 @@ class CliKotlinAsJavaSupport(
val filesForFacade = findFilesForFacade(facadeFqName, scope) val filesForFacade = findFilesForFacade(facadeFqName, scope)
if (filesForFacade.isEmpty()) return emptyList() if (filesForFacade.isEmpty()) return emptyList()
return listOfNotNull<PsiClass>( return listOfNotNull(
KtLightClassForFacade.createForFacade( KtLightClassForFacade.createForFacade(psiManager, facadeFqName, scope, filesForFacade)
psiManager,
facadeFqName,
scope,
filesForFacade
)
) )
} }
@@ -88,7 +75,6 @@ class CliKotlinAsJavaSupport(
} }
override fun getKotlinInternalClasses(fqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> { override fun getKotlinInternalClasses(fqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {
//
return emptyList() return emptyList()
} }
@@ -97,7 +83,7 @@ class CliKotlinAsJavaSupport(
return traceHolder.bindingContext.get(FilesByFacadeFqNameIndexer.FACADE_FILES_BY_FQ_NAME, facadeFqName)?.filter { return traceHolder.bindingContext.get(FilesByFacadeFqNameIndexer.FACADE_FILES_BY_FQ_NAME, facadeFqName)?.filter {
PsiSearchScopeUtil.isInScope(scope, it) PsiSearchScopeUtil.isInScope(scope, it)
} ?: emptyList() }.orEmpty()
} }
@@ -122,20 +108,10 @@ class CliKotlinAsJavaSupport(
override fun getSubPackages(fqn: FqName, scope: GlobalSearchScope): Collection<FqName> { override fun getSubPackages(fqn: FqName, scope: GlobalSearchScope): Collection<FqName> {
val packageView = traceHolder.module.getPackage(fqn) val packageView = traceHolder.module.getPackage(fqn)
val members = packageView.memberScope.getContributedDescriptors( return packageView.memberScope.getContributedDescriptors(
DescriptorKindFilter.PACKAGES, DescriptorKindFilter.PACKAGES,
MemberScope.ALL_NAME_FILTER MemberScope.ALL_NAME_FILTER
) ).mapNotNull { member -> (member as? PackageViewDescriptor)?.fqName }
return ContainerUtil.mapNotNull(
members,
object : Function<DeclarationDescriptor, FqName> {
override fun `fun`(member: DeclarationDescriptor): FqName? {
if (member is PackageViewDescriptor) {
return member.fqName
}
return null
}
})
} }
override fun getLightClass(classOrObject: KtClassOrObject): KtLightClass? = override fun getLightClass(classOrObject: KtClassOrObject): KtLightClass? =
@@ -144,24 +120,18 @@ class CliKotlinAsJavaSupport(
override fun getLightClassForScript(script: KtScript): KtLightClassForScript? = override fun getLightClassForScript(script: KtScript): KtLightClassForScript? =
KtLightClassForScript.create(script) KtLightClassForScript.create(script)
override fun findClassOrObjectDeclarations(fqName: FqName, searchScope: GlobalSearchScope): Collection<KtClassOrObject> { override fun findClassOrObjectDeclarations(fqName: FqName, searchScope: GlobalSearchScope): Collection<KtClassOrObject> {
return ResolveSessionUtils.getClassDescriptorsByFqName(traceHolder.module, fqName).mapNotNull { return ResolveSessionUtils.getClassDescriptorsByFqName(traceHolder.module, fqName).mapNotNull {
val element = DescriptorToSourceUtils.getSourceFromDescriptor(it) val element = DescriptorToSourceUtils.getSourceFromDescriptor(it)
if (element is KtClassOrObject && PsiSearchScopeUtil.isInScope( if (element is KtClassOrObject && PsiSearchScopeUtil.isInScope(searchScope, element)) {
searchScope,
element
)
) {
element element
} } else null
else null
} }
} }
override fun findFilesForPackage(fqName: FqName, searchScope: GlobalSearchScope): Collection<KtFile> { override fun findFilesForPackage(fqName: FqName, searchScope: GlobalSearchScope): Collection<KtFile> {
return traceHolder.bindingContext.get(BindingContext.PACKAGE_TO_FILES, fqName)?.filter { return traceHolder.bindingContext.get(BindingContext.PACKAGE_TO_FILES, fqName)?.filter {
PsiSearchScopeUtil.isInScope(searchScope, it) PsiSearchScopeUtil.isInScope(searchScope, it)
} ?: emptyList() }.orEmpty()
} }
} }
@@ -39,9 +39,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
* To mitigate this, CliLightClassGenerationSupport hold a trace that is shared between the analyzer and JetLightClasses * To mitigate this, CliLightClassGenerationSupport hold a trace that is shared between the analyzer and JetLightClasses
*/ */
class CliLightClassGenerationSupport(private val traceHolder: CliTraceHolder) : LightClassGenerationSupport() { class CliLightClassGenerationSupport(private val traceHolder: CliTraceHolder) : LightClassGenerationSupport() {
override fun createDataHolderForClass( override fun createDataHolderForClass(classOrObject: KtClassOrObject, builder: LightClassBuilder): LightClassDataHolder.ForClass {
classOrObject: KtClassOrObject, builder: LightClassBuilder
): LightClassDataHolder.ForClass {
//force resolve companion for light class generation //force resolve companion for light class generation
traceHolder.bindingContext.get(BindingContext.CLASS, classOrObject)?.companionObjectDescriptor traceHolder.bindingContext.get(BindingContext.CLASS, classOrObject)?.companionObjectDescriptor
@@ -49,10 +47,7 @@ class CliLightClassGenerationSupport(private val traceHolder: CliTraceHolder) :
bindingContext.get(BindingContext.CLASS, classOrObject) ?: return InvalidLightClassDataHolder bindingContext.get(BindingContext.CLASS, classOrObject) ?: return InvalidLightClassDataHolder
return LightClassDataHolderImpl( return LightClassDataHolderImpl(stub, diagnostics)
stub,
diagnostics
)
} }
override fun createDataHolderForFacade(files: Collection<KtFile>, builder: LightClassBuilder): LightClassDataHolder.ForFacade { override fun createDataHolderForFacade(files: Collection<KtFile>, builder: LightClassBuilder): LightClassDataHolder.ForFacade {
@@ -75,5 +70,3 @@ class CliLightClassGenerationSupport(private val traceHolder: CliTraceHolder) :
override fun analyzeWithContent(element: KtClassOrObject) = traceHolder.bindingContext override fun analyzeWithContent(element: KtClassOrObject) = traceHolder.bindingContext
} }
@@ -45,7 +45,7 @@ class CliTraceHolder : CodeAnalyzerInitializer {
// TODO: needs better name + list of keys to skip somewhere // TODO: needs better name + list of keys to skip somewhere
class NoScopeRecordCliBindingTrace : CliBindingTrace() { class NoScopeRecordCliBindingTrace : CliBindingTrace() {
override fun <K, V> record(slice: WritableSlice<K, V>, key: K, value: V) { override fun <K, V> record(slice: WritableSlice<K, V>, key: K, value: V) {
if (slice === BindingContext.LEXICAL_SCOPE || slice == BindingContext.DATA_FLOW_INFO_BEFORE) { if (slice == BindingContext.LEXICAL_SCOPE || slice == BindingContext.DATA_FLOW_INFO_BEFORE) {
// In the compiler there's no need to keep scopes // In the compiler there's no need to keep scopes
return return
} }
@@ -29,16 +29,19 @@ import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerial
import java.io.InputStream import java.io.InputStream
class CliVirtualFileFinder( class CliVirtualFileFinder(
private val index: JvmDependenciesIndex, private val index: JvmDependenciesIndex,
private val scope: GlobalSearchScope private val scope: GlobalSearchScope
) : VirtualFileFinder() { ) : VirtualFileFinder() {
override fun findVirtualFileWithHeader(classId: ClassId): VirtualFile? = override fun findVirtualFileWithHeader(classId: ClassId): VirtualFile? =
findBinaryClass(classId, classId.relativeClassName.asString().replace('.', '$') + ".class") findBinaryClass(classId, classId.relativeClassName.asString().replace('.', '$') + ".class")
override fun findMetadata(classId: ClassId): InputStream? { override fun findMetadata(classId: ClassId): InputStream? {
assert(!classId.isNestedClass) { "Nested classes are not supported here: $classId" } assert(!classId.isNestedClass) { "Nested classes are not supported here: $classId" }
return findBinaryClass(classId, classId.shortClassName.asString() + MetadataPackageFragment.DOT_METADATA_FILE_EXTENSION)?.inputStream return findBinaryClass(
classId,
classId.shortClassName.asString() + MetadataPackageFragment.DOT_METADATA_FILE_EXTENSION
)?.inputStream
} }
override fun hasMetadataPackage(fqName: FqName): Boolean { override fun hasMetadataPackage(fqName: FqName): Boolean {
@@ -59,7 +62,7 @@ class CliVirtualFileFinder(
} }
private fun findBinaryClass(classId: ClassId, fileName: String): VirtualFile? = private fun findBinaryClass(classId: ClassId, fileName: String): VirtualFile? =
index.findClass(classId, acceptedRootTypes = JavaRoot.OnlyBinary) { dir, _ -> index.findClass(classId, acceptedRootTypes = JavaRoot.OnlyBinary) { dir, _ ->
dir.findChild(fileName)?.takeIf(VirtualFile::isValid) dir.findChild(fileName)?.takeIf(VirtualFile::isValid)
}?.takeIf { it in scope } }?.takeIf { it in scope }
} }
@@ -21,10 +21,6 @@ public class CompileEnvironmentException extends RuntimeException {
super(message); super(message);
} }
public CompileEnvironmentException(Throwable cause) {
super(cause);
}
public CompileEnvironmentException(String message, Throwable cause) { public CompileEnvironmentException(String message, Throwable cause) {
super(message, cause); super(message, cause);
} }
@@ -73,7 +73,9 @@ public class CompileEnvironmentUtil {
} }
// TODO: includeRuntime should be not a flag but a path to runtime // TODO: includeRuntime should be not a flag but a path to runtime
private static void doWriteToJar(OutputFileCollection outputFiles, OutputStream fos, @Nullable FqName mainClass, boolean includeRuntime) { private static void doWriteToJar(
OutputFileCollection outputFiles, OutputStream fos, @Nullable FqName mainClass, boolean includeRuntime
) {
try { try {
Manifest manifest = new Manifest(); Manifest manifest = new Manifest();
Attributes mainAttributes = manifest.getMainAttributes(); Attributes mainAttributes = manifest.getMainAttributes();
@@ -31,8 +31,8 @@ import org.jetbrains.kotlin.serialization.deserialization.MetadataPartProvider
import java.io.EOFException import java.io.EOFException
class JvmPackagePartProvider( class JvmPackagePartProvider(
languageVersionSettings: LanguageVersionSettings, languageVersionSettings: LanguageVersionSettings,
private val scope: GlobalSearchScope private val scope: GlobalSearchScope
) : PackagePartProvider, MetadataPartProvider { ) : PackagePartProvider, MetadataPartProvider {
private data class ModuleMappingInfo(val root: VirtualFile, val mapping: ModuleMapping, val name: String) private data class ModuleMappingInfo(val root: VirtualFile, val mapping: ModuleMapping, val name: String)
@@ -59,7 +59,7 @@ class JvmPackagePartProvider(
} }
override fun findMetadataPackageParts(packageFqName: String): List<String> = override fun findMetadataPackageParts(packageFqName: String): List<String> =
getPackageParts(packageFqName).values.flatMap(PackageParts::metadataParts).distinct() getPackageParts(packageFqName).values.flatMap(PackageParts::metadataParts).distinct()
@Synchronized @Synchronized
private fun getPackageParts(packageFqName: String): Map<VirtualFile, PackageParts> { private fun getPackageParts(packageFqName: String): Map<VirtualFile, PackageParts> {
@@ -53,10 +53,10 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
private var useFastClassFilesReading = false private var useFastClassFilesReading = false
fun initialize( fun initialize(
index: JvmDependenciesIndex, index: JvmDependenciesIndex,
packagePartProviders: List<JvmPackagePartProvider>, packagePartProviders: List<JvmPackagePartProvider>,
singleJavaFileRootsIndex: SingleJavaFileRootsIndex, singleJavaFileRootsIndex: SingleJavaFileRootsIndex,
useFastClassFilesReading: Boolean useFastClassFilesReading: Boolean
) { ) {
this.index = index this.index = index
this.packagePartProviders = packagePartProviders this.packagePartProviders = packagePartProviders
@@ -73,14 +73,12 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
return topLevelClassesCache.getOrPut(classId.packageFqName.child(classId.relativeClassName.pathSegments().first())) { return topLevelClassesCache.getOrPut(classId.packageFqName.child(classId.relativeClassName.pathSegments().first())) {
index.findClass(classId) { dir, type -> index.findClass(classId) { dir, type ->
findVirtualFileGivenPackage(dir, relativeClassName, type) findVirtualFileGivenPackage(dir, relativeClassName, type)
} } ?: singleJavaFileRootsIndex.findJavaSourceClass(classId)
?: singleJavaFileRootsIndex.findJavaSourceClass(classId)
}?.takeIf { it in searchScope } }?.takeIf { it in searchScope }
} }
private val binaryCache: MutableMap<ClassId, JavaClass?> = THashMap() private val binaryCache: MutableMap<ClassId, JavaClass?> = THashMap()
private val signatureParsingComponent = private val signatureParsingComponent = BinaryClassSignatureParser()
BinaryClassSignatureParser()
override fun findClass(classId: ClassId, searchScope: GlobalSearchScope): JavaClass? { override fun findClass(classId: ClassId, searchScope: GlobalSearchScope): JavaClass? {
val virtualFile = findVirtualFileForTopLevelClass(classId, searchScope) ?: return null val virtualFile = findVirtualFileForTopLevelClass(classId, searchScope) ?: return null
@@ -103,12 +101,8 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
val resolver = ClassifierResolutionContext { findClass(it, allScope) } val resolver = ClassifierResolutionContext { findClass(it, allScope) }
BinaryJavaClass( BinaryJavaClass(
virtualFile, virtualFile, classId.asSingleFqName(), resolver, signatureParsingComponent,
classId.asSingleFqName(), outerClass = null, classContent = classContent
resolver,
signatureParsingComponent,
outerClass = null,
classContent = classContent
) )
} }
} }
@@ -142,9 +136,9 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
if (packageFqName.isRoot) break if (packageFqName.isRoot) break
classId = ClassId( classId = ClassId(
packageFqName.parent(), packageFqName.parent(),
FqName(packageFqName.shortName().asString() + "." + classId.relativeClassName.asString()), FqName(packageFqName.shortName().asString() + "." + classId.relativeClassName.asString()),
false false
) )
} }
} }
@@ -155,9 +149,9 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
val relativeClassName = classId.relativeClassName.asString() val relativeClassName = classId.relativeClassName.asString()
index.traverseDirectoriesInPackage(classId.packageFqName) { dir, rootType -> index.traverseDirectoriesInPackage(classId.packageFqName) { dir, rootType ->
val psiClass = val psiClass =
findVirtualFileGivenPackage(dir, relativeClassName, rootType) findVirtualFileGivenPackage(dir, relativeClassName, rootType)
?.takeIf { it in scope } ?.takeIf { it in scope }
?.findPsiClassInVirtualFile(relativeClassName) ?.findPsiClassInVirtualFile(relativeClassName)
if (psiClass != null) { if (psiClass != null) {
result.add(psiClass) result.add(psiClass)
} }
@@ -166,9 +160,9 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
} }
result.addIfNotNull( result.addIfNotNull(
singleJavaFileRootsIndex.findJavaSourceClass(classId) singleJavaFileRootsIndex.findJavaSourceClass(classId)
?.takeIf { it in scope } ?.takeIf { it in scope }
?.findPsiClassInVirtualFile(relativeClassName) ?.findPsiClassInVirtualFile(relativeClassName)
) )
if (result.isNotEmpty()) { if (result.isNotEmpty()) {
@@ -197,9 +191,9 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
} }
private fun findVirtualFileGivenPackage( private fun findVirtualFileGivenPackage(
packageDir: VirtualFile, packageDir: VirtualFile,
classNameWithInnerClasses: String, classNameWithInnerClasses: String,
rootType: JavaRoot.RootType rootType: JavaRoot.RootType
): VirtualFile? { ): VirtualFile? {
val topLevelClassName = classNameWithInnerClasses.substringBefore('.') val topLevelClassName = classNameWithInnerClasses.substringBefore('.')
@@ -216,18 +210,14 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
return vFile return vFile
} }
private fun VirtualFile.findPsiClassInVirtualFile( private fun VirtualFile.findPsiClassInVirtualFile(classNameWithInnerClasses: String): PsiClass? {
classNameWithInnerClasses: String
): PsiClass? {
val file = myPsiManager.findFile(this) as? PsiClassOwner ?: return null val file = myPsiManager.findFile(this) as? PsiClassOwner ?: return null
return findClassInPsiFile(classNameWithInnerClasses, file) return findClassInPsiFile(classNameWithInnerClasses, file)
} }
override fun knownClassNamesInPackage(packageFqName: FqName): Set<String> { override fun knownClassNamesInPackage(packageFqName: FqName): Set<String> {
val result = hashSetOf<String>() val result = hashSetOf<String>()
index.traverseDirectoriesInPackage(packageFqName, continueSearch = { index.traverseDirectoriesInPackage(packageFqName, continueSearch = { dir, _ ->
dir, _ ->
for (child in dir.children) { for (child in dir.children) {
if (child.extension == "class" || child.extension == "java") { if (child.extension == "class" || child.extension == "java") {
result.add(child.nameWithoutExtension) result.add(child.nameWithoutExtension)
@@ -286,15 +276,14 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
} }
// a sad workaround to avoid throwing exception when called from inside IDEA code // a sad workaround to avoid throwing exception when called from inside IDEA code
private fun <T : Any> safely(compute: () -> T): T? = try { private fun <T : Any> safely(compute: () -> T): T? =
compute() try {
} compute()
catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
null null
} } catch (e: AssertionError) {
catch (e: AssertionError) { null
null }
}
private fun String.toSafeFqName(): FqName? = safely { FqName(this) } private fun String.toSafeFqName(): FqName? = safely { FqName(this) }
private fun String.toSafeTopLevelClassId(): ClassId? = safely { ClassId.topLevel(FqName(this)) } private fun String.toSafeTopLevelClassId(): ClassId? = safely { ClassId.topLevel(FqName(this)) }
@@ -53,10 +53,10 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
private var useFastClassFilesReading = false private var useFastClassFilesReading = false
fun initialize( fun initialize(
index: JvmDependenciesIndex, index: JvmDependenciesIndex,
packagePartProviders: List<JvmPackagePartProvider>, packagePartProviders: List<JvmPackagePartProvider>,
singleJavaFileRootsIndex: SingleJavaFileRootsIndex, singleJavaFileRootsIndex: SingleJavaFileRootsIndex,
useFastClassFilesReading: Boolean useFastClassFilesReading: Boolean
) { ) {
this.index = index this.index = index
this.packagePartProviders = packagePartProviders this.packagePartProviders = packagePartProviders
@@ -73,14 +73,12 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
return topLevelClassesCache.getOrPut(classId.packageFqName.child(classId.relativeClassName.pathSegments().first())) { return topLevelClassesCache.getOrPut(classId.packageFqName.child(classId.relativeClassName.pathSegments().first())) {
index.findClass(classId) { dir, type -> index.findClass(classId) { dir, type ->
findVirtualFileGivenPackage(dir, relativeClassName, type) findVirtualFileGivenPackage(dir, relativeClassName, type)
} } ?: singleJavaFileRootsIndex.findJavaSourceClass(classId)
?: singleJavaFileRootsIndex.findJavaSourceClass(classId)
}?.takeIf { it in searchScope } }?.takeIf { it in searchScope }
} }
private val binaryCache: MutableMap<ClassId, JavaClass?> = THashMap() private val binaryCache: MutableMap<ClassId, JavaClass?> = THashMap()
private val signatureParsingComponent = private val signatureParsingComponent = BinaryClassSignatureParser()
BinaryClassSignatureParser()
override fun findClass(classId: ClassId, searchScope: GlobalSearchScope): JavaClass? { override fun findClass(classId: ClassId, searchScope: GlobalSearchScope): JavaClass? {
val virtualFile = findVirtualFileForTopLevelClass(classId, searchScope) ?: return null val virtualFile = findVirtualFileForTopLevelClass(classId, searchScope) ?: return null
@@ -103,12 +101,8 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
val resolver = ClassifierResolutionContext { findClass(it, allScope) } val resolver = ClassifierResolutionContext { findClass(it, allScope) }
BinaryJavaClass( BinaryJavaClass(
virtualFile, virtualFile, classId.asSingleFqName(), resolver, signatureParsingComponent,
classId.asSingleFqName(), outerClass = null, classContent = classContent
resolver,
signatureParsingComponent,
outerClass = null,
classContent = classContent
) )
} }
} }
@@ -142,9 +136,9 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
if (packageFqName.isRoot) break if (packageFqName.isRoot) break
classId = ClassId( classId = ClassId(
packageFqName.parent(), packageFqName.parent(),
FqName(packageFqName.shortName().asString() + "." + classId.relativeClassName.asString()), FqName(packageFqName.shortName().asString() + "." + classId.relativeClassName.asString()),
false false
) )
} }
} }
@@ -155,9 +149,9 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
val relativeClassName = classId.relativeClassName.asString() val relativeClassName = classId.relativeClassName.asString()
index.traverseDirectoriesInPackage(classId.packageFqName) { dir, rootType -> index.traverseDirectoriesInPackage(classId.packageFqName) { dir, rootType ->
val psiClass = val psiClass =
findVirtualFileGivenPackage(dir, relativeClassName, rootType) findVirtualFileGivenPackage(dir, relativeClassName, rootType)
?.takeIf { it in scope } ?.takeIf { it in scope }
?.findPsiClassInVirtualFile(relativeClassName) ?.findPsiClassInVirtualFile(relativeClassName)
if (psiClass != null) { if (psiClass != null) {
result.add(psiClass) result.add(psiClass)
} }
@@ -166,9 +160,9 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
} }
result.addIfNotNull( result.addIfNotNull(
singleJavaFileRootsIndex.findJavaSourceClass(classId) singleJavaFileRootsIndex.findJavaSourceClass(classId)
?.takeIf { it in scope } ?.takeIf { it in scope }
?.findPsiClassInVirtualFile(relativeClassName) ?.findPsiClassInVirtualFile(relativeClassName)
) )
if (result.isNotEmpty()) { if (result.isNotEmpty()) {
@@ -197,9 +191,9 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
} }
private fun findVirtualFileGivenPackage( private fun findVirtualFileGivenPackage(
packageDir: VirtualFile, packageDir: VirtualFile,
classNameWithInnerClasses: String, classNameWithInnerClasses: String,
rootType: JavaRoot.RootType rootType: JavaRoot.RootType
): VirtualFile? { ): VirtualFile? {
val topLevelClassName = classNameWithInnerClasses.substringBefore('.') val topLevelClassName = classNameWithInnerClasses.substringBefore('.')
@@ -216,18 +210,14 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
return vFile return vFile
} }
private fun VirtualFile.findPsiClassInVirtualFile( private fun VirtualFile.findPsiClassInVirtualFile(classNameWithInnerClasses: String): PsiClass? {
classNameWithInnerClasses: String
): PsiClass? {
val file = myPsiManager.findFile(this) as? PsiClassOwner ?: return null val file = myPsiManager.findFile(this) as? PsiClassOwner ?: return null
return findClassInPsiFile(classNameWithInnerClasses, file) return findClassInPsiFile(classNameWithInnerClasses, file)
} }
override fun knownClassNamesInPackage(packageFqName: FqName): Set<String> { override fun knownClassNamesInPackage(packageFqName: FqName): Set<String> {
val result = hashSetOf<String>() val result = hashSetOf<String>()
index.traverseDirectoriesInPackage(packageFqName, continueSearch = { index.traverseDirectoriesInPackage(packageFqName, continueSearch = { dir, _ ->
dir, _ ->
for (child in dir.children) { for (child in dir.children) {
if (child.extension == "class" || child.extension == "java") { if (child.extension == "class" || child.extension == "java") {
result.add(child.nameWithoutExtension) result.add(child.nameWithoutExtension)
@@ -288,15 +278,14 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
} }
// a sad workaround to avoid throwing exception when called from inside IDEA code // a sad workaround to avoid throwing exception when called from inside IDEA code
private fun <T : Any> safely(compute: () -> T): T? = try { private fun <T : Any> safely(compute: () -> T): T? =
compute() try {
} compute()
catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
null null
} } catch (e: AssertionError) {
catch (e: AssertionError) { null
null }
}
private fun String.toSafeFqName(): FqName? = safely { FqName(this) } private fun String.toSafeFqName(): FqName? = safely { FqName(this) }
private fun String.toSafeTopLevelClassId(): ClassId? = safely { ClassId.topLevel(FqName(this)) } private fun String.toSafeTopLevelClassId(): ClassId? = safely { ClassId.topLevel(FqName(this)) }
@@ -53,10 +53,10 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
private var useFastClassFilesReading = false private var useFastClassFilesReading = false
fun initialize( fun initialize(
index: JvmDependenciesIndex, index: JvmDependenciesIndex,
packagePartProviders: List<JvmPackagePartProvider>, packagePartProviders: List<JvmPackagePartProvider>,
singleJavaFileRootsIndex: SingleJavaFileRootsIndex, singleJavaFileRootsIndex: SingleJavaFileRootsIndex,
useFastClassFilesReading: Boolean useFastClassFilesReading: Boolean
) { ) {
this.index = index this.index = index
this.packagePartProviders = packagePartProviders this.packagePartProviders = packagePartProviders
@@ -73,14 +73,12 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
return topLevelClassesCache.getOrPut(classId.packageFqName.child(classId.relativeClassName.pathSegments().first())) { return topLevelClassesCache.getOrPut(classId.packageFqName.child(classId.relativeClassName.pathSegments().first())) {
index.findClass(classId) { dir, type -> index.findClass(classId) { dir, type ->
findVirtualFileGivenPackage(dir, relativeClassName, type) findVirtualFileGivenPackage(dir, relativeClassName, type)
} } ?: singleJavaFileRootsIndex.findJavaSourceClass(classId)
?: singleJavaFileRootsIndex.findJavaSourceClass(classId)
}?.takeIf { it in searchScope } }?.takeIf { it in searchScope }
} }
private val binaryCache: MutableMap<ClassId, JavaClass?> = THashMap() private val binaryCache: MutableMap<ClassId, JavaClass?> = THashMap()
private val signatureParsingComponent = private val signatureParsingComponent = BinaryClassSignatureParser()
BinaryClassSignatureParser()
override fun findClass(classId: ClassId, searchScope: GlobalSearchScope): JavaClass? { override fun findClass(classId: ClassId, searchScope: GlobalSearchScope): JavaClass? {
val virtualFile = findVirtualFileForTopLevelClass(classId, searchScope) ?: return null val virtualFile = findVirtualFileForTopLevelClass(classId, searchScope) ?: return null
@@ -103,12 +101,8 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
val resolver = ClassifierResolutionContext { findClass(it, allScope) } val resolver = ClassifierResolutionContext { findClass(it, allScope) }
BinaryJavaClass( BinaryJavaClass(
virtualFile, virtualFile, classId.asSingleFqName(), resolver, signatureParsingComponent,
classId.asSingleFqName(), outerClass = null, classContent = classContent
resolver,
signatureParsingComponent,
outerClass = null,
classContent = classContent
) )
} }
} }
@@ -142,9 +136,9 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
if (packageFqName.isRoot) break if (packageFqName.isRoot) break
classId = ClassId( classId = ClassId(
packageFqName.parent(), packageFqName.parent(),
FqName(packageFqName.shortName().asString() + "." + classId.relativeClassName.asString()), FqName(packageFqName.shortName().asString() + "." + classId.relativeClassName.asString()),
false false
) )
} }
} }
@@ -155,9 +149,9 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
val relativeClassName = classId.relativeClassName.asString() val relativeClassName = classId.relativeClassName.asString()
index.traverseDirectoriesInPackage(classId.packageFqName) { dir, rootType -> index.traverseDirectoriesInPackage(classId.packageFqName) { dir, rootType ->
val psiClass = val psiClass =
findVirtualFileGivenPackage(dir, relativeClassName, rootType) findVirtualFileGivenPackage(dir, relativeClassName, rootType)
?.takeIf { it in scope } ?.takeIf { it in scope }
?.findPsiClassInVirtualFile(relativeClassName) ?.findPsiClassInVirtualFile(relativeClassName)
if (psiClass != null) { if (psiClass != null) {
result.add(psiClass) result.add(psiClass)
} }
@@ -166,9 +160,9 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
} }
result.addIfNotNull( result.addIfNotNull(
singleJavaFileRootsIndex.findJavaSourceClass(classId) singleJavaFileRootsIndex.findJavaSourceClass(classId)
?.takeIf { it in scope } ?.takeIf { it in scope }
?.findPsiClassInVirtualFile(relativeClassName) ?.findPsiClassInVirtualFile(relativeClassName)
) )
if (result.isNotEmpty()) { if (result.isNotEmpty()) {
@@ -197,9 +191,9 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
} }
private fun findVirtualFileGivenPackage( private fun findVirtualFileGivenPackage(
packageDir: VirtualFile, packageDir: VirtualFile,
classNameWithInnerClasses: String, classNameWithInnerClasses: String,
rootType: JavaRoot.RootType rootType: JavaRoot.RootType
): VirtualFile? { ): VirtualFile? {
val topLevelClassName = classNameWithInnerClasses.substringBefore('.') val topLevelClassName = classNameWithInnerClasses.substringBefore('.')
@@ -216,18 +210,14 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
return vFile return vFile
} }
private fun VirtualFile.findPsiClassInVirtualFile( private fun VirtualFile.findPsiClassInVirtualFile(classNameWithInnerClasses: String): PsiClass? {
classNameWithInnerClasses: String
): PsiClass? {
val file = myPsiManager.findFile(this) as? PsiClassOwner ?: return null val file = myPsiManager.findFile(this) as? PsiClassOwner ?: return null
return findClassInPsiFile(classNameWithInnerClasses, file) return findClassInPsiFile(classNameWithInnerClasses, file)
} }
override fun knownClassNamesInPackage(packageFqName: FqName): Set<String> { override fun knownClassNamesInPackage(packageFqName: FqName): Set<String> {
val result = hashSetOf<String>() val result = hashSetOf<String>()
index.traverseDirectoriesInPackage(packageFqName, continueSearch = { index.traverseDirectoriesInPackage(packageFqName, continueSearch = { dir, _ ->
dir, _ ->
for (child in dir.children) { for (child in dir.children) {
if (child.extension == "class" || child.extension == "java") { if (child.extension == "class" || child.extension == "java") {
result.add(child.nameWithoutExtension) result.add(child.nameWithoutExtension)
@@ -288,15 +278,14 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
} }
// a sad workaround to avoid throwing exception when called from inside IDEA code // a sad workaround to avoid throwing exception when called from inside IDEA code
private fun <T : Any> safely(compute: () -> T): T? = try { private fun <T : Any> safely(compute: () -> T): T? =
compute() try {
} compute()
catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
null null
} } catch (e: AssertionError) {
catch (e: AssertionError) { null
null }
}
private fun String.toSafeFqName(): FqName? = safely { FqName(this) } private fun String.toSafeFqName(): FqName? = safely { FqName(this) }
private fun String.toSafeTopLevelClassId(): ClassId? = safely { ClassId.topLevel(FqName(this)) } private fun String.toSafeTopLevelClassId(): ClassId? = safely { ClassId.topLevel(FqName(this)) }
@@ -246,7 +246,7 @@ class KotlinCoreEnvironment private constructor(
val outputDirectory = val outputDirectory =
configuration.get(JVMConfigurationKeys.MODULES)?.singleOrNull()?.getOutputDirectory() configuration.get(JVMConfigurationKeys.MODULES)?.singleOrNull()?.getOutputDirectory()
?: configuration.get(JVMConfigurationKeys.OUTPUT_DIRECTORY)?.absolutePath ?: configuration.get(JVMConfigurationKeys.OUTPUT_DIRECTORY)?.absolutePath
classpathRootsResolver = ClasspathRootsResolver( classpathRootsResolver = ClasspathRootsResolver(
PsiManager.getInstance(project), PsiManager.getInstance(project),
@@ -554,14 +554,14 @@ class KotlinCoreEnvironment private constructor(
val pluginRoot = val pluginRoot =
configuration.get(CLIConfigurationKeys.INTELLIJ_PLUGIN_ROOT)?.let(::File) configuration.get(CLIConfigurationKeys.INTELLIJ_PLUGIN_ROOT)?.let(::File)
?: configuration.get(CLIConfigurationKeys.COMPILER_JAR_LOCATOR)?.compilerJar ?: configuration.get(CLIConfigurationKeys.COMPILER_JAR_LOCATOR)?.compilerJar
?: PathUtil.getResourcePathForClass(this::class.java).takeIf { it.hasConfigFile(configFilePath) } ?: PathUtil.getResourcePathForClass(this::class.java).takeIf { it.hasConfigFile(configFilePath) }
// hack for load extensions when compiler run directly from project directory (e.g. in tests) // hack for load extensions when compiler run directly from project directory (e.g. in tests)
?: File("idea/src").takeIf { it.hasConfigFile(configFilePath) } ?: File("idea/src").takeIf { it.hasConfigFile(configFilePath) }
?: throw IllegalStateException( ?: throw IllegalStateException(
"Unable to find extension point configuration $configFilePath " + "Unable to find extension point configuration $configFilePath " +
"(cp:\n ${(Thread.currentThread().contextClassLoader as? UrlClassLoader)?.urls?.joinToString("\n ") { it.file }})" "(cp:\n ${(Thread.currentThread().contextClassLoader as? UrlClassLoader)?.urls?.joinToString("\n ") { it.file }})"
) )
CoreApplicationEnvironment.registerExtensionPointAndExtensions(pluginRoot, configFilePath, Extensions.getRootArea()) CoreApplicationEnvironment.registerExtensionPointAndExtensions(pluginRoot, configFilePath, Extensions.getRootArea())
} }
@@ -20,11 +20,10 @@ import com.intellij.core.JavaCoreApplicationEnvironment
import com.intellij.core.JavaCoreProjectEnvironment import com.intellij.core.JavaCoreProjectEnvironment
import com.intellij.openapi.Disposable import com.intellij.openapi.Disposable
import com.intellij.psi.PsiManager import com.intellij.psi.PsiManager
import com.intellij.psi.controlFlow.ControlFlowFactory
open class KotlinCoreProjectEnvironment( open class KotlinCoreProjectEnvironment(
disposable: Disposable, disposable: Disposable,
applicationEnvironment: JavaCoreApplicationEnvironment applicationEnvironment: JavaCoreApplicationEnvironment
) : JavaCoreProjectEnvironment(disposable, applicationEnvironment) { ) : JavaCoreProjectEnvironment(disposable, applicationEnvironment) {
override fun createCoreFileManager() = KotlinCliJavaFileManagerImpl(PsiManager.getInstance(project)) override fun createCoreFileManager() = KotlinCliJavaFileManagerImpl(PsiManager.getInstance(project))
} }
@@ -29,7 +29,9 @@ import org.jetbrains.kotlin.asJava.FilteredJvmDiagnostics
import org.jetbrains.kotlin.backend.common.output.OutputFileCollection import org.jetbrains.kotlin.backend.common.output.OutputFileCollection
import org.jetbrains.kotlin.backend.common.output.SimpleOutputFileCollection import org.jetbrains.kotlin.backend.common.output.SimpleOutputFileCollection
import org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory import org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory
import org.jetbrains.kotlin.cli.common.* import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.checkKotlinPackageUsage
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.OUTPUT import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.OUTPUT
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.WARNING import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.WARNING
@@ -51,12 +53,10 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.script.tryConstructClassFromStringArgs import org.jetbrains.kotlin.script.tryConstructClassFromStringArgs
import org.jetbrains.kotlin.util.PerformanceCounter
import org.jetbrains.kotlin.utils.newLinkedHashMapWithExpectedSize import org.jetbrains.kotlin.utils.newLinkedHashMapWithExpectedSize
import java.io.File import java.io.File
import java.lang.reflect.InvocationTargetException import java.lang.reflect.InvocationTargetException
import java.net.URLClassLoader import java.net.URLClassLoader
import java.util.concurrent.TimeUnit
object KotlinToJVMBytecodeCompiler { object KotlinToJVMBytecodeCompiler {
@@ -159,12 +159,11 @@ object KotlinToJVMBytecodeCompiler {
it.compile(File(singleModule.getOutputDirectory())) it.compile(File(singleModule.getOutputDirectory()))
} }
} else { } else {
projectConfiguration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).let { projectConfiguration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report(
it.report( WARNING,
WARNING, "A chunk contains multiple modules (${chunk.joinToString { it.getModuleName() }}). " +
"A chunk contains multiple modules (${chunk.joinToString { it.getModuleName() }}). -Xuse-javac option couldn't be used to compile java files" "-Xuse-javac option couldn't be used to compile java files"
) )
}
JavacWrapper.getInstance(environment.project).close() JavacWrapper.getInstance(environment.project).close()
} }
} }
@@ -257,7 +256,7 @@ object KotlinToJVMBytecodeCompiler {
try { try {
try { try {
tryConstructClassFromStringArgs(scriptClass, scriptArgs) tryConstructClassFromStringArgs(scriptClass, scriptArgs)
?: throw RuntimeException("unable to find appropriate constructor for class ${scriptClass.name} accepting arguments $scriptArgs\n") ?: throw RuntimeException("unable to find appropriate constructor for class ${scriptClass.name} accepting arguments $scriptArgs\n")
} finally { } finally {
// NB: these lines are required (see KT-9546) but aren't covered by tests // NB: these lines are required (see KT-9546) but aren't covered by tests
System.out.flush() System.out.flush()
@@ -335,11 +334,11 @@ object KotlinToJVMBytecodeCompiler {
val script = environment.getSourceFiles()[0].script ?: error("Script must be parsed") val script = environment.getSourceFiles()[0].script ?: error("Script must be parsed")
return classLoader.loadClass(script.fqName.asString()) return classLoader.loadClass(script.fqName.asString())
} catch (e: Exception) { } catch (e: Exception) {
throw RuntimeException("Failed to evaluate script: " + e, e) throw RuntimeException("Failed to evaluate script: $e", e)
} }
} }
fun analyzeAndGenerate(environment: KotlinCoreEnvironment): GenerationState? { private fun analyzeAndGenerate(environment: KotlinCoreEnvironment): GenerationState? {
val result = repeatAnalysisIfNeeded(analyze(environment, null), environment, null) ?: return null val result = repeatAnalysisIfNeeded(analyze(environment, null), environment, null) ?: return null
if (!result.shouldGenerateCode) return null if (!result.shouldGenerateCode) return null
@@ -37,7 +37,6 @@ import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.WARNING
import org.jetbrains.kotlin.cli.common.messages.MessageCollector import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.messages.OutputMessageUtil import org.jetbrains.kotlin.cli.common.messages.OutputMessageUtil
import org.jetbrains.kotlin.cli.common.output.outputUtils.writeAll import org.jetbrains.kotlin.cli.common.output.outputUtils.writeAll
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
import org.jetbrains.kotlin.cli.jvm.config.* import org.jetbrains.kotlin.cli.jvm.config.*
import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
@@ -53,12 +52,10 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.script.tryConstructClassFromStringArgs import org.jetbrains.kotlin.script.tryConstructClassFromStringArgs
import org.jetbrains.kotlin.util.PerformanceCounter
import org.jetbrains.kotlin.utils.newLinkedHashMapWithExpectedSize import org.jetbrains.kotlin.utils.newLinkedHashMapWithExpectedSize
import java.io.File import java.io.File
import java.lang.reflect.InvocationTargetException import java.lang.reflect.InvocationTargetException
import java.net.URLClassLoader import java.net.URLClassLoader
import java.util.concurrent.TimeUnit
object KotlinToJVMBytecodeCompiler { object KotlinToJVMBytecodeCompiler {
@@ -161,12 +158,11 @@ object KotlinToJVMBytecodeCompiler {
it.compile(File(singleModule.getOutputDirectory())) it.compile(File(singleModule.getOutputDirectory()))
} }
} else { } else {
projectConfiguration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).let { projectConfiguration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report(
it.report( WARNING,
WARNING, "A chunk contains multiple modules (${chunk.joinToString { it.getModuleName() }}). " +
"A chunk contains multiple modules (${chunk.joinToString { it.getModuleName() }}). -Xuse-javac option couldn't be used to compile java files" "-Xuse-javac option couldn't be used to compile java files"
) )
}
JavacWrapper.getInstance(environment.project).close() JavacWrapper.getInstance(environment.project).close()
} }
} }
@@ -192,8 +188,8 @@ object KotlinToJVMBytecodeCompiler {
module.getJavaSourceRoots().any { (path, packagePrefix) -> module.getJavaSourceRoots().any { (path, packagePrefix) ->
val file = File(path) val file = File(path)
packagePrefix == null && packagePrefix == null &&
(file.name == PsiJavaModule.MODULE_INFO_FILE || (file.name == PsiJavaModule.MODULE_INFO_FILE ||
(file.isDirectory && file.listFiles().any { it.name == PsiJavaModule.MODULE_INFO_FILE })) (file.isDirectory && file.listFiles().any { it.name == PsiJavaModule.MODULE_INFO_FILE }))
} }
}*/ }*/
@@ -259,7 +255,7 @@ object KotlinToJVMBytecodeCompiler {
try { try {
try { try {
tryConstructClassFromStringArgs(scriptClass, scriptArgs) tryConstructClassFromStringArgs(scriptClass, scriptArgs)
?: throw RuntimeException("unable to find appropriate constructor for class ${scriptClass.name} accepting arguments $scriptArgs\n") ?: throw RuntimeException("unable to find appropriate constructor for class ${scriptClass.name} accepting arguments $scriptArgs\n")
} finally { } finally {
// NB: these lines are required (see KT-9546) but aren't covered by tests // NB: these lines are required (see KT-9546) but aren't covered by tests
System.out.flush() System.out.flush()
@@ -337,11 +333,11 @@ object KotlinToJVMBytecodeCompiler {
val script = environment.getSourceFiles()[0].script ?: error("Script must be parsed") val script = environment.getSourceFiles()[0].script ?: error("Script must be parsed")
return classLoader.loadClass(script.fqName.asString()) return classLoader.loadClass(script.fqName.asString())
} catch (e: Exception) { } catch (e: Exception) {
throw RuntimeException("Failed to evaluate script: " + e, e) throw RuntimeException("Failed to evaluate script: $e", e)
} }
} }
fun analyzeAndGenerate(environment: KotlinCoreEnvironment): GenerationState? { private fun analyzeAndGenerate(environment: KotlinCoreEnvironment): GenerationState? {
val result = repeatAnalysisIfNeeded(analyze(environment, null), environment, null) ?: return null val result = repeatAnalysisIfNeeded(analyze(environment, null), environment, null) ?: return null
if (!result.shouldGenerateCode) return null if (!result.shouldGenerateCode) return null
@@ -37,7 +37,6 @@ import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.WARNING
import org.jetbrains.kotlin.cli.common.messages.MessageCollector import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.messages.OutputMessageUtil import org.jetbrains.kotlin.cli.common.messages.OutputMessageUtil
import org.jetbrains.kotlin.cli.common.output.outputUtils.writeAll import org.jetbrains.kotlin.cli.common.output.outputUtils.writeAll
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
import org.jetbrains.kotlin.cli.jvm.config.* import org.jetbrains.kotlin.cli.jvm.config.*
import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
@@ -53,12 +52,10 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.script.tryConstructClassFromStringArgs import org.jetbrains.kotlin.script.tryConstructClassFromStringArgs
import org.jetbrains.kotlin.util.PerformanceCounter
import org.jetbrains.kotlin.utils.newLinkedHashMapWithExpectedSize import org.jetbrains.kotlin.utils.newLinkedHashMapWithExpectedSize
import java.io.File import java.io.File
import java.lang.reflect.InvocationTargetException import java.lang.reflect.InvocationTargetException
import java.net.URLClassLoader import java.net.URLClassLoader
import java.util.concurrent.TimeUnit
object KotlinToJVMBytecodeCompiler { object KotlinToJVMBytecodeCompiler {
@@ -161,12 +158,11 @@ object KotlinToJVMBytecodeCompiler {
it.compile(File(singleModule.getOutputDirectory())) it.compile(File(singleModule.getOutputDirectory()))
} }
} else { } else {
projectConfiguration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).let { projectConfiguration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report(
it.report( WARNING,
WARNING, "A chunk contains multiple modules (${chunk.joinToString { it.getModuleName() }}). " +
"A chunk contains multiple modules (${chunk.joinToString { it.getModuleName() }}). -Xuse-javac option couldn't be used to compile java files" "-Xuse-javac option couldn't be used to compile java files"
) )
}
JavacWrapper.getInstance(environment.project).close() JavacWrapper.getInstance(environment.project).close()
} }
} }
@@ -192,8 +188,8 @@ object KotlinToJVMBytecodeCompiler {
module.getJavaSourceRoots().any { (path, packagePrefix) -> module.getJavaSourceRoots().any { (path, packagePrefix) ->
val file = File(path) val file = File(path)
packagePrefix == null && packagePrefix == null &&
(file.name == PsiJavaModule.MODULE_INFO_FILE || (file.name == PsiJavaModule.MODULE_INFO_FILE ||
(file.isDirectory && file.listFiles().any { it.name == PsiJavaModule.MODULE_INFO_FILE })) (file.isDirectory && file.listFiles().any { it.name == PsiJavaModule.MODULE_INFO_FILE }))
} }
}*/ }*/
@@ -259,7 +255,7 @@ object KotlinToJVMBytecodeCompiler {
try { try {
try { try {
tryConstructClassFromStringArgs(scriptClass, scriptArgs) tryConstructClassFromStringArgs(scriptClass, scriptArgs)
?: throw RuntimeException("unable to find appropriate constructor for class ${scriptClass.name} accepting arguments $scriptArgs\n") ?: throw RuntimeException("unable to find appropriate constructor for class ${scriptClass.name} accepting arguments $scriptArgs\n")
} finally { } finally {
// NB: these lines are required (see KT-9546) but aren't covered by tests // NB: these lines are required (see KT-9546) but aren't covered by tests
System.out.flush() System.out.flush()
@@ -337,11 +333,11 @@ object KotlinToJVMBytecodeCompiler {
val script = environment.getSourceFiles()[0].script ?: error("Script must be parsed") val script = environment.getSourceFiles()[0].script ?: error("Script must be parsed")
return classLoader.loadClass(script.fqName.asString()) return classLoader.loadClass(script.fqName.asString())
} catch (e: Exception) { } catch (e: Exception) {
throw RuntimeException("Failed to evaluate script: " + e, e) throw RuntimeException("Failed to evaluate script: $e", e)
} }
} }
fun analyzeAndGenerate(environment: KotlinCoreEnvironment): GenerationState? { private fun analyzeAndGenerate(environment: KotlinCoreEnvironment): GenerationState? {
val result = repeatAnalysisIfNeeded(analyze(environment, null), environment, null) ?: return null val result = repeatAnalysisIfNeeded(analyze(environment, null), environment, null) ?: return null
if (!result.shouldGenerateCode) return null if (!result.shouldGenerateCode) return null
@@ -30,7 +30,12 @@ class MockExternalAnnotationsManager : ExternalAnnotationsManager() {
override fun findExternalAnnotation(listOwner: PsiModifierListOwner, annotationFQN: String): PsiAnnotation? = null override fun findExternalAnnotation(listOwner: PsiModifierListOwner, annotationFQN: String): PsiAnnotation? = null
override fun findExternalAnnotations(listOwner: PsiModifierListOwner): Array<out PsiAnnotation>? = null override fun findExternalAnnotations(listOwner: PsiModifierListOwner): Array<out PsiAnnotation>? = null
override fun annotateExternally(listOwner: PsiModifierListOwner, annotationFQName: String, fromFile: PsiFile, value: Array<out PsiNameValuePair>?) { override fun annotateExternally(
listOwner: PsiModifierListOwner,
annotationFQName: String,
fromFile: PsiFile,
value: Array<out PsiNameValuePair>?
) {
throw UnsupportedOperationException("not implemented") throw UnsupportedOperationException("not implemented")
} }
@@ -38,7 +43,11 @@ class MockExternalAnnotationsManager : ExternalAnnotationsManager() {
throw UnsupportedOperationException("not implemented") throw UnsupportedOperationException("not implemented")
} }
override fun editExternalAnnotation(listOwner: PsiModifierListOwner, annotationFQN: String, value: Array<out PsiNameValuePair>?): Boolean { override fun editExternalAnnotation(
listOwner: PsiModifierListOwner,
annotationFQN: String,
value: Array<out PsiNameValuePair>?
): Boolean {
throw UnsupportedOperationException("not implemented") throw UnsupportedOperationException("not implemented")
} }
@@ -1,31 +0,0 @@
/*
* 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.cli.jvm.compiler;
public class ModuleExecutionException extends RuntimeException {
public ModuleExecutionException(String message) {
super(message);
}
public ModuleExecutionException(Throwable cause) {
super(cause);
}
public ModuleExecutionException(String message, Throwable cause) {
super(message, cause);
}
}
@@ -50,7 +50,6 @@ import org.jetbrains.kotlin.load.java.lazy.ModuleClassResolver
import org.jetbrains.kotlin.load.java.structure.JavaClass import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.java.structure.impl.VirtualFileBoundJavaClass import org.jetbrains.kotlin.load.java.structure.impl.VirtualFileBoundJavaClass
import org.jetbrains.kotlin.load.kotlin.DeserializationComponentsForJava import org.jetbrains.kotlin.load.kotlin.DeserializationComponentsForJava
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
import org.jetbrains.kotlin.load.kotlin.incremental.IncrementalPackageFragmentProvider import org.jetbrains.kotlin.load.kotlin.incremental.IncrementalPackageFragmentProvider
import org.jetbrains.kotlin.load.kotlin.incremental.IncrementalPackagePartProvider import org.jetbrains.kotlin.load.kotlin.incremental.IncrementalPackagePartProvider
@@ -66,7 +65,6 @@ import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtens
import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.StorageManager
import java.util.* import java.util.*
import kotlin.reflect.KFunction1 import kotlin.reflect.KFunction1
@@ -75,16 +73,16 @@ object TopDownAnalyzerFacadeForJVM {
@JvmStatic @JvmStatic
@JvmOverloads @JvmOverloads
fun analyzeFilesWithJavaIntegration( fun analyzeFilesWithJavaIntegration(
project: Project, project: Project,
files: Collection<KtFile>, files: Collection<KtFile>,
trace: BindingTrace, trace: BindingTrace,
configuration: CompilerConfiguration, configuration: CompilerConfiguration,
packagePartProvider: (GlobalSearchScope) -> PackagePartProvider, packagePartProvider: (GlobalSearchScope) -> PackagePartProvider,
declarationProviderFactory: (StorageManager, Collection<KtFile>) -> DeclarationProviderFactory = ::FileBasedDeclarationProviderFactory, declarationProviderFactory: (StorageManager, Collection<KtFile>) -> DeclarationProviderFactory = ::FileBasedDeclarationProviderFactory,
sourceModuleSearchScope: GlobalSearchScope = newModuleSearchScope(project, files) sourceModuleSearchScope: GlobalSearchScope = newModuleSearchScope(project, files)
): AnalysisResult { ): AnalysisResult {
val container = createContainer( val container = createContainer(
project, files, trace, configuration, packagePartProvider, declarationProviderFactory, sourceModuleSearchScope project, files, trace, configuration, packagePartProvider, declarationProviderFactory, sourceModuleSearchScope
) )
val module = container.get<ModuleDescriptor>() val module = container.get<ModuleDescriptor>()
@@ -118,13 +116,13 @@ object TopDownAnalyzerFacadeForJVM {
} }
fun createContainer( fun createContainer(
project: Project, project: Project,
files: Collection<KtFile>, files: Collection<KtFile>,
trace: BindingTrace, trace: BindingTrace,
configuration: CompilerConfiguration, configuration: CompilerConfiguration,
packagePartProvider: (GlobalSearchScope) -> PackagePartProvider, packagePartProvider: (GlobalSearchScope) -> PackagePartProvider,
declarationProviderFactory: (StorageManager, Collection<KtFile>) -> DeclarationProviderFactory, declarationProviderFactory: (StorageManager, Collection<KtFile>) -> DeclarationProviderFactory,
sourceModuleSearchScope: GlobalSearchScope = newModuleSearchScope(project, files) sourceModuleSearchScope: GlobalSearchScope = newModuleSearchScope(project, files)
): ComponentProvider { ): ComponentProvider {
val createBuiltInsFromModule = configuration.getBoolean(JVMConfigurationKeys.CREATE_BUILT_INS_FROM_MODULE_DEPENDENCIES) val createBuiltInsFromModule = configuration.getBoolean(JVMConfigurationKeys.CREATE_BUILT_INS_FROM_MODULE_DEPENDENCIES)
val moduleContext = createModuleContext(project, configuration, createBuiltInsFromModule) val moduleContext = createModuleContext(project, configuration, createBuiltInsFromModule)
@@ -146,12 +144,11 @@ object TopDownAnalyzerFacadeForJVM {
val languageVersionSettings = configuration.languageVersionSettings val languageVersionSettings = configuration.languageVersionSettings
val optionalBuiltInsModule = val optionalBuiltInsModule =
if (configuration.getBoolean(JVMConfigurationKeys.ADD_BUILT_INS_FROM_COMPILER_TO_DEPENDENCIES)) { if (configuration.getBoolean(JVMConfigurationKeys.ADD_BUILT_INS_FROM_COMPILER_TO_DEPENDENCIES)) {
if (createBuiltInsFromModule) if (createBuiltInsFromModule)
JvmBuiltIns(storageManager).apply { initialize(module, languageVersionSettings) }.builtInsModule JvmBuiltIns(storageManager).apply { initialize(module, languageVersionSettings) }.builtInsModule
else module.builtIns.builtInsModule else module.builtIns.builtInsModule
} } else null
else null
fun StorageComponentContainer.useJavac() { fun StorageComponentContainer.useJavac() {
useImpl<JavacBasedClassFinder>() useImpl<JavacBasedClassFinder>()
@@ -159,34 +156,38 @@ object TopDownAnalyzerFacadeForJVM {
useImpl<JavacBasedSourceElementFactory>() useImpl<JavacBasedSourceElementFactory>()
} }
@Suppress("USELESS_CAST")
val configureJavaClassFinder = val configureJavaClassFinder =
if (configuration.getBoolean(JVMConfigurationKeys.USE_JAVAC)) StorageComponentContainer::useJavac if (configuration.getBoolean(JVMConfigurationKeys.USE_JAVAC)) StorageComponentContainer::useJavac
else null as KFunction1<StorageComponentContainer, Unit>? else null as KFunction1<StorageComponentContainer, Unit>?
val dependencyModule = if (separateModules) { val dependencyModule = if (separateModules) {
val dependenciesContext = ContextForNewModule( val dependenciesContext = ContextForNewModule(
moduleContext, Name.special("<dependencies of ${configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME)}>"), moduleContext, Name.special("<dependencies of ${configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME)}>"),
module.builtIns, null module.builtIns, null
) )
// Scope for the dependency module contains everything except files present in the scope for the source module // Scope for the dependency module contains everything except files present in the scope for the source module
val dependencyScope = GlobalSearchScope.notScope(sourceScope) val dependencyScope = GlobalSearchScope.notScope(sourceScope)
val dependenciesContainer = createContainerForTopDownAnalyzerForJvm( val dependenciesContainer = createContainerForTopDownAnalyzerForJvm(
dependenciesContext, trace, DeclarationProviderFactory.EMPTY, dependencyScope, lookupTracker, expectActualTracker, dependenciesContext, trace, DeclarationProviderFactory.EMPTY, dependencyScope, lookupTracker, expectActualTracker,
packagePartProvider(dependencyScope), moduleClassResolver, jvmTarget, languageVersionSettings, configureJavaClassFinder packagePartProvider(dependencyScope), moduleClassResolver, jvmTarget, languageVersionSettings, configureJavaClassFinder
) )
moduleClassResolver.compiledCodeResolver = dependenciesContainer.get<JavaDescriptorResolver>() moduleClassResolver.compiledCodeResolver = dependenciesContainer.get()
dependenciesContext.setDependencies(listOfNotNull(dependenciesContext.module, optionalBuiltInsModule)) dependenciesContext.setDependencies(listOfNotNull(dependenciesContext.module, optionalBuiltInsModule))
dependenciesContext.initializeModuleContents(CompositePackageFragmentProvider(listOf( dependenciesContext.initializeModuleContents(
moduleClassResolver.compiledCodeResolver.packageFragmentProvider, CompositePackageFragmentProvider(
dependenciesContainer.get<JvmBuiltInsPackageFragmentProvider>() listOf(
))) moduleClassResolver.compiledCodeResolver.packageFragmentProvider,
dependenciesContainer.get<JvmBuiltInsPackageFragmentProvider>()
)
)
)
dependenciesContext.module dependenciesContext.module
} } else null
else null
val partProvider = packagePartProvider(sourceScope).let { fragment -> val partProvider = packagePartProvider(sourceScope).let { fragment ->
if (targetIds == null || incrementalComponents == null) fragment if (targetIds == null || incrementalComponents == null) fragment
@@ -198,23 +199,22 @@ object TopDownAnalyzerFacadeForJVM {
// to be stored in CliLightClassGenerationSupport, and it better be the source one (otherwise light classes would not be found) // to be stored in CliLightClassGenerationSupport, and it better be the source one (otherwise light classes would not be found)
// TODO: get rid of duplicate invocation of CodeAnalyzerInitializer#initialize, or refactor CliLightClassGenerationSupport // TODO: get rid of duplicate invocation of CodeAnalyzerInitializer#initialize, or refactor CliLightClassGenerationSupport
val container = createContainerForTopDownAnalyzerForJvm( val container = createContainerForTopDownAnalyzerForJvm(
moduleContext, trace, declarationProviderFactory(storageManager, files), sourceScope, lookupTracker, expectActualTracker, moduleContext, trace, declarationProviderFactory(storageManager, files), sourceScope, lookupTracker, expectActualTracker,
partProvider, moduleClassResolver, jvmTarget, languageVersionSettings, configureJavaClassFinder, partProvider, moduleClassResolver, jvmTarget, languageVersionSettings, configureJavaClassFinder,
javaClassTracker = configuration[JVMConfigurationKeys.JAVA_CLASSES_TRACKER] javaClassTracker = configuration[JVMConfigurationKeys.JAVA_CLASSES_TRACKER]
).apply { ).apply {
initJvmBuiltInsForTopDownAnalysis() initJvmBuiltInsForTopDownAnalysis()
(partProvider as? IncrementalPackagePartProvider)?.deserializationConfiguration = get<DeserializationConfiguration>() (partProvider as? IncrementalPackagePartProvider)?.deserializationConfiguration = get()
} }
moduleClassResolver.sourceCodeResolver = container.get<JavaDescriptorResolver>() moduleClassResolver.sourceCodeResolver = container.get()
val additionalProviders = ArrayList<PackageFragmentProvider>() val additionalProviders = ArrayList<PackageFragmentProvider>()
if (incrementalComponents != null) { if (incrementalComponents != null) {
targetIds?.mapTo(additionalProviders) { targetId -> targetIds?.mapTo(additionalProviders) { targetId ->
IncrementalPackageFragmentProvider( IncrementalPackageFragmentProvider(
files, module, storageManager, container.get<DeserializationComponentsForJava>().components, files, module, storageManager, container.get<DeserializationComponentsForJava>().components,
incrementalComponents.getIncrementalCache(targetId), targetId, incrementalComponents.getIncrementalCache(targetId), targetId, container.get()
container.get<KotlinClassFinder>()
) )
} }
} }
@@ -228,13 +228,14 @@ object TopDownAnalyzerFacadeForJVM {
// TODO: remove dependencyModule from friends // TODO: remove dependencyModule from friends
module.setDependencies( module.setDependencies(
listOfNotNull(module, dependencyModule, optionalBuiltInsModule), listOfNotNull(module, dependencyModule, optionalBuiltInsModule),
if (dependencyModule != null) setOf(dependencyModule) else emptySet() if (dependencyModule != null) setOf(dependencyModule) else emptySet()
)
module.initialize(
CompositePackageFragmentProvider(
listOf(container.get<KotlinCodeAnalyzer>().packageFragmentProvider) + additionalProviders
)
) )
module.initialize(CompositePackageFragmentProvider(
listOf(container.get<KotlinCodeAnalyzer>().packageFragmentProvider) +
additionalProviders
))
return container return container
} }
@@ -251,7 +252,7 @@ object TopDownAnalyzerFacadeForJVM {
// 'isDirectory' check is needed because otherwise directories such as 'frontend.java' would be recognized // 'isDirectory' check is needed because otherwise directories such as 'frontend.java' would be recognized
// as Java source files, which makes no sense // as Java source files, which makes no sense
override fun contains(file: VirtualFile) = override fun contains(file: VirtualFile) =
file.fileType === JavaFileType.INSTANCE && !file.isDirectory file.fileType === JavaFileType.INSTANCE && !file.isDirectory
override fun toString() = "All Java sources in the project" override fun toString() = "All Java sources in the project"
} }
@@ -270,20 +271,20 @@ object TopDownAnalyzerFacadeForJVM {
} }
fun createContextWithSealedModule(project: Project, configuration: CompilerConfiguration): MutableModuleContext = fun createContextWithSealedModule(project: Project, configuration: CompilerConfiguration): MutableModuleContext =
createModuleContext(project, configuration, false).apply { createModuleContext(project, configuration, false).apply {
setDependencies(module, module.builtIns.builtInsModule) setDependencies(module, module.builtIns.builtInsModule)
(module.builtIns as JvmBuiltIns).initialize(module, configuration.languageVersionSettings) (module.builtIns as JvmBuiltIns).initialize(module, configuration.languageVersionSettings)
} }
private fun createModuleContext( private fun createModuleContext(
project: Project, project: Project,
configuration: CompilerConfiguration, configuration: CompilerConfiguration,
createBuiltInsFromModule: Boolean createBuiltInsFromModule: Boolean
): MutableModuleContext { ): MutableModuleContext {
val projectContext = ProjectContext(project) val projectContext = ProjectContext(project)
val builtIns = JvmBuiltIns(projectContext.storageManager, !createBuiltInsFromModule) val builtIns = JvmBuiltIns(projectContext.storageManager, !createBuiltInsFromModule)
return ContextForNewModule( return ContextForNewModule(
projectContext, Name.special("<${configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME)}>"), builtIns, null projectContext, Name.special("<${configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME)}>"), builtIns, null
).apply { ).apply {
if (createBuiltInsFromModule) { if (createBuiltInsFromModule) {
builtIns.builtInsModule = module builtIns.builtInsModule = module
@@ -58,10 +58,10 @@ fun CompilerConfiguration.addJavaSourceRoots(files: List<File>, packagePrefix: S
} }
val CompilerConfiguration.javaSourceRoots: Set<String> val CompilerConfiguration.javaSourceRoots: Set<String>
get() = getList(JVMConfigurationKeys.CONTENT_ROOTS).mapNotNullTo(linkedSetOf<String>()) { root -> get() = getList(JVMConfigurationKeys.CONTENT_ROOTS).mapNotNullTo(linkedSetOf()) { root ->
when (root) { when (root) {
is KotlinSourceRoot -> root.path is KotlinSourceRoot -> root.path
is JavaSourceRoot -> root.file.path is JavaSourceRoot -> root.file.path
else -> null else -> null
} }
} }
@@ -34,27 +34,27 @@ class JvmDependenciesDynamicCompoundIndex : JvmDependenciesIndex {
} }
fun addNewIndexForRoots(roots: Iterable<JavaRoot>): JvmDependenciesIndex? = fun addNewIndexForRoots(roots: Iterable<JavaRoot>): JvmDependenciesIndex? =
lock.read { lock.read {
val alreadyIndexed = indexedRoots.toHashSet() val alreadyIndexed = indexedRoots.toHashSet()
val newRoots = roots.filter { root -> root !in alreadyIndexed } val newRoots = roots.filter { root -> root !in alreadyIndexed }
if (newRoots.isEmpty()) null if (newRoots.isEmpty()) null
else JvmDependenciesIndexImpl(newRoots).also(this::addIndex) else JvmDependenciesIndexImpl(newRoots).also(this::addIndex)
} }
override val indexedRoots: Sequence<JavaRoot> get() = indices.asSequence().flatMap { it.indexedRoots } override val indexedRoots: Sequence<JavaRoot> get() = indices.asSequence().flatMap { it.indexedRoots }
override fun <T : Any> findClass( override fun <T : Any> findClass(
classId: ClassId, classId: ClassId,
acceptedRootTypes: Set<JavaRoot.RootType>, acceptedRootTypes: Set<JavaRoot.RootType>,
findClassGivenDirectory: (VirtualFile, JavaRoot.RootType) -> T? findClassGivenDirectory: (VirtualFile, JavaRoot.RootType) -> T?
): T? = lock.read { ): T? = lock.read {
indices.asSequence().mapNotNull { it.findClass(classId, acceptedRootTypes, findClassGivenDirectory) }.firstOrNull() indices.asSequence().mapNotNull { it.findClass(classId, acceptedRootTypes, findClassGivenDirectory) }.firstOrNull()
} }
override fun traverseDirectoriesInPackage( override fun traverseDirectoriesInPackage(
packageFqName: FqName, packageFqName: FqName,
acceptedRootTypes: Set<JavaRoot.RootType>, acceptedRootTypes: Set<JavaRoot.RootType>,
continueSearch: (VirtualFile, JavaRoot.RootType) -> Boolean continueSearch: (VirtualFile, JavaRoot.RootType) -> Boolean
) = lock.read { ) = lock.read {
indices.forEach { it.traverseDirectoriesInPackage(packageFqName, acceptedRootTypes, continueSearch) } indices.forEach { it.traverseDirectoriesInPackage(packageFqName, acceptedRootTypes, continueSearch) }
} }
@@ -25,15 +25,15 @@ interface JvmDependenciesIndex {
val indexedRoots: Sequence<JavaRoot> val indexedRoots: Sequence<JavaRoot>
fun <T : Any> findClass( fun <T : Any> findClass(
classId: ClassId, classId: ClassId,
acceptedRootTypes: Set<JavaRoot.RootType> = JavaRoot.SourceAndBinary, acceptedRootTypes: Set<JavaRoot.RootType> = JavaRoot.SourceAndBinary,
findClassGivenDirectory: (VirtualFile, JavaRoot.RootType) -> T? findClassGivenDirectory: (VirtualFile, JavaRoot.RootType) -> T?
): T? ): T?
fun traverseDirectoriesInPackage( fun traverseDirectoriesInPackage(
packageFqName: FqName, packageFqName: FqName,
acceptedRootTypes: Set<JavaRoot.RootType> = JavaRoot.SourceAndBinary, acceptedRootTypes: Set<JavaRoot.RootType> = JavaRoot.SourceAndBinary,
continueSearch: (VirtualFile, JavaRoot.RootType) -> Boolean continueSearch: (VirtualFile, JavaRoot.RootType) -> Boolean
) )
} }
@@ -29,7 +29,7 @@ import java.util.*
// speeds up finding files/classes in classpath/java source roots // speeds up finding files/classes in classpath/java source roots
// NOT THREADSAFE, needs to be adapted/removed if we want compiler to be multithreaded // NOT THREADSAFE, needs to be adapted/removed if we want compiler to be multithreaded
// the main idea of this class is for each package to store roots which contains it to avoid excessive file system traversal // the main idea of this class is for each package to store roots which contains it to avoid excessive file system traversal
class JvmDependenciesIndexImpl(_roots: List<JavaRoot>): JvmDependenciesIndex { class JvmDependenciesIndexImpl(_roots: List<JavaRoot>) : JvmDependenciesIndex {
//these fields are computed based on _roots passed to constructor which are filled in later //these fields are computed based on _roots passed to constructor which are filled in later
private val roots: List<JavaRoot> by lazy { _roots.toList() } private val roots: List<JavaRoot> by lazy { _roots.toList() }
@@ -69,9 +69,9 @@ class JvmDependenciesIndexImpl(_roots: List<JavaRoot>): JvmDependenciesIndex {
} }
override fun traverseDirectoriesInPackage( override fun traverseDirectoriesInPackage(
packageFqName: FqName, packageFqName: FqName,
acceptedRootTypes: Set<JavaRoot.RootType>, acceptedRootTypes: Set<JavaRoot.RootType>,
continueSearch: (VirtualFile, JavaRoot.RootType) -> Boolean continueSearch: (VirtualFile, JavaRoot.RootType) -> Boolean
) { ) {
search(TraverseRequest(packageFqName, acceptedRootTypes)) { dir, rootType -> search(TraverseRequest(packageFqName, acceptedRootTypes)) { dir, rootType ->
if (continueSearch(dir, rootType)) null else Unit if (continueSearch(dir, rootType)) null else Unit
@@ -80,9 +80,9 @@ class JvmDependenciesIndexImpl(_roots: List<JavaRoot>): JvmDependenciesIndex {
// findClassGivenDirectory MUST check whether the class with this classId exists in given package // findClassGivenDirectory MUST check whether the class with this classId exists in given package
override fun <T : Any> findClass( override fun <T : Any> findClass(
classId: ClassId, classId: ClassId,
acceptedRootTypes: Set<JavaRoot.RootType>, acceptedRootTypes: Set<JavaRoot.RootType>,
findClassGivenDirectory: (VirtualFile, JavaRoot.RootType) -> T? findClassGivenDirectory: (VirtualFile, JavaRoot.RootType) -> T?
): T? { ): T? {
// make a decision based on information saved from last class search // make a decision based on information saved from last class search
if (lastClassSearch?.first?.classId != classId) { if (lastClassSearch?.first?.classId != classId) {
@@ -95,16 +95,14 @@ class JvmDependenciesIndexImpl(_roots: List<JavaRoot>): JvmDependenciesIndex {
val limitedRootTypes = acceptedRootTypes - cachedRequest.acceptedRootTypes val limitedRootTypes = acceptedRootTypes - cachedRequest.acceptedRootTypes
if (limitedRootTypes.isEmpty()) { if (limitedRootTypes.isEmpty()) {
null null
} } else {
else {
search(FindClassRequest(classId, limitedRootTypes), findClassGivenDirectory) search(FindClassRequest(classId, limitedRootTypes), findClassGivenDirectory)
} }
} }
is SearchResult.Found -> { is SearchResult.Found -> {
if (cachedRequest.acceptedRootTypes == acceptedRootTypes) { if (cachedRequest.acceptedRootTypes == acceptedRootTypes) {
findClassGivenDirectory(cachedResult.packageDirectory, cachedResult.root.type) findClassGivenDirectory(cachedResult.packageDirectory, cachedResult.root.type)
} } else {
else {
search(FindClassRequest(classId, acceptedRootTypes), findClassGivenDirectory) search(FindClassRequest(classId, acceptedRootTypes), findClassGivenDirectory)
} }
} }
@@ -151,11 +149,11 @@ class JvmDependenciesIndexImpl(_roots: List<JavaRoot>): JvmDependenciesIndex {
// try to find a target directory corresponding to package represented by packagesPath in a given root represented by index // try to find a target directory corresponding to package represented by packagesPath in a given root represented by index
// possibly filling "Cache" objects with new information // possibly filling "Cache" objects with new information
private fun travelPath( private fun travelPath(
rootIndex: Int, rootIndex: Int,
packageFqName: FqName, packageFqName: FqName,
packagesPath: List<String>, packagesPath: List<String>,
fillCachesAfter: Int, fillCachesAfter: Int,
cachesPath: List<Cache> cachesPath: List<Cache>
): VirtualFile? { ): VirtualFile? {
if (rootIndex >= maxIndex) { if (rootIndex >= maxIndex) {
for (i in (fillCachesAfter + 1)..(cachesPath.size - 1)) { for (i in (fillCachesAfter + 1)..(cachesPath.size - 1)) {
@@ -184,8 +182,7 @@ class JvmDependenciesIndexImpl(_roots: List<JavaRoot>): JvmDependenciesIndex {
if (prefixPathSegments[pathIndex].identifier != subPackageName) { if (prefixPathSegments[pathIndex].identifier != subPackageName) {
return null return null
} }
} } else {
else {
currentFile = currentFile.findChildPackage(subPackageName, pathRoot.type) ?: return null currentFile = currentFile.findChildPackage(subPackageName, pathRoot.type) ?: return null
} }
@@ -235,8 +232,8 @@ class JvmDependenciesIndexImpl(_roots: List<JavaRoot>): JvmDependenciesIndex {
} }
private data class TraverseRequest( private data class TraverseRequest(
override val packageFqName: FqName, override val packageFqName: FqName,
override val acceptedRootTypes: Set<JavaRoot.RootType> override val acceptedRootTypes: Set<JavaRoot.RootType>
) : SearchRequest ) : SearchRequest
private interface SearchRequest { private interface SearchRequest {
@@ -35,12 +35,12 @@ class SingleJavaFileRootsIndex(private val roots: List<JavaRoot>) {
private val classIdsInRoots = ArrayList<List<ClassId>>(roots.size) private val classIdsInRoots = ArrayList<List<ClassId>>(roots.size)
fun findJavaSourceClass(classId: ClassId): VirtualFile? = fun findJavaSourceClass(classId: ClassId): VirtualFile? =
roots.indices roots.indices
.find { index -> classId in getClassIdsForRootAt(index) } .find { index -> classId in getClassIdsForRootAt(index) }
?.let { index -> roots[index].file } ?.let { index -> roots[index].file }
fun findJavaSourceClasses(packageFqName: FqName): List<ClassId> = fun findJavaSourceClasses(packageFqName: FqName): List<ClassId> =
roots.indices.flatMap(this::getClassIdsForRootAt).filter { root -> root.packageFqName == packageFqName } roots.indices.flatMap(this::getClassIdsForRootAt).filter { root -> root.packageFqName == packageFqName }
private fun getClassIdsForRootAt(index: Int): List<ClassId> { private fun getClassIdsForRootAt(index: Int): List<ClassId> {
for (i in classIdsInRoots.size..index) { for (i in classIdsInRoots.size..index) {
@@ -73,7 +73,7 @@ class SingleJavaFileRootsIndex(private val roots: List<JavaRoot>) {
private fun tokenText(): String = lexer.tokenText private fun tokenText(): String = lexer.tokenText
private fun atClass(): Boolean = private fun atClass(): Boolean =
braceBalance == 0 && lexer.tokenType in CLASS_KEYWORDS braceBalance == 0 && lexer.tokenType in CLASS_KEYWORDS
fun readClassIds(): List<ClassId> { fun readClassIds(): List<ClassId> {
var packageFqName = FqName.ROOT var packageFqName = FqName.ROOT
@@ -25,10 +25,10 @@ import java.io.PrintWriter
import java.io.Writer import java.io.Writer
class JavacLogger( class JavacLogger(
context: Context, context: Context,
errorWriter: PrintWriter, errorWriter: PrintWriter,
warningWriter: PrintWriter, warningWriter: PrintWriter,
infoWriter: PrintWriter infoWriter: PrintWriter
) : Log(context, errorWriter, warningWriter, infoWriter) { ) : Log(context, errorWriter, warningWriter, infoWriter) {
init { init {
context.put(Log.outKey, infoWriter) context.put(Log.outKey, infoWriter)
@@ -39,18 +39,20 @@ class JavacLogger(
companion object { companion object {
fun preRegister(context: Context, messageCollector: MessageCollector) { fun preRegister(context: Context, messageCollector: MessageCollector) {
context.put(Log.logKey, Context.Factory<Log> { context.put(Log.logKey, Context.Factory<Log> {
JavacLogger(it, JavacLogger(
PrintWriter(MessageCollectorAdapter(messageCollector, CompilerMessageSeverity.ERROR)), it,
PrintWriter(MessageCollectorAdapter(messageCollector, CompilerMessageSeverity.WARNING)), PrintWriter(MessageCollectorAdapter(messageCollector, CompilerMessageSeverity.ERROR)),
PrintWriter(MessageCollectorAdapter(messageCollector, CompilerMessageSeverity.INFO))) PrintWriter(MessageCollectorAdapter(messageCollector, CompilerMessageSeverity.WARNING)),
PrintWriter(MessageCollectorAdapter(messageCollector, CompilerMessageSeverity.INFO))
)
}) })
} }
} }
} }
private class MessageCollectorAdapter( private class MessageCollectorAdapter(
private val messageCollector: MessageCollector, private val messageCollector: MessageCollector,
private val severity: CompilerMessageSeverity private val severity: CompilerMessageSeverity
) : Writer() { ) : Writer() {
override fun write(buffer: CharArray, offset: Int, length: Int) { override fun write(buffer: CharArray, offset: Int, length: Int) {
if (length == 1 && buffer[0] == '\n') return if (length == 1 && buffer[0] == '\n') return
@@ -38,9 +38,10 @@ class JavacWrapperKotlinResolverImpl(private val lightClassGenerationSupport: Li
return supersCache[classOrObject]!! return supersCache[classOrObject]!!
} }
val classDescriptor = lightClassGenerationSupport.analyze(classOrObject).get(BindingContext.CLASS, classOrObject) ?: return emptyList() val classDescriptor =
lightClassGenerationSupport.analyze(classOrObject).get(BindingContext.CLASS, classOrObject) ?: return emptyList()
val classIds = classDescriptor.defaultType.constructor.supertypes val classIds = classDescriptor.defaultType.constructor.supertypes
.mapNotNull { (it.constructor.declarationDescriptor as? ClassDescriptor)?.classId } .mapNotNull { (it.constructor.declarationDescriptor as? ClassDescriptor)?.classId }
supersCache[classOrObject] = classIds supersCache[classOrObject] = classIds
return classIds return classIds
@@ -49,12 +50,12 @@ class JavacWrapperKotlinResolverImpl(private val lightClassGenerationSupport: Li
override fun findField(classOrObject: KtClassOrObject, name: String): JavaField? { override fun findField(classOrObject: KtClassOrObject, name: String): JavaField? {
val lightClass = classOrObject.toLightClass() ?: return null val lightClass = classOrObject.toLightClass() ?: return null
return lightClass.allFields.find { it.name == name}?.let(::MockKotlinField) return lightClass.allFields.find { it.name == name }?.let(::MockKotlinField)
} }
override fun findField(ktFile: KtFile?, name: String): JavaField? { override fun findField(ktFile: KtFile?, name: String): JavaField? {
val lightClass = ktFile?.findFacadeClass() ?: return null val lightClass = ktFile?.findFacadeClass() ?: return null
return lightClass.allFields.find { it.name == name}?.let(::MockKotlinField) return lightClass.allFields.find { it.name == name }?.let(::MockKotlinField)
} }
} }
@@ -29,25 +29,23 @@ import org.jetbrains.kotlin.psi.KtFile
import java.io.File import java.io.File
object JavacWrapperRegistrar { object JavacWrapperRegistrar {
private const val JAVAC_CONTEXT_CLASS = "com.sun.tools.javac.util.Context" private const val JAVAC_CONTEXT_CLASS = "com.sun.tools.javac.util.Context"
fun registerJavac( fun registerJavac(
project: MockProject, project: MockProject,
configuration: CompilerConfiguration, configuration: CompilerConfiguration,
javaFiles: List<File>, javaFiles: List<File>,
kotlinFiles: List<KtFile>, kotlinFiles: List<KtFile>,
arguments: Array<String>?, arguments: Array<String>?,
bootClasspath: List<File>?, bootClasspath: List<File>?,
sourcePath: List<File>?, sourcePath: List<File>?,
lightClassGenerationSupport: LightClassGenerationSupport lightClassGenerationSupport: LightClassGenerationSupport
): Boolean { ): Boolean {
val messageCollector = configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) val messageCollector = configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
try { try {
Class.forName(JAVAC_CONTEXT_CLASS) Class.forName(JAVAC_CONTEXT_CLASS)
} } catch (e: ClassNotFoundException) {
catch (e: ClassNotFoundException) {
messageCollector.report(ERROR, "'$JAVAC_CONTEXT_CLASS' class can't be found ('tools.jar' is not found)") messageCollector.report(ERROR, "'$JAVAC_CONTEXT_CLASS' class can't be found ('tools.jar' is not found)")
return false return false
} }
@@ -60,8 +58,10 @@ object JavacWrapperRegistrar {
val compileJava = configuration.getBoolean(JVMConfigurationKeys.COMPILE_JAVA) val compileJava = configuration.getBoolean(JVMConfigurationKeys.COMPILE_JAVA)
val kotlinSupertypesResolver = JavacWrapperKotlinResolverImpl(lightClassGenerationSupport) val kotlinSupertypesResolver = JavacWrapperKotlinResolverImpl(lightClassGenerationSupport)
val javacWrapper = JavacWrapper(javaFiles, kotlinFiles, arguments, jvmClasspathRoots, bootClasspath, sourcePath, val javacWrapper = JavacWrapper(
kotlinSupertypesResolver, compileJava, outputDirectory, context) javaFiles, kotlinFiles, arguments, jvmClasspathRoots, bootClasspath, sourcePath,
kotlinSupertypesResolver, compileJava, outputDirectory, context
)
project.registerService(JavacWrapper::class.java, javacWrapper) project.registerService(JavacWrapper::class.java, javacWrapper)
@@ -37,7 +37,7 @@ class CliJavaModuleFinder(jrtFileSystemRoot: VirtualFile?) : JavaModuleFinder {
get() = modulesRoot?.children.orEmpty().asSequence().mapNotNull(this::findSystemModule) get() = modulesRoot?.children.orEmpty().asSequence().mapNotNull(this::findSystemModule)
override fun findModule(name: String): JavaModule? = override fun findModule(name: String): JavaModule? =
modulesRoot?.findChild(name)?.let(this::findSystemModule) ?: userModules[name] modulesRoot?.findChild(name)?.let(this::findSystemModule) ?: userModules[name]
private fun findSystemModule(moduleRoot: VirtualFile): JavaModule.Explicit? { private fun findSystemModule(moduleRoot: VirtualFile): JavaModule.Explicit? {
val file = moduleRoot.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE) ?: return null val file = moduleRoot.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE) ?: return null
@@ -35,7 +35,7 @@ class CliJavaModuleFinder(jrtFileSystemRoot: VirtualFile?) : JavaModuleFinder {
get() = modulesRoot?.children.orEmpty().asSequence().mapNotNull(this::findSystemModule) get() = modulesRoot?.children.orEmpty().asSequence().mapNotNull(this::findSystemModule)
override fun findModule(name: String): JavaModule? = override fun findModule(name: String): JavaModule? =
modulesRoot?.findChild(name)?.let(this::findSystemModule) ?: userModules[name] modulesRoot?.findChild(name)?.let(this::findSystemModule) ?: userModules[name]
private fun findSystemModule(moduleRoot: VirtualFile): JavaModule.Explicit? { private fun findSystemModule(moduleRoot: VirtualFile): JavaModule.Explicit? {
/* /*
@@ -35,7 +35,7 @@ class CliJavaModuleFinder(jrtFileSystemRoot: VirtualFile?) : JavaModuleFinder {
get() = modulesRoot?.children.orEmpty().asSequence().mapNotNull(this::findSystemModule) get() = modulesRoot?.children.orEmpty().asSequence().mapNotNull(this::findSystemModule)
override fun findModule(name: String): JavaModule? = override fun findModule(name: String): JavaModule? =
modulesRoot?.findChild(name)?.let(this::findSystemModule) ?: userModules[name] modulesRoot?.findChild(name)?.let(this::findSystemModule) ?: userModules[name]
private fun findSystemModule(moduleRoot: VirtualFile): JavaModule.Explicit? { private fun findSystemModule(moduleRoot: VirtualFile): JavaModule.Explicit? {
/* /*
@@ -27,9 +27,9 @@ import org.jetbrains.kotlin.resolve.jvm.modules.JavaModule
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
class CliJavaModuleResolver( class CliJavaModuleResolver(
private val moduleGraph: JavaModuleGraph, private val moduleGraph: JavaModuleGraph,
private val userModules: List<JavaModule>, private val userModules: List<JavaModule>,
private val systemModules: List<JavaModule.Explicit> private val systemModules: List<JavaModule.Explicit>
) : JavaModuleResolver { ) : JavaModuleResolver {
init { init {
assert(userModules.count(JavaModule::isSourceModule) <= 1) { assert(userModules.count(JavaModule::isSourceModule) <= 1) {
@@ -52,10 +52,10 @@ class CliJavaModuleResolver(
} }
private operator fun JavaModule.contains(file: VirtualFile): Boolean = private operator fun JavaModule.contains(file: VirtualFile): Boolean =
moduleRoots.any { (root, isBinary) -> isBinary && VfsUtilCore.isAncestor(root, file, false) } moduleRoots.any { (root, isBinary) -> isBinary && VfsUtilCore.isAncestor(root, file, false) }
override fun checkAccessibility( override fun checkAccessibility(
fileFromOurModule: VirtualFile?, referencedFile: VirtualFile, referencedPackage: FqName? fileFromOurModule: VirtualFile?, referencedFile: VirtualFile, referencedPackage: FqName?
): JavaModuleResolver.AccessError? { ): JavaModuleResolver.AccessError? {
val ourModule = fileFromOurModule?.let(this::findJavaModule) val ourModule = fileFromOurModule?.let(this::findJavaModule)
val theirModule = this.findJavaModule(referencedFile) val theirModule = this.findJavaModule(referencedFile)
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.cli.jvm.modules package org.jetbrains.kotlin.cli.jvm.modules
import com.intellij.openapi.util.SystemInfo
import com.intellij.openapi.vfs.DeprecatedVirtualFileSystem import com.intellij.openapi.vfs.DeprecatedVirtualFileSystem
import com.intellij.openapi.vfs.StandardFileSystems import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
@@ -47,9 +46,9 @@ class CoreJrtFileSystem : DeprecatedVirtualFileSystem() {
} }
internal class CoreJrtHandler( internal class CoreJrtHandler(
val virtualFileSystem: CoreJrtFileSystem, val virtualFileSystem: CoreJrtFileSystem,
val jdkHomePath: String, val jdkHomePath: String,
private val root: Path private val root: Path
) { ) {
fun findFile(fileName: String): VirtualFile? { fun findFile(fileName: String): VirtualFile? {
val path = root.resolve(fileName) val path = root.resolve(fileName)
@@ -80,9 +79,9 @@ class CoreJrtFileSystem : DeprecatedVirtualFileSystem() {
companion object { companion object {
private fun loadJrtFsJar(jdkHome: File): File? = private fun loadJrtFsJar(jdkHome: File): File? =
File(jdkHome, "lib/jrt-fs.jar").takeIf(File::exists) File(jdkHome, "lib/jrt-fs.jar").takeIf(File::exists)
fun isModularJdk(jdkHome: File): Boolean = fun isModularJdk(jdkHome: File): Boolean =
loadJrtFsJar(jdkHome) != null loadJrtFsJar(jdkHome) != null
} }
} }
@@ -36,10 +36,10 @@ internal class CoreJrtVirtualFile(private val handler: CoreJrtHandler, private v
override fun getFileSystem(): VirtualFileSystem = handler.virtualFileSystem override fun getFileSystem(): VirtualFileSystem = handler.virtualFileSystem
override fun getName(): String = override fun getName(): String =
path.fileName.toString() path.fileName.toString()
override fun getPath(): String = override fun getPath(): String =
FileUtil.toSystemIndependentName(handler.jdkHomePath + URLUtil.JAR_SEPARATOR + path) FileUtil.toSystemIndependentName(handler.jdkHomePath + URLUtil.JAR_SEPARATOR + path)
override fun isWritable(): Boolean = false override fun isWritable(): Boolean = false
@@ -55,8 +55,7 @@ internal class CoreJrtVirtualFile(private val handler: CoreJrtHandler, private v
override fun getChildren(): Array<out VirtualFile> { override fun getChildren(): Array<out VirtualFile> {
val paths = try { val paths = try {
Files.newDirectoryStream(path).use(Iterable<Path>::toList) Files.newDirectoryStream(path).use(Iterable<Path>::toList)
} } catch (e: IOException) {
catch (e: IOException) {
emptyList<Path>() emptyList<Path>()
} }
return when { return when {
@@ -66,26 +65,26 @@ internal class CoreJrtVirtualFile(private val handler: CoreJrtHandler, private v
} }
override fun getOutputStream(requestor: Any, newModificationStamp: Long, newTimeStamp: Long): OutputStream = override fun getOutputStream(requestor: Any, newModificationStamp: Long, newTimeStamp: Long): OutputStream =
throw UnsupportedOperationException() throw UnsupportedOperationException()
override fun contentsToByteArray(): ByteArray = override fun contentsToByteArray(): ByteArray =
Files.readAllBytes(path) Files.readAllBytes(path)
override fun getTimeStamp(): Long = override fun getTimeStamp(): Long =
attributes.lastModifiedTime().toMillis() attributes.lastModifiedTime().toMillis()
override fun getLength(): Long = attributes.size() override fun getLength(): Long = attributes.size()
override fun refresh(asynchronous: Boolean, recursive: Boolean, postRunnable: Runnable?) {} override fun refresh(asynchronous: Boolean, recursive: Boolean, postRunnable: Runnable?) {}
override fun getInputStream(): InputStream = override fun getInputStream(): InputStream =
VfsUtilCore.inputStreamSkippingBOM(Files.newInputStream(path).buffered(), this) VfsUtilCore.inputStreamSkippingBOM(Files.newInputStream(path).buffered(), this)
override fun getModificationStamp(): Long = 0 override fun getModificationStamp(): Long = 0
override fun equals(other: Any?): Boolean = override fun equals(other: Any?): Boolean =
other is CoreJrtVirtualFile && path == other.path && fileSystem == other.fileSystem other is CoreJrtVirtualFile && path == other.path && fileSystem == other.fileSystem
override fun hashCode(): Int = override fun hashCode(): Int =
path.hashCode() path.hashCode()
} }
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.storage.LockBasedStorageManager
class JavaModuleGraph(finder: JavaModuleFinder) { class JavaModuleGraph(finder: JavaModuleFinder) {
private val module: (String) -> JavaModule? = private val module: (String) -> JavaModule? =
LockBasedStorageManager.NO_LOCKS.createMemoizedFunctionWithNullableValues(finder::findModule) LockBasedStorageManager.NO_LOCKS.createMemoizedFunctionWithNullableValues(finder::findModule)
fun getAllDependencies(moduleNames: List<String>): LinkedHashSet<String> { fun getAllDependencies(moduleNames: List<String>): LinkedHashSet<String> {
val visited = LinkedHashSet(moduleNames) val visited = LinkedHashSet(moduleNames)
@@ -26,32 +26,31 @@ import org.jetbrains.kotlin.cli.jvm.BundledCompilerPlugins
import org.jetbrains.kotlin.compiler.plugin.* import org.jetbrains.kotlin.compiler.plugin.*
import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CompilerConfiguration
import java.io.File import java.io.File
import java.net.URL
import java.util.* import java.util.*
object PluginCliParser { object PluginCliParser {
@JvmStatic @JvmStatic
fun loadPluginsSafe(pluginClasspaths: Array<String>?, pluginOptions: Array<String>?, configuration: CompilerConfiguration): ExitCode = fun loadPluginsSafe(pluginClasspaths: Array<String>?, pluginOptions: Array<String>?, configuration: CompilerConfiguration): ExitCode =
loadPluginsSafe(pluginClasspaths?.asIterable(), pluginOptions?.asIterable(), configuration) loadPluginsSafe(pluginClasspaths?.asIterable(), pluginOptions?.asIterable(), configuration)
@JvmStatic @JvmStatic
fun loadPluginsSafe(pluginClasspaths: Iterable<String>?, pluginOptions: Iterable<String>?, configuration: CompilerConfiguration): ExitCode { fun loadPluginsSafe(
pluginClasspaths: Iterable<String>?,
pluginOptions: Iterable<String>?,
configuration: CompilerConfiguration
): ExitCode {
val messageCollector = configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) val messageCollector = configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
try { try {
PluginCliParser.loadPlugins(pluginClasspaths, pluginOptions, configuration) PluginCliParser.loadPlugins(pluginClasspaths, pluginOptions, configuration)
} } catch (e: PluginCliOptionProcessingException) {
catch (e: PluginCliOptionProcessingException) {
val message = e.message + "\n\n" + cliPluginUsageString(e.pluginId, e.options) val message = e.message + "\n\n" + cliPluginUsageString(e.pluginId, e.options)
messageCollector.report(CompilerMessageSeverity.ERROR, message) messageCollector.report(CompilerMessageSeverity.ERROR, message)
return ExitCode.INTERNAL_ERROR return ExitCode.INTERNAL_ERROR
} } catch (e: CliOptionProcessingException) {
catch (e: CliOptionProcessingException) {
messageCollector.report(CompilerMessageSeverity.ERROR, e.message!!) messageCollector.report(CompilerMessageSeverity.ERROR, e.message!!)
return ExitCode.INTERNAL_ERROR return ExitCode.INTERNAL_ERROR
} } catch (t: Throwable) {
catch (t: Throwable) {
MessageCollectorUtil.reportException(messageCollector, t) MessageCollectorUtil.reportException(messageCollector, t)
return ExitCode.INTERNAL_ERROR return ExitCode.INTERNAL_ERROR
} }
@@ -61,11 +60,11 @@ object PluginCliParser {
@JvmStatic @JvmStatic
fun loadPlugins(pluginClasspaths: Iterable<String>?, pluginOptions: Iterable<String>?, configuration: CompilerConfiguration) { fun loadPlugins(pluginClasspaths: Iterable<String>?, pluginOptions: Iterable<String>?, configuration: CompilerConfiguration) {
val classLoader = PluginURLClassLoader( val classLoader = PluginURLClassLoader(
pluginClasspaths pluginClasspaths
?.map { File(it).toURI().toURL() } ?.map { File(it).toURI().toURL() }
?.toTypedArray() ?.toTypedArray()
?: arrayOf<URL>(), ?: emptyArray(),
this::class.java.classLoader this::class.java.classLoader
) )
val componentRegistrars = ServiceLoader.load(ComponentRegistrar::class.java, classLoader).toMutableList() val componentRegistrars = ServiceLoader.load(ComponentRegistrar::class.java, classLoader).toMutableList()
@@ -76,9 +75,9 @@ object PluginCliParser {
} }
private fun processPluginOptions( private fun processPluginOptions(
pluginOptions: Iterable<String>?, pluginOptions: Iterable<String>?,
configuration: CompilerConfiguration, configuration: CompilerConfiguration,
classLoader: ClassLoader classLoader: ClassLoader
) { ) {
val optionValuesByPlugin = pluginOptions?.map(::parsePluginOption)?.groupBy { val optionValuesByPlugin = pluginOptions?.map(::parsePluginOption)?.groupBy {
if (it == null) throw CliOptionProcessingException("Wrong plugin option format: $it, should be ${CommonCompilerArguments.PLUGIN_OPTION_FORMAT}") if (it == null) throw CliOptionProcessingException("Wrong plugin option format: $it, should be ${CommonCompilerArguments.PLUGIN_OPTION_FORMAT}")
@@ -94,7 +93,7 @@ object PluginCliParser {
for (optionValue in optionValuesByPlugin[processor.pluginId].orEmpty()) { for (optionValue in optionValuesByPlugin[processor.pluginId].orEmpty()) {
val option = declaredOptions[optionValue!!.optionName] val option = declaredOptions[optionValue!!.optionName]
?: throw CliOptionProcessingException("Unsupported plugin option: $optionValue") ?: throw CliOptionProcessingException("Unsupported plugin option: $optionValue")
optionsToValues.putValue(option, optionValue) optionsToValues.putValue(option, optionValue)
} }
@@ -102,15 +101,17 @@ object PluginCliParser {
val values = optionsToValues[option] val values = optionsToValues[option]
if (option.required && values.isEmpty()) { if (option.required && values.isEmpty()) {
throw PluginCliOptionProcessingException( throw PluginCliOptionProcessingException(
processor.pluginId, processor.pluginId,
processor.pluginOptions, processor.pluginOptions,
"Required plugin option not present: ${processor.pluginId}:${option.name}") "Required plugin option not present: ${processor.pluginId}:${option.name}"
)
} }
if (!option.allowMultipleOccurrences && values.size > 1) { if (!option.allowMultipleOccurrences && values.size > 1) {
throw PluginCliOptionProcessingException( throw PluginCliOptionProcessingException(
processor.pluginId, processor.pluginId,
processor.pluginOptions, processor.pluginOptions,
"Multiple values are not allowed for plugin option ${processor.pluginId}:${option.name}") "Multiple values are not allowed for plugin option ${processor.pluginId}:${option.name}"
)
} }
for (value in values) { for (value in values) {
@@ -27,8 +27,7 @@ internal class PluginURLClassLoader(urls: Array<URL>, parent: ClassLoader) : Cla
override fun loadClass(name: String, resolve: Boolean): Class<*> { override fun loadClass(name: String, resolve: Boolean): Class<*> {
return try { return try {
childClassLoader.findClass(name) childClassLoader.findClass(name)
} } catch (e: ClassNotFoundException) {
catch (e: ClassNotFoundException) {
super.loadClass(name, resolve) super.loadClass(name, resolve)
} }
} }
@@ -45,8 +44,7 @@ internal class PluginURLClassLoader(urls: Array<URL>, parent: ClassLoader) : Cla
return try { return try {
super.findClass(name) super.findClass(name)
} } catch (e: ClassNotFoundException) {
catch (e: ClassNotFoundException) {
onFail.loadClass(name) onFail.loadClass(name)
} }
} }
@@ -31,15 +31,17 @@ open class DelegatePackageMemberDeclarationProvider(var delegate: PackageMemberD
override fun containsFile(file: KtFile) = delegate.containsFile(file) override fun containsFile(file: KtFile) = delegate.containsFile(file)
override fun getDeclarations(kindFilter: DescriptorKindFilter, override fun getDeclarations(
nameFilter: (Name) -> Boolean) = delegate.getDeclarations(kindFilter, nameFilter) kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
) = delegate.getDeclarations(kindFilter, nameFilter)
override fun getFunctionDeclarations(name: Name) = delegate.getFunctionDeclarations(name) override fun getFunctionDeclarations(name: Name) = delegate.getFunctionDeclarations(name)
override fun getPropertyDeclarations(name: Name) = delegate.getPropertyDeclarations(name) override fun getPropertyDeclarations(name: Name) = delegate.getPropertyDeclarations(name)
override fun getDestructuringDeclarationsEntries(name: Name): Collection<KtDestructuringDeclarationEntry> = override fun getDestructuringDeclarationsEntries(name: Name): Collection<KtDestructuringDeclarationEntry> =
delegate.getDestructuringDeclarationsEntries(name) delegate.getDestructuringDeclarationsEntries(name)
override fun getClassOrObjectDeclarations(name: Name) = delegate.getClassOrObjectDeclarations(name) override fun getClassOrObjectDeclarations(name: Name) = delegate.getClassOrObjectDeclarations(name)
@@ -43,26 +43,28 @@ class ReplCompilerStageHistory(private val state: GenericReplCompilerState) : Ba
} }
private fun checkConsistent(removedCompiledLines: Iterable<ILineId>, removedAnalyzedLines: List<ReplCodeLine>) { private fun checkConsistent(removedCompiledLines: Iterable<ILineId>, removedAnalyzedLines: List<ReplCodeLine>) {
removedCompiledLines.zip(removedAnalyzedLines).forEach { removedCompiledLines.zip(removedAnalyzedLines).forEach { (removedCompiledLine, removedAnalyzedLine) ->
if (it.first != LineId(it.second)) { if (removedCompiledLine != LineId(removedAnalyzedLine)) {
throw IllegalStateException("History mismatch when resetting lines: ${it.first.no} != ${it.second}") throw IllegalStateException("History mismatch when resetting lines: ${removedCompiledLine.no} != $removedAnalyzedLine")
} }
} }
} }
} }
abstract class GenericReplCheckerState: IReplStageState<ScriptDescriptor> { abstract class GenericReplCheckerState : IReplStageState<ScriptDescriptor> {
// "line" - is the unit of evaluation here, could in fact consists of several character lines // "line" - is the unit of evaluation here, could in fact consists of several character lines
class LineState( class LineState(
val codeLine: ReplCodeLine, val codeLine: ReplCodeLine,
val psiFile: KtFile, val psiFile: KtFile,
val errorHolder: DiagnosticMessageHolder) val errorHolder: DiagnosticMessageHolder
)
var lastLineState: LineState? = null // for transferring state to the compiler in most typical case var lastLineState: LineState? = null // for transferring state to the compiler in most typical case
} }
class GenericReplCompilerState(environment: KotlinCoreEnvironment, override val lock: ReentrantReadWriteLock = ReentrantReadWriteLock()) : IReplStageState<ScriptDescriptor>, GenericReplCheckerState() { class GenericReplCompilerState(environment: KotlinCoreEnvironment, override val lock: ReentrantReadWriteLock = ReentrantReadWriteLock()) :
IReplStageState<ScriptDescriptor>, GenericReplCheckerState() {
override val history = ReplCompilerStageHistory(this) override val history = ReplCompilerStageHistory(this)
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.cli.jvm.repl package org.jetbrains.kotlin.cli.jvm.repl
import com.intellij.openapi.Disposable import com.intellij.openapi.Disposable
import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.util.text.StringUtil
import com.intellij.openapi.vfs.CharsetToolkit import com.intellij.openapi.vfs.CharsetToolkit
@@ -42,10 +41,10 @@ import kotlin.concurrent.write
const val KOTLIN_REPL_JVM_TARGET_PROPERTY = "kotlin.repl.jvm.target" const val KOTLIN_REPL_JVM_TARGET_PROPERTY = "kotlin.repl.jvm.target"
open class GenericReplChecker( open class GenericReplChecker(
disposable: Disposable, disposable: Disposable,
private val scriptDefinition: KotlinScriptDefinition, private val scriptDefinition: KotlinScriptDefinition,
private val compilerConfiguration: CompilerConfiguration, private val compilerConfiguration: CompilerConfiguration,
messageCollector: MessageCollector messageCollector: MessageCollector
) : ReplCheckAction { ) : ReplCheckAction {
internal val environment = run { internal val environment = run {
@@ -57,7 +56,7 @@ open class GenericReplChecker(
if (get(JVMConfigurationKeys.JVM_TARGET) == null) { if (get(JVMConfigurationKeys.JVM_TARGET) == null) {
put(JVMConfigurationKeys.JVM_TARGET, put(JVMConfigurationKeys.JVM_TARGET,
System.getProperty(KOTLIN_REPL_JVM_TARGET_PROPERTY)?.let { JvmTarget.fromString(it) } System.getProperty(KOTLIN_REPL_JVM_TARGET_PROPERTY)?.let { JvmTarget.fromString(it) }
?: if (getJavaVersion() >= 0x10008) JvmTarget.JVM_1_8 else JvmTarget.JVM_1_6) ?: if (getJavaVersion() >= 0x10008) JvmTarget.JVM_1_8 else JvmTarget.JVM_1_6)
} }
} }
KotlinCoreEnvironment.createForProduction(disposable, compilerConfiguration, EnvironmentConfigFiles.JVM_CONFIG_FILES) KotlinCoreEnvironment.createForProduction(disposable, compilerConfiguration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
@@ -72,11 +71,15 @@ open class GenericReplChecker(
val checkerState = state.asState(GenericReplCheckerState::class.java) val checkerState = state.asState(GenericReplCheckerState::class.java)
val scriptFileName = makeScriptBaseName(codeLine) val scriptFileName = makeScriptBaseName(codeLine)
val virtualFile = val virtualFile =
LightVirtualFile("$scriptFileName${KotlinParserDefinition.STD_SCRIPT_EXT}", KotlinLanguage.INSTANCE, StringUtil.convertLineSeparators(codeLine.code)).apply { LightVirtualFile(
charset = CharsetToolkit.UTF8_CHARSET "$scriptFileName${KotlinParserDefinition.STD_SCRIPT_EXT}",
} KotlinLanguage.INSTANCE,
StringUtil.convertLineSeparators(codeLine.code)
).apply {
charset = CharsetToolkit.UTF8_CHARSET
}
val psiFile: KtFile = psiFileFactory.trySetupPsiForFile(virtualFile, KotlinLanguage.INSTANCE, true, false) as KtFile? val psiFile: KtFile = psiFileFactory.trySetupPsiForFile(virtualFile, KotlinLanguage.INSTANCE, true, false) as KtFile?
?: error("Script file not analyzed at line ${codeLine.no}: ${codeLine.code}") ?: error("Script file not analyzed at line ${codeLine.no}: ${codeLine.code}")
val errorHolder = createDiagnosticHolder() val errorHolder = createDiagnosticHolder()
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.cli.jvm.repl package org.jetbrains.kotlin.cli.jvm.repl
import com.intellij.openapi.Disposable import com.intellij.openapi.Disposable
import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.Disposer
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
@@ -24,6 +23,7 @@ import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.repl.* import org.jetbrains.kotlin.cli.common.repl.*
import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
import org.jetbrains.kotlin.codegen.ClassBuilderFactories import org.jetbrains.kotlin.codegen.ClassBuilderFactories
import org.jetbrains.kotlin.codegen.CompilationErrorHandler
import org.jetbrains.kotlin.codegen.KotlinCodegenFacade import org.jetbrains.kotlin.codegen.KotlinCodegenFacade
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CompilerConfiguration
@@ -41,14 +41,18 @@ import kotlin.concurrent.write
// WARNING: not thread safe, assuming external synchronization // WARNING: not thread safe, assuming external synchronization
open class GenericReplCompiler(disposable: Disposable, open class GenericReplCompiler(
scriptDefinition: KotlinScriptDefinition, disposable: Disposable,
private val compilerConfiguration: CompilerConfiguration, scriptDefinition: KotlinScriptDefinition,
messageCollector: MessageCollector private val compilerConfiguration: CompilerConfiguration,
messageCollector: MessageCollector
) : ReplCompiler { ) : ReplCompiler {
constructor(scriptDefinition: KotlinScriptDefinition, compilerConfiguration: CompilerConfiguration, messageCollector: MessageCollector) : constructor(
this(Disposer.newDisposable(), scriptDefinition, compilerConfiguration, messageCollector) scriptDefinition: KotlinScriptDefinition,
compilerConfiguration: CompilerConfiguration,
messageCollector: MessageCollector
) : this(Disposer.newDisposable(), scriptDefinition, compilerConfiguration, messageCollector)
private val checker = GenericReplChecker(disposable, scriptDefinition, compilerConfiguration, messageCollector) private val checker = GenericReplChecker(disposable, scriptDefinition, compilerConfiguration, messageCollector)
@@ -66,7 +70,8 @@ open class GenericReplCompiler(disposable: Disposable,
when (res) { when (res) {
is ReplCheckResult.Incomplete -> return@compile ReplCompileResult.Incomplete() is ReplCheckResult.Incomplete -> return@compile ReplCompileResult.Incomplete()
is ReplCheckResult.Error -> return@compile ReplCompileResult.Error(res.message, res.location) is ReplCheckResult.Error -> return@compile ReplCompileResult.Error(res.message, res.location)
is ReplCheckResult.Ok -> {} // continue is ReplCheckResult.Ok -> {
} // continue
} }
} }
Pair(compilerState.lastLineState!!.psiFile, compilerState.lastLineState!!.errorHolder) Pair(compilerState.lastLineState!!.psiFile, compilerState.lastLineState!!.errorHolder)
@@ -88,29 +93,28 @@ open class GenericReplCompiler(disposable: Disposable,
} }
val generationState = GenerationState.Builder( val generationState = GenerationState.Builder(
psiFile.project, psiFile.project,
ClassBuilderFactories.BINARIES, ClassBuilderFactories.BINARIES,
compilerState.analyzerEngine.module, compilerState.analyzerEngine.module,
compilerState.analyzerEngine.trace.bindingContext, compilerState.analyzerEngine.trace.bindingContext,
listOf(psiFile), listOf(psiFile),
compilerConfiguration compilerConfiguration
).build() ).build()
generationState.replSpecific.scriptResultFieldName = SCRIPT_RESULT_FIELD_NAME generationState.replSpecific.scriptResultFieldName = SCRIPT_RESULT_FIELD_NAME
generationState.replSpecific.earlierScriptsForReplInterpreter = compilerState.history.map { it.item } generationState.replSpecific.earlierScriptsForReplInterpreter = compilerState.history.map { it.item }
generationState.beforeCompile() generationState.beforeCompile()
KotlinCodegenFacade.generatePackage( KotlinCodegenFacade.generatePackage(
generationState, generationState,
psiFile.script!!.containingKtFile.packageFqName, psiFile.script!!.containingKtFile.packageFqName,
setOf(psiFile.script!!.containingKtFile), setOf(psiFile.script!!.containingKtFile),
org.jetbrains.kotlin.codegen.CompilationErrorHandler.THROW_EXCEPTION) CompilationErrorHandler.THROW_EXCEPTION
)
val generatedClassname = makeScriptBaseName(codeLine) val generatedClassname = makeScriptBaseName(codeLine)
compilerState.history.push(LineId(codeLine), scriptDescriptor) compilerState.history.push(LineId(codeLine), scriptDescriptor)
val expression = psiFile.getChildOfType<KtScript>()?. val expression = psiFile.getChildOfType<KtScript>()?.getChildOfType<KtBlockExpression>()?.getChildOfType<KtScriptInitializer>()
getChildOfType<KtBlockExpression>()?. ?.getChildOfType<KtExpression>()
getChildOfType<KtScriptInitializer>()?.
getChildOfType<KtExpression>()
val type = expression?.let { val type = expression?.let {
compilerState.analyzerEngine.trace.bindingContext.getType(it) compilerState.analyzerEngine.trace.bindingContext.getType(it)
@@ -118,17 +122,19 @@ open class GenericReplCompiler(disposable: Disposable,
DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(it) DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(it)
} }
return ReplCompileResult.CompiledClasses(LineId(codeLine), return ReplCompileResult.CompiledClasses(
compilerState.history.map { it.id }, LineId(codeLine),
generatedClassname, compilerState.history.map { it.id },
generationState.factory.asList().map { CompiledClassData(it.relativePath, it.asByteArray()) }, generatedClassname,
generationState.replSpecific.hasResult, generationState.factory.asList().map { CompiledClassData(it.relativePath, it.asByteArray()) },
classpathAddendum ?: emptyList(), generationState.replSpecific.hasResult,
type) classpathAddendum ?: emptyList(),
type
)
} }
} }
companion object { companion object {
private val SCRIPT_RESULT_FIELD_NAME = "\$\$result" private const val SCRIPT_RESULT_FIELD_NAME = "\$\$result"
} }
} }
@@ -47,7 +47,6 @@ import org.jetbrains.kotlin.resolve.scopes.utils.replaceImportingScopes
import org.jetbrains.kotlin.script.ScriptPriorities import org.jetbrains.kotlin.script.ScriptPriorities
class ReplCodeAnalyzer(environment: KotlinCoreEnvironment) { class ReplCodeAnalyzer(environment: KotlinCoreEnvironment) {
private val topDownAnalysisContext: TopDownAnalysisContext private val topDownAnalysisContext: TopDownAnalysisContext
private val topDownAnalyzer: LazyTopDownAnalyzer private val topDownAnalyzer: LazyTopDownAnalyzer
private val resolveSession: ResolveSession private val resolveSession: ResolveSession
@@ -63,28 +62,29 @@ class ReplCodeAnalyzer(environment: KotlinCoreEnvironment) {
// to be found via ResolveSession. The latter is true as long as light classes are not needed in REPL (which is currently true // to be found via ResolveSession. The latter is true as long as light classes are not needed in REPL (which is currently true
// because no symbol declared in the REPL session can be used from Java) // because no symbol declared in the REPL session can be used from Java)
val container = TopDownAnalyzerFacadeForJVM.createContainer( val container = TopDownAnalyzerFacadeForJVM.createContainer(
environment.project, environment.project,
emptyList(), emptyList(),
trace, trace,
environment.configuration, environment.configuration,
environment::createPackagePartProvider, environment::createPackagePartProvider,
{ _, _ -> ScriptMutableDeclarationProviderFactory() } { _, _ -> ScriptMutableDeclarationProviderFactory() }
) )
this.module = container.get<ModuleDescriptorImpl>() this.module = container.get()
this.scriptDeclarationFactory = container.get<ScriptMutableDeclarationProviderFactory>() this.scriptDeclarationFactory = container.get()
this.resolveSession = container.get<ResolveSession>() this.resolveSession = container.get()
this.topDownAnalysisContext = TopDownAnalysisContext( this.topDownAnalysisContext = TopDownAnalysisContext(
TopDownAnalysisMode.TopLevelDeclarations, DataFlowInfoFactory.EMPTY, resolveSession.declarationScopeProvider TopDownAnalysisMode.TopLevelDeclarations, DataFlowInfoFactory.EMPTY, resolveSession.declarationScopeProvider
) )
this.topDownAnalyzer = container.get<LazyTopDownAnalyzer>() this.topDownAnalyzer = container.get()
} }
interface ReplLineAnalysisResult { interface ReplLineAnalysisResult {
val scriptDescriptor: ScriptDescriptor? val scriptDescriptor: ScriptDescriptor?
val diagnostics: Diagnostics val diagnostics: Diagnostics
data class Successful(override val scriptDescriptor: ScriptDescriptor, override val diagnostics: Diagnostics) : ReplLineAnalysisResult data class Successful(override val scriptDescriptor: ScriptDescriptor, override val diagnostics: Diagnostics) :
ReplLineAnalysisResult
data class WithErrors(override val diagnostics: Diagnostics) : ReplLineAnalysisResult { data class WithErrors(override val diagnostics: Diagnostics) : ReplLineAnalysisResult {
override val scriptDescriptor: ScriptDescriptor? get() = null override val scriptDescriptor: ScriptDescriptor? get() = null
@@ -115,8 +115,7 @@ class ReplCodeAnalyzer(environment: KotlinCoreEnvironment) {
return if (hasErrors) { return if (hasErrors) {
replState.lineFailure(linePsi, codeLine) replState.lineFailure(linePsi, codeLine)
ReplLineAnalysisResult.WithErrors(diagnostics) ReplLineAnalysisResult.WithErrors(diagnostics)
} } else {
else {
val scriptDescriptor = context.scripts[linePsi.script]!! val scriptDescriptor = context.scripts[linePsi.script]!!
replState.lineSuccess(linePsi, codeLine, scriptDescriptor) replState.lineSuccess(linePsi, codeLine, scriptDescriptor)
ReplLineAnalysisResult.Successful(scriptDescriptor, diagnostics) ReplLineAnalysisResult.Successful(scriptDescriptor, diagnostics)
@@ -134,8 +133,7 @@ class ReplCodeAnalyzer(environment: KotlinCoreEnvironment) {
val provider = delegateFactory.getPackageMemberDeclarationProvider(FqName.ROOT)!! val provider = delegateFactory.getPackageMemberDeclarationProvider(FqName.ROOT)!!
try { try {
rootPackageProvider.addDelegateProvider(provider) rootPackageProvider.addDelegateProvider(provider)
} } catch (e: UninitializedPropertyAccessException) {
catch (e: UninitializedPropertyAccessException) {
rootPackageProvider = AdaptablePackageMemberDeclarationProvider(provider) rootPackageProvider = AdaptablePackageMemberDeclarationProvider(provider)
} }
} }
@@ -157,7 +155,7 @@ class ReplCodeAnalyzer(environment: KotlinCoreEnvironment) {
} }
class AdaptablePackageMemberDeclarationProvider( class AdaptablePackageMemberDeclarationProvider(
private var delegateProvider: PackageMemberDeclarationProvider private var delegateProvider: PackageMemberDeclarationProvider
) : DelegatePackageMemberDeclarationProvider(delegateProvider) { ) : DelegatePackageMemberDeclarationProvider(delegateProvider) {
fun addDelegateProvider(provider: PackageMemberDeclarationProvider) { fun addDelegateProvider(provider: PackageMemberDeclarationProvider) {
delegateProvider = CombinedPackageMemberDeclarationProvider(listOf(provider, delegateProvider)) delegateProvider = CombinedPackageMemberDeclarationProvider(listOf(provider, delegateProvider))
@@ -167,8 +165,8 @@ class ReplCodeAnalyzer(environment: KotlinCoreEnvironment) {
} }
} }
// TODO: merge with org.jetbrains.kotlin.resolve.repl.ReplState when switching to new REPL infrastruct everywhere // TODO: merge with org.jetbrains.kotlin.resolve.repl.ReplState when switching to new REPL infrastructure everywhere
// TODO: review it's place in the extracted state infrastruct (now the analyzer itself is a part of the state // TODO: review its place in the extracted state infrastructure (now the analyzer itself is a part of the state)
class ResettableAnalyzerState { class ResettableAnalyzerState {
private val successfulLines = ReplHistory<LineInfo.SuccessfulLine>() private val successfulLines = ReplHistory<LineInfo.SuccessfulLine>()
private val submittedLines = hashMapOf<KtFile, LineInfo>() private val submittedLines = hashMapOf<KtFile, LineInfo>()
@@ -212,7 +210,12 @@ class ReplCodeAnalyzer(environment: KotlinCoreEnvironment) {
abstract val parentLine: SuccessfulLine? abstract val parentLine: SuccessfulLine?
class SubmittedLine(override val linePsi: KtFile, override val parentLine: SuccessfulLine?) : LineInfo() class SubmittedLine(override val linePsi: KtFile, override val parentLine: SuccessfulLine?) : LineInfo()
class SuccessfulLine(override val linePsi: KtFile, override val parentLine: SuccessfulLine?, val lineDescriptor: LazyScriptDescriptor) : LineInfo() class SuccessfulLine(
override val linePsi: KtFile,
override val parentLine: SuccessfulLine?,
val lineDescriptor: LazyScriptDescriptor
) : LineInfo()
class FailedLine(override val linePsi: KtFile, override val parentLine: SuccessfulLine?) : LineInfo() class FailedLine(override val linePsi: KtFile, override val parentLine: SuccessfulLine?) : LineInfo()
} }
@@ -22,8 +22,8 @@ import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.messages.GroupingMessageCollector import org.jetbrains.kotlin.cli.common.messages.GroupingMessageCollector
import org.jetbrains.kotlin.cli.common.repl.ReplEvalResult import org.jetbrains.kotlin.cli.common.repl.ReplEvalResult
import org.jetbrains.kotlin.cli.jvm.repl.configuration.ConsoleReplConfiguration import org.jetbrains.kotlin.cli.jvm.repl.configuration.ConsoleReplConfiguration
import org.jetbrains.kotlin.cli.jvm.repl.configuration.ReplConfiguration
import org.jetbrains.kotlin.cli.jvm.repl.configuration.IdeReplConfiguration import org.jetbrains.kotlin.cli.jvm.repl.configuration.IdeReplConfiguration
import org.jetbrains.kotlin.cli.jvm.repl.configuration.ReplConfiguration
import org.jetbrains.kotlin.cli.jvm.repl.messages.unescapeLineBreaks import org.jetbrains.kotlin.cli.jvm.repl.messages.unescapeLineBreaks
import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.KotlinCompilerVersion import org.jetbrains.kotlin.config.KotlinCompilerVersion
@@ -36,9 +36,9 @@ import java.util.concurrent.Executors
import java.util.concurrent.Future import java.util.concurrent.Future
class ReplFromTerminal( class ReplFromTerminal(
disposable: Disposable, disposable: Disposable,
compilerConfiguration: CompilerConfiguration, compilerConfiguration: CompilerConfiguration,
private val replConfiguration: ReplConfiguration private val replConfiguration: ReplConfiguration
) { ) {
private val replInitializer: Future<ReplInterpreter> = Executors.newSingleThreadExecutor().submit(Callable { private val replInitializer: Future<ReplInterpreter> = Executors.newSingleThreadExecutor().submit(Callable {
ReplInterpreter(disposable, compilerConfiguration, replConfiguration) ReplInterpreter(disposable, compilerConfiguration, replConfiguration)
@@ -53,9 +53,11 @@ class ReplFromTerminal(
private fun doRun() { private fun doRun() {
try { try {
with (writer) { with(writer) {
printlnWelcomeMessage("Welcome to Kotlin version ${KotlinCompilerVersion.VERSION} " + printlnWelcomeMessage(
"(JRE ${System.getProperty("java.runtime.version")})") "Welcome to Kotlin version ${KotlinCompilerVersion.VERSION} " +
"(JRE ${System.getProperty("java.runtime.version")})"
)
printlnWelcomeMessage("Type :help for help, :quit for quit") printlnWelcomeMessage("Type :help for help, :quit for quit")
} }
@@ -71,16 +73,13 @@ class ReplFromTerminal(
break break
} }
} }
} } catch (e: Exception) {
catch (e: Exception) {
replConfiguration.exceptionReporter.report(e) replConfiguration.exceptionReporter.report(e)
throw e throw e
} } finally {
finally {
try { try {
replConfiguration.commandReader.flushHistory() replConfiguration.commandReader.flushHistory()
} } catch (e: Exception) {
catch (e: Exception) {
replConfiguration.exceptionReporter.report(e) replConfiguration.exceptionReporter.report(e)
throw e throw e
} }
@@ -99,7 +98,7 @@ class ReplFromTerminal(
line = unescapeLineBreaks(line) line = unescapeLineBreaks(line)
if (line.startsWith(":") && (line.length == 1 || line.get(1) != ':')) { if (line.startsWith(":") && (line.length == 1 || line[1] != ':')) {
val notQuit = oneCommand(line.substring(1)) val notQuit = oneCommand(line.substring(1))
return if (notQuit) WhatNextAfterOneLine.READ_LINE else WhatNextAfterOneLine.QUIT return if (notQuit) WhatNextAfterOneLine.READ_LINE else WhatNextAfterOneLine.QUIT
} }
@@ -107,8 +106,7 @@ class ReplFromTerminal(
val lineResult = eval(line) val lineResult = eval(line)
return if (lineResult is ReplEvalResult.Incomplete) { return if (lineResult is ReplEvalResult.Incomplete) {
WhatNextAfterOneLine.INCOMPLETE WhatNextAfterOneLine.INCOMPLETE
} } else {
else {
WhatNextAfterOneLine.READ_LINE WhatNextAfterOneLine.READ_LINE
} }
} }
@@ -132,22 +130,21 @@ class ReplFromTerminal(
@Throws(Exception::class) @Throws(Exception::class)
private fun oneCommand(command: String): Boolean { private fun oneCommand(command: String): Boolean {
val split = splitCommand(command) val split = splitCommand(command)
if (split.size >= 1 && command == "help") { if (split.isNotEmpty() && command == "help") {
writer.printlnHelpMessage("Available commands:\n" + writer.printlnHelpMessage(
":help show this help\n" + "Available commands:\n" +
":quit exit the interpreter\n" + ":help show this help\n" +
":dump bytecode dump classes to terminal\n" + ":quit exit the interpreter\n" +
":load <file> load script from specified file") ":dump bytecode dump classes to terminal\n" +
":load <file> load script from specified file"
)
return true return true
} } else if (split.size >= 2 && split[0] == "dump" && split[1] == "bytecode") {
else if (split.size >= 2 && split[0] == "dump" && split[1] == "bytecode") {
replInterpreter.dumpClasses(PrintWriter(System.out)) replInterpreter.dumpClasses(PrintWriter(System.out))
return true return true
} } else if (split.isNotEmpty() && split[0] == "quit") {
else if (split.size >= 1 && split[0] == "quit") {
return false return false
} } else if (split.size >= 2 && split[0] == "load") {
else if (split.size >= 2 && split[0] == "load") {
val fileName = split[1] val fileName = split[1]
try { try {
val scriptText = FileUtil.loadFile(File(fileName)) val scriptText = FileUtil.loadFile(File(fileName))
@@ -156,8 +153,7 @@ class ReplFromTerminal(
writer.outputCompileError("Can not load script: ${e.message}") writer.outputCompileError("Can not load script: ${e.message}")
} }
return true return true
} } else {
else {
writer.printlnHelpMessage("Unknown command\n" + "Type :help for help") writer.printlnHelpMessage("Unknown command\n" + "Type :help for help")
return true return true
} }
@@ -173,12 +169,10 @@ class ReplFromTerminal(
val replConfiguration = if (replIdeMode) IdeReplConfiguration() else ConsoleReplConfiguration() val replConfiguration = if (replIdeMode) IdeReplConfiguration() else ConsoleReplConfiguration()
return try { return try {
ReplFromTerminal(disposable, configuration, replConfiguration).doRun() ReplFromTerminal(disposable, configuration, replConfiguration).doRun()
} } catch (e: Exception) {
catch (e: Exception) {
replConfiguration.exceptionReporter.report(e) replConfiguration.exceptionReporter.report(e)
throw e throw e
} }
} }
} }
} }
@@ -33,9 +33,9 @@ import java.net.URLClassLoader
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
class ReplInterpreter( class ReplInterpreter(
disposable: Disposable, disposable: Disposable,
private val configuration: CompilerConfiguration, private val configuration: CompilerConfiguration,
private val replConfiguration: ReplConfiguration private val replConfiguration: ReplConfiguration
) { ) {
private val lineNumber = AtomicInteger() private val lineNumber = AtomicInteger()
@@ -60,14 +60,18 @@ class ReplInterpreter(
override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation?) { override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation?) {
val msg = messageRenderer.render(severity, message, location).trimEnd() val msg = messageRenderer.render(severity, message, location).trimEnd()
with (replConfiguration.writer) { with(replConfiguration.writer) {
when (severity) { when (severity) {
CompilerMessageSeverity.EXCEPTION -> sendInternalErrorReport(msg) CompilerMessageSeverity.EXCEPTION -> sendInternalErrorReport(msg)
CompilerMessageSeverity.ERROR -> outputCompileError(msg) CompilerMessageSeverity.ERROR -> outputCompileError(msg)
CompilerMessageSeverity.STRONG_WARNING -> {} // TODO consider reporting this and two below CompilerMessageSeverity.STRONG_WARNING -> {
CompilerMessageSeverity.WARNING -> {} } // TODO consider reporting this and two below
CompilerMessageSeverity.INFO -> {} CompilerMessageSeverity.WARNING -> {
else -> {} }
CompilerMessageSeverity.INFO -> {
}
else -> {
}
} }
} }
} }
@@ -86,14 +90,17 @@ class ReplInterpreter(
private val evalState by lazy { scriptEvaluator.createState() } private val evalState by lazy { scriptEvaluator.createState() }
fun eval(line: String): ReplEvalResult { fun eval(line: String): ReplEvalResult {
val fullText = (previousIncompleteLines + line).joinToString(separator = "\n") val fullText = (previousIncompleteLines + line).joinToString(separator = "\n")
try { try {
val evalRes = scriptEvaluator.compileAndEval(
val evalRes = scriptEvaluator.compileAndEval(evalState, ReplCodeLine(lineNumber.getAndIncrement(), 0, fullText), null, object : InvokeWrapper { evalState,
override fun <T> invoke(body: () -> T): T = replConfiguration.executionInterceptor.execute(body) ReplCodeLine(lineNumber.getAndIncrement(), 0, fullText),
}) null,
object : InvokeWrapper {
override fun <T> invoke(body: () -> T): T = replConfiguration.executionInterceptor.execute(body)
}
)
when { when {
evalRes !is ReplEvalResult.Incomplete -> previousIncompleteLines.clear() evalRes !is ReplEvalResult.Incomplete -> previousIncompleteLines.clear()
@@ -101,8 +108,7 @@ class ReplInterpreter(
else -> return ReplEvalResult.Error.CompileTime("incomplete code") else -> return ReplEvalResult.Error.CompileTime("incomplete code")
} }
return evalRes return evalRes
} } catch (e: Throwable) {
catch (e: Throwable) {
val writer = PrintWriter(System.err) val writer = PrintWriter(System.err)
classLoader.dumpClasses(writer) classLoader.dumpClasses(writer)
writer.flush() writer.flush()
@@ -27,8 +27,9 @@ class ConsoleDiagnosticMessageHolder : MessageCollectorBasedReporter, Diagnostic
private val outputStream = ByteArrayOutputStream() private val outputStream = ByteArrayOutputStream()
override val messageCollector: GroupingMessageCollector = GroupingMessageCollector( override val messageCollector: GroupingMessageCollector = GroupingMessageCollector(
PrintingMessageCollector(PrintStream(outputStream), MessageRenderer.WITHOUT_PATHS, false), PrintingMessageCollector(PrintStream(outputStream), MessageRenderer.WITHOUT_PATHS, false),
false) false
)
override fun renderMessage(): String { override fun renderMessage(): String {
messageCollector.flush() messageCollector.flush()
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.cli.jvm.repl.messages
import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.util.text.StringUtil
// using '#' to avoid collisions with xml escaping // using '#' to avoid collisions with xml escaping
internal val SOURCE_CHARS: Array<String> = arrayOf("\n", "#") internal val SOURCE_CHARS: Array<String> = arrayOf("\n", "#")
internal val XML_REPLACEMENTS: Array<String> = arrayOf("#n", "#diez") internal val XML_REPLACEMENTS: Array<String> = arrayOf("#n", "#diez")
fun unescapeLineBreaks(s: String) = StringUtil.replace(s, XML_REPLACEMENTS, SOURCE_CHARS) fun unescapeLineBreaks(s: String) = StringUtil.replace(s, XML_REPLACEMENTS, SOURCE_CHARS)
@@ -28,26 +28,24 @@ import java.util.logging.Logger
class ConsoleReplCommandReader : ReplCommandReader { class ConsoleReplCommandReader : ReplCommandReader {
private val lineReader = LineReaderBuilder.builder() private val lineReader = LineReaderBuilder.builder()
.appName("kotlin") .appName("kotlin")
.terminal(TerminalBuilder.terminal()) .terminal(TerminalBuilder.terminal())
.variable(LineReader.HISTORY_FILE, File(File(System.getProperty("user.home")), ".kotlinc_history").absolutePath) .variable(LineReader.HISTORY_FILE, File(File(System.getProperty("user.home")), ".kotlinc_history").absolutePath)
.build() .build()
.apply { .apply {
setOpt(LineReader.Option.DISABLE_EVENT_EXPANSION) setOpt(LineReader.Option.DISABLE_EVENT_EXPANSION)
} }
override fun readLine(next: ReplFromTerminal.WhatNextAfterOneLine): String? { override fun readLine(next: ReplFromTerminal.WhatNextAfterOneLine): String? {
val prompt = if (next == ReplFromTerminal.WhatNextAfterOneLine.INCOMPLETE) "... " else ">>> " val prompt = if (next == ReplFromTerminal.WhatNextAfterOneLine.INCOMPLETE) "... " else ">>> "
try { return try {
return lineReader.readLine(prompt) lineReader.readLine(prompt)
} } catch (e: UserInterruptException) {
catch (e: UserInterruptException) {
println("<interrupted>") println("<interrupted>")
System.out.flush() System.out.flush()
return "" ""
} } catch (e: EndOfFileException) {
catch (e: EndOfFileException) { null
return null
} }
} }
@@ -55,7 +53,7 @@ class ConsoleReplCommandReader : ReplCommandReader {
private companion object { private companion object {
init { init {
Logger.getLogger("org.jline").level = Level.OFF; Logger.getLogger("org.jline").level = Level.OFF
} }
} }
} }
@@ -26,8 +26,8 @@ import java.io.InputStream
import javax.xml.parsers.DocumentBuilderFactory import javax.xml.parsers.DocumentBuilderFactory
class ReplSystemInWrapper( class ReplSystemInWrapper(
private val stdin: InputStream, private val stdin: InputStream,
private val replWriter: ReplWriter private val replWriter: ReplWriter
) : InputStream() { ) : InputStream() {
private var isXmlIncomplete = true private var isXmlIncomplete = true
private var isLastByteProcessed = false private var isLastByteProcessed = false
@@ -39,7 +39,8 @@ class ReplSystemInWrapper(
private val isAtBufferEnd: Boolean private val isAtBufferEnd: Boolean
get() = curBytePos == inputByteArray.size get() = curBytePos == inputByteArray.size
@Volatile var isReplScriptExecuting = false @Volatile
var isReplScriptExecuting = false
override fun read(): Int { override fun read(): Int {
if (isLastByteProcessed) { if (isLastByteProcessed) {
@@ -43,16 +43,16 @@ class K2MetadataCompiler : CLICompiler<K2MetadataCompilerArguments>() {
override fun createArguments() = K2MetadataCompilerArguments() override fun createArguments() = K2MetadataCompilerArguments()
override fun setupPlatformSpecificArgumentsAndServices( override fun setupPlatformSpecificArgumentsAndServices(
configuration: CompilerConfiguration, arguments: K2MetadataCompilerArguments, services: Services configuration: CompilerConfiguration, arguments: K2MetadataCompilerArguments, services: Services
) { ) {
// No specific arguments yet // No specific arguments yet
} }
override fun doExecute( override fun doExecute(
arguments: K2MetadataCompilerArguments, arguments: K2MetadataCompilerArguments,
configuration: CompilerConfiguration, configuration: CompilerConfiguration,
rootDisposable: Disposable, rootDisposable: Disposable,
paths: KotlinPaths? paths: KotlinPaths?
): ExitCode { ): ExitCode {
val collector = configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) val collector = configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
@@ -74,12 +74,16 @@ class K2MetadataCompiler : CLICompiler<K2MetadataCompilerArguments>() {
if (destination != null) { if (destination != null) {
if (destination.endsWith(".jar")) { if (destination.endsWith(".jar")) {
// TODO: support .jar destination // TODO: support .jar destination
collector.report(STRONG_WARNING, ".jar destination is not yet supported, results will be written to the directory with the given name") collector.report(
STRONG_WARNING,
".jar destination is not yet supported, results will be written to the directory with the given name"
)
} }
configuration.put(CLIConfigurationKeys.METADATA_DESTINATION_DIRECTORY, File(destination)) configuration.put(CLIConfigurationKeys.METADATA_DESTINATION_DIRECTORY, File(destination))
} }
val environment = KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.METADATA_CONFIG_FILES) val environment =
KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.METADATA_CONFIG_FILES)
if (environment.getSourceFiles().isEmpty()) { if (environment.getSourceFiles().isEmpty()) {
if (arguments.version) { if (arguments.version) {
@@ -95,8 +99,7 @@ class K2MetadataCompiler : CLICompiler<K2MetadataCompilerArguments>() {
val metadataVersion = val metadataVersion =
configuration.get(CommonConfigurationKeys.METADATA_VERSION) as? BuiltInsBinaryVersion ?: BuiltInsBinaryVersion.INSTANCE configuration.get(CommonConfigurationKeys.METADATA_VERSION) as? BuiltInsBinaryVersion ?: BuiltInsBinaryVersion.INSTANCE
MetadataSerializer(metadataVersion, true).serialize(environment) MetadataSerializer(metadataVersion, true).serialize(environment)
} } catch (e: CompilationException) {
catch (e: CompilationException) {
collector.report(EXCEPTION, OutputMessageUtil.renderException(e), MessageUtil.psiElementToMessageLocation(e.element)) collector.report(EXCEPTION, OutputMessageUtil.renderException(e), MessageUtil.psiElementToMessageLocation(e.element))
return ExitCode.INTERNAL_ERROR return ExitCode.INTERNAL_ERROR
} }
@@ -81,7 +81,7 @@ open class MetadataSerializer(
} }
protected open fun performSerialization( protected open fun performSerialization(
files: Collection<KtFile>, bindingContext: BindingContext, module: ModuleDescriptor, destDir: File files: Collection<KtFile>, bindingContext: BindingContext, module: ModuleDescriptor, destDir: File
) { ) {
val packageTable = hashMapOf<FqName, PackageParts>() val packageTable = hashMapOf<FqName, PackageParts>()
@@ -91,23 +91,29 @@ open class MetadataSerializer(
for (declaration in file.declarations) { for (declaration in file.declarations) {
declaration.accept(object : KtVisitorVoid() { declaration.accept(object : KtVisitorVoid() {
override fun visitNamedFunction(function: KtNamedFunction) { override fun visitNamedFunction(function: KtNamedFunction) {
members.add(bindingContext.get(BindingContext.FUNCTION, function) members.add(
?: error("No descriptor found for function ${function.fqName}")) bindingContext.get(BindingContext.FUNCTION, function)
?: error("No descriptor found for function ${function.fqName}")
)
} }
override fun visitProperty(property: KtProperty) { override fun visitProperty(property: KtProperty) {
members.add(bindingContext.get(BindingContext.VARIABLE, property) members.add(
?: error("No descriptor found for property ${property.fqName}")) bindingContext.get(BindingContext.VARIABLE, property)
?: error("No descriptor found for property ${property.fqName}")
)
} }
override fun visitTypeAlias(typeAlias: KtTypeAlias) { override fun visitTypeAlias(typeAlias: KtTypeAlias) {
members.add(bindingContext.get(BindingContext.TYPE_ALIAS, typeAlias) members.add(
?: error("No descriptor found for type alias ${typeAlias.fqName}")) bindingContext.get(BindingContext.TYPE_ALIAS, typeAlias)
?: error("No descriptor found for type alias ${typeAlias.fqName}")
)
} }
override fun visitClassOrObject(classOrObject: KtClassOrObject) { override fun visitClassOrObject(classOrObject: KtClassOrObject) {
val classDescriptor = bindingContext.get(BindingContext.CLASS, classOrObject) val classDescriptor = bindingContext.get(BindingContext.CLASS, classOrObject)
?: error("No descriptor found for class ${classOrObject.fqName}") ?: error("No descriptor found for class ${classOrObject.fqName}")
val destFile = File(destDir, getClassFilePath(ClassId(packageFqName, classDescriptor.name))) val destFile = File(destDir, getClassFilePath(ClassId(packageFqName, classDescriptor.name)))
PackageSerializer(listOf(classDescriptor), emptyList(), packageFqName, destFile).run() PackageSerializer(listOf(classDescriptor), emptyList(), packageFqName, destFile).run()
} }
@@ -139,17 +145,17 @@ open class MetadataSerializer(
protected open fun createSerializerExtension(): KotlinSerializerExtensionBase = MetadataSerializerExtension(metadataVersion) protected open fun createSerializerExtension(): KotlinSerializerExtensionBase = MetadataSerializerExtension(metadataVersion)
private fun getPackageFilePath(packageFqName: FqName, fileName: String): String = private fun getPackageFilePath(packageFqName: FqName, fileName: String): String =
packageFqName.asString().replace('.', '/') + "/" + packageFqName.asString().replace('.', '/') + "/" +
PackagePartClassUtils.getFilePartShortName(fileName) + DOT_METADATA_FILE_EXTENSION PackagePartClassUtils.getFilePartShortName(fileName) + DOT_METADATA_FILE_EXTENSION
private fun getClassFilePath(classId: ClassId): String = private fun getClassFilePath(classId: ClassId): String =
classId.asSingleFqName().asString().replace('.', '/') + DOT_METADATA_FILE_EXTENSION classId.asSingleFqName().asString().replace('.', '/') + DOT_METADATA_FILE_EXTENSION
protected inner class PackageSerializer( protected inner class PackageSerializer(
private val classes: Collection<DeclarationDescriptor>, private val classes: Collection<DeclarationDescriptor>,
private val members: Collection<DeclarationDescriptor>, private val members: Collection<DeclarationDescriptor>,
private val packageFqName: FqName, private val packageFqName: FqName,
private val destFile: File private val destFile: File
) { ) {
private val proto = ProtoBuf.PackageFragment.newBuilder() private val proto = ProtoBuf.PackageFragment.newBuilder()
private val extension = createSerializerExtension() private val extension = createSerializerExtension()