Use separate module analysis in CliReplAnalyzerEngine

This commit is contained in:
Alexander Udalov
2016-10-06 10:54:04 +03:00
parent 1e51ba7d00
commit 8ffe379c92
5 changed files with 67 additions and 35 deletions
@@ -422,7 +422,7 @@ object KotlinToJVMBytecodeCompiler {
CliLightClassGenerationSupport.NoScopeRecordCliBindingTrace(),
environment.configuration,
{ scope -> JvmPackagePartProvider(environment, scope) },
scope
sourceModuleSearchScope = scope
)
}
@@ -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<ModuleDescriptorImpl>()
this.scriptDeclarationFactory = container.get<ScriptMutableDeclarationProviderFactory>()
this.resolveSession = container.get<ResolveSession>()
this.topDownAnalysisContext = TopDownAnalysisContext(
TopDownAnalysisMode.LocalDeclarations, DataFlowInfoFactory.EMPTY, resolveSession.declarationScopeProvider
)
this.topDownAnalyzer = container.get<LazyTopDownAnalyzer>()
moduleContext.initializeModuleContents(CompositePackageFragmentProvider(
listOf(
resolveSession.packageFragmentProvider,
container.get<JavaDescriptorResolver>().packageFragmentProvider
)
))
}
interface ReplLineAnalysisResult {
@@ -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<KtFile>,
trace: BindingTrace,
configuration: CompilerConfiguration,
packagePartProviderFactory: (GlobalSearchScope) -> PackagePartProvider,
packagePartProvider: (GlobalSearchScope) -> PackagePartProvider,
declarationProviderFactory: (StorageManager, Collection<KtFile>) -> DeclarationProviderFactory = ::FileBasedDeclarationProviderFactory,
sourceModuleSearchScope: GlobalSearchScope = newModuleSearchScope(project, files)
): AnalysisResult {
val container = createContainer(
project, files, trace, configuration, packagePartProvider, declarationProviderFactory, sourceModuleSearchScope
)
container.get<LazyTopDownAnalyzer>().analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, files)
val module = container.get<ModuleDescriptor>()
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<KtFile>,
trace: BindingTrace,
configuration: CompilerConfiguration,
packagePartProvider: (GlobalSearchScope) -> PackagePartProvider,
declarationProviderFactory: (StorageManager, Collection<KtFile>) -> 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<JavaDescriptorResolver>()
@@ -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<LazyTopDownAnalyzer>().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<KtFile>): GlobalSearchScope {
+5
View File
@@ -0,0 +1,5 @@
>>> val x: Pair<Any?, Any?> = 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()
^
@@ -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)