From 8ffe379c92b605b1d7cce3d50f9119d36894773d Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 6 Oct 2016 10:54:04 +0300 Subject: [PATCH] Use separate module analysis in CliReplAnalyzerEngine --- .../compiler/KotlinToJVMBytecodeCompiler.kt | 2 +- .../cli/jvm/repl/CliReplAnalyzerEngine.kt | 35 ++++++--------- .../jvm/TopDownAnalyzerFacadeForJVM.kt | 45 ++++++++++++++----- compiler/testData/repl/modules/kt10001.repl | 5 +++ .../repl/ReplInterpreterTestGenerated.java | 15 +++++++ 5 files changed, 67 insertions(+), 35 deletions(-) create mode 100644 compiler/testData/repl/modules/kt10001.repl diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt index d382dbb19be..e2c6eff88c3 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt @@ -422,7 +422,7 @@ object KotlinToJVMBytecodeCompiler { CliLightClassGenerationSupport.NoScopeRecordCliBindingTrace(), environment.configuration, { scope -> JvmPackagePartProvider(environment, scope) }, - scope + sourceModuleSearchScope = scope ) } diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/CliReplAnalyzerEngine.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/CliReplAnalyzerEngine.kt index 65cdfac04de..11ef9106473 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/CliReplAnalyzerEngine.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/CliReplAnalyzerEngine.kt @@ -16,22 +16,19 @@ package org.jetbrains.kotlin.cli.jvm.repl -import com.intellij.psi.search.ProjectScope +import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.cli.jvm.compiler.CliLightClassGenerationSupport import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.container.get import org.jetbrains.kotlin.descriptors.ScriptDescriptor -import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl import org.jetbrains.kotlin.diagnostics.Severity -import org.jetbrains.kotlin.frontend.java.di.createContainerForTopDownSingleModuleAnalyzerForJvm import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.* import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics -import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM import org.jetbrains.kotlin.resolve.lazy.ResolveSession import org.jetbrains.kotlin.resolve.lazy.data.KtClassLikeInfo @@ -49,32 +46,26 @@ class CliReplAnalyzerEngine(environment: KotlinCoreEnvironment) { val trace: BindingTraceContext = CliLightClassGenerationSupport.NoScopeRecordCliBindingTrace() init { - val moduleContext = TopDownAnalyzerFacadeForJVM.createContextWithSealedModule(environment.project, environment.configuration) - this.module = moduleContext.module - - this.scriptDeclarationFactory = ScriptMutableDeclarationProviderFactory() - - val moduleContentScope = ProjectScope.getAllScope(environment.project) - val container = createContainerForTopDownSingleModuleAnalyzerForJvm( - moduleContext, + // Module source scope is empty because all binary classes are in the dependency module, and all source classes are guaranteed + // 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) + val container = TopDownAnalyzerFacadeForJVM.createContainer( + environment.project, + emptyList(), trace, - scriptDeclarationFactory, - moduleContentScope, - JvmPackagePartProvider(environment, moduleContentScope) + environment.configuration, + { scope -> JvmPackagePartProvider(environment, scope) }, + { storageManager, files -> ScriptMutableDeclarationProviderFactory() }, + GlobalSearchScope.EMPTY_SCOPE ) + this.module = container.get() + this.scriptDeclarationFactory = container.get() this.resolveSession = container.get() this.topDownAnalysisContext = TopDownAnalysisContext( TopDownAnalysisMode.LocalDeclarations, DataFlowInfoFactory.EMPTY, resolveSession.declarationScopeProvider ) this.topDownAnalyzer = container.get() - - moduleContext.initializeModuleContents(CompositePackageFragmentProvider( - listOf( - resolveSession.packageFragmentProvider, - container.get().packageFragmentProvider - ) - )) } interface ReplLineAnalysisResult { diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/TopDownAnalyzerFacadeForJVM.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/TopDownAnalyzerFacadeForJVM.kt index 708a46b8d54..4f924219766 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/TopDownAnalyzerFacadeForJVM.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/TopDownAnalyzerFacadeForJVM.kt @@ -26,11 +26,13 @@ import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl +import org.jetbrains.kotlin.container.ComponentProvider import org.jetbrains.kotlin.container.get import org.jetbrains.kotlin.context.ContextForNewModule import org.jetbrains.kotlin.context.MutableModuleContext import org.jetbrains.kotlin.context.ProjectContext import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.PackageFragmentProvider import org.jetbrains.kotlin.descriptors.PackagePartProvider import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider @@ -57,6 +59,7 @@ import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory +import org.jetbrains.kotlin.storage.StorageManager import java.util.* object TopDownAnalyzerFacadeForJVM { @@ -67,9 +70,34 @@ object TopDownAnalyzerFacadeForJVM { files: Collection, trace: BindingTrace, configuration: CompilerConfiguration, - packagePartProviderFactory: (GlobalSearchScope) -> PackagePartProvider, + packagePartProvider: (GlobalSearchScope) -> PackagePartProvider, + declarationProviderFactory: (StorageManager, Collection) -> DeclarationProviderFactory = ::FileBasedDeclarationProviderFactory, sourceModuleSearchScope: GlobalSearchScope = newModuleSearchScope(project, files) ): AnalysisResult { + val container = createContainer( + project, files, trace, configuration, packagePartProvider, declarationProviderFactory, sourceModuleSearchScope + ) + + container.get().analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, files) + + val module = container.get() + for (extension in AnalysisCompletedHandlerExtension.getInstances(project)) { + val result = extension.analysisCompleted(project, module, trace, files) + if (result != null) return result + } + + return AnalysisResult.success(trace.bindingContext, module) + } + + fun createContainer( + project: Project, + files: Collection, + trace: BindingTrace, + configuration: CompilerConfiguration, + packagePartProvider: (GlobalSearchScope) -> PackagePartProvider, + declarationProviderFactory: (StorageManager, Collection) -> DeclarationProviderFactory, + sourceModuleSearchScope: GlobalSearchScope + ): ComponentProvider { val moduleContext = createModuleContext(project, configuration) val storageManager = moduleContext.storageManager @@ -98,7 +126,7 @@ object TopDownAnalyzerFacadeForJVM { val dependenciesContainer = createContainerForTopDownAnalyzerForJvm( dependenciesContext, trace, DeclarationProviderFactory.EMPTY, dependencyScope, lookupTracker, - packagePartProviderFactory(dependencyScope), languageVersionSettings, moduleClassResolver + packagePartProvider(dependencyScope), languageVersionSettings, moduleClassResolver ) moduleClassResolver.compiledCodeResolver = dependenciesContainer.get() @@ -114,9 +142,9 @@ object TopDownAnalyzerFacadeForJVM { // 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 val container = createContainerForTopDownAnalyzerForJvm( - moduleContext, trace, FileBasedDeclarationProviderFactory(storageManager, files), sourceScope, lookupTracker, + moduleContext, trace, declarationProviderFactory(storageManager, files), sourceScope, lookupTracker, IncrementalPackagePartProvider.create( - packagePartProviderFactory(sourceScope), targetIds, incrementalComponents, storageManager + packagePartProvider(sourceScope), targetIds, incrementalComponents, storageManager ), languageVersionSettings, moduleClassResolver ).apply { @@ -152,14 +180,7 @@ object TopDownAnalyzerFacadeForJVM { additionalProviders )) - container.get().analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, files) - - for (extension in AnalysisCompletedHandlerExtension.getInstances(project)) { - val result = extension.analysisCompleted(project, module, trace, files) - if (result != null) return result - } - - return AnalysisResult.success(trace.bindingContext, module) + return container } fun newModuleSearchScope(project: Project, files: Collection): GlobalSearchScope { diff --git a/compiler/testData/repl/modules/kt10001.repl b/compiler/testData/repl/modules/kt10001.repl new file mode 100644 index 00000000000..b49ae808a9a --- /dev/null +++ b/compiler/testData/repl/modules/kt10001.repl @@ -0,0 +1,5 @@ +>>> val x: Pair = null to null +>>> if (x.first != null) x.first.hashCode() +error: smart cast to 'Any' is impossible, because 'x.first' is a public API property declared in different module +if (x.first != null) x.first.hashCode() + ^ diff --git a/compiler/tests/org/jetbrains/kotlin/repl/ReplInterpreterTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/repl/ReplInterpreterTestGenerated.java index 4cda6c55810..9d3e0403d51 100644 --- a/compiler/tests/org/jetbrains/kotlin/repl/ReplInterpreterTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/repl/ReplInterpreterTestGenerated.java @@ -200,6 +200,21 @@ public class ReplInterpreterTestGenerated extends AbstractReplInterpreterTest { } } + @TestMetadata("compiler/testData/repl/modules") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Modules extends AbstractReplInterpreterTest { + public void testAllFilesPresentInModules() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/repl/modules"), Pattern.compile("^(.+)\\.repl$"), true); + } + + @TestMetadata("kt10001.repl") + public void testKt10001() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/repl/modules/kt10001.repl"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/repl/multiline") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)