[Resolve] Introduce CompositeAnalysisSettings

Because we want to support both COMPOSITE and SEPARATE resolution modes
at once, we have to leave 'globalFacadesPerPlatformAndSdk'-map, but in
COMPOSITE mode it should use less parameters for that map, and, in
particular, we shouldn't use Platform and SDK for equality.

This commit introduces separate instance which should be used in
COMPOSITE mode.

COMPOSITE mode itself will be introduced in the following commits.
This commit is contained in:
Dmitry Savvinov
2019-06-17 17:16:25 +03:00
parent 5e95890028
commit adb0f5eaf9
2 changed files with 80 additions and 48 deletions
@@ -50,6 +50,7 @@ import org.jetbrains.kotlin.idea.compiler.IDELanguageSettingsProvider
import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesModificationTracker
import org.jetbrains.kotlin.idea.core.script.dependencies.ScriptAdditionalIdeaDependenciesProvider
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
import org.jetbrains.kotlin.idea.project.useCompositeAnalysis
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.platform.TargetPlatform
@@ -64,16 +65,47 @@ import org.jetbrains.kotlin.utils.addToStdlib.sumByLong
internal val LOG = Logger.getInstance(KotlinCacheService::class.java)
// For every different instance of these settings we must create a different builtIns instance and thus a different moduleDescriptor graph
// since in the current implementation types from one module are leaking into other modules' resolution
// meaning that we can't just change those setting on a per module basis
data class PlatformAnalysisSettings(
val platform: TargetPlatform, val sdk: Sdk?,
val isAdditionalBuiltInFeaturesSupported: Boolean,
/**
* Regulates what sources should be analyzed together.
*
* There are exactly two descendants, which are in string one-to-one correspondence with [ResolutionModeComponent.Mode] pick (meaning
* that after checking value of ResolutionMode, it's safe to downcast settings instance to the respective type):
* - [PlatformAnalysisSettingsImpl] should be used iff we're working under [Mode.SEPARATE], and will create separate
* facade for each platforms, sdk, builtIns settings and other stuff.
* This is the old and stable mode, which should be used by default.
*
* - [CompositeAnalysisSettings] should be used iff we're working under [Mode.COMPOSITE], and will analyze all sources
* together, in one facade.
* This mode is new and experimental, and works only together with TypeRefinement facilities in the compiler's frontend.
* This mode is currently enabled only for HMPP projects
*/
sealed class PlatformAnalysisSettings {
// Effectively unused as a property. Needed only to distinguish different modes when being put in a map
val isReleaseCoroutines: Boolean,
val isTypeRefinementEnabled: Boolean
)
abstract val isReleaseCoroutines: Boolean
companion object {
fun create(
project: Project,
platform: TargetPlatform,
sdk: Sdk?,
isAdditionalBuiltInFeaturesSupported: Boolean,
isReleaseCoroutines: Boolean
) = if (project.useCompositeAnalysis)
CompositeAnalysisSettings(isReleaseCoroutines)
else
PlatformAnalysisSettingsImpl(platform, sdk, isAdditionalBuiltInFeaturesSupported, isReleaseCoroutines)
}
}
data class PlatformAnalysisSettingsImpl(
val platform: TargetPlatform,
val sdk: Sdk?,
val isAdditionalBuiltInFeaturesSupported: Boolean,
override val isReleaseCoroutines: Boolean
) : PlatformAnalysisSettings()
data class CompositeAnalysisSettings(override val isReleaseCoroutines: Boolean) : PlatformAnalysisSettings() {
}
class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
override fun getResolutionFacade(elements: List<KtElement>): ResolutionFacade {
@@ -112,10 +144,9 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
): ProjectResolutionFacade {
val sdk = dependenciesModuleInfo.sdk
val platform = JvmPlatforms.defaultJvmPlatform // TODO: Js scripts?
val settings = PlatformAnalysisSettings(
platform, sdk, true,
LanguageFeature.ReleaseCoroutines.defaultState == LanguageFeature.State.ENABLED,
false // TODO: replace with correct value
val settings = PlatformAnalysisSettings.create(
project, platform, sdk, true,
LanguageFeature.ReleaseCoroutines.defaultState == LanguageFeature.State.ENABLED
)
val dependenciesForScriptDependencies = listOf(
@@ -133,7 +164,7 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
getOrBuildGlobalFacade(settings).facadeForSdk
}
val globalContext = globalFacade.globalContext.contextWithCompositeExceptionTracker(settings, "facadeForScriptDependencies")
val globalContext = globalFacade.globalContext.contextWithCompositeExceptionTracker(project, "facadeForScriptDependencies")
return ProjectResolutionFacade(
"facadeForScriptDependencies",
resolverForScriptDependenciesName,
@@ -152,7 +183,7 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
private inner class GlobalFacade(settings: PlatformAnalysisSettings) {
private val sdkContext = GlobalContext(resolverForSdkName)
val facadeForSdk = ProjectResolutionFacade(
"facadeForSdk", "$resolverForSdkName ${settings.sdk}",
"facadeForSdk", "$resolverForSdkName with settings=$settings",
project, sdkContext, settings,
moduleFilter = { it is SdkInfo },
dependencies = listOf(
@@ -163,9 +194,9 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
reuseDataFrom = null
)
private val librariesContext = sdkContext.contextWithCompositeExceptionTracker(settings, resolverForLibrariesName)
private val librariesContext = sdkContext.contextWithCompositeExceptionTracker(project, resolverForLibrariesName)
val facadeForLibraries = ProjectResolutionFacade(
"facadeForLibraries", "$resolverForLibrariesName for platform ${settings.sdk}",
"facadeForLibraries", "$resolverForLibrariesName with settings=$settings",
project, librariesContext, settings,
reuseDataFrom = facadeForSdk,
moduleFilter = { it is LibraryInfo },
@@ -176,9 +207,9 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
)
)
private val modulesContext = librariesContext.contextWithCompositeExceptionTracker(settings, resolverForModulesName)
private val modulesContext = librariesContext.contextWithCompositeExceptionTracker(project, resolverForModulesName)
val facadeForModules = ProjectResolutionFacade(
"facadeForModules", "$resolverForModulesName for platform ${settings.platform}",
"facadeForModules", "$resolverForModulesName with settings=$settings",
project, modulesContext, settings,
reuseDataFrom = facadeForLibraries,
moduleFilter = { !it.isLibraryClasses() },
@@ -190,31 +221,18 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
)
}
private fun IdeaModuleInfo.platformSettings(targetPlatform: TargetPlatform) = PlatformAnalysisSettings(
targetPlatform, sdk,
supportsAdditionalBuiltInsMembers(),
isReleaseCoroutines(),
isTypeRefinementEnabled()
private fun IdeaModuleInfo.platformSettings(targetPlatform: TargetPlatform) = PlatformAnalysisSettings.create(
project, targetPlatform, sdk,
supportsAdditionalBuiltInsMembers(project),
isReleaseCoroutines()
)
private fun IdeaModuleInfo.supportsAdditionalBuiltInsMembers(): Boolean {
return IDELanguageSettingsProvider
.getLanguageVersionSettings(this, project)
.supportsFeature(LanguageFeature.AdditionalBuiltInsMembers)
}
private fun IdeaModuleInfo.isReleaseCoroutines(): Boolean {
return IDELanguageSettingsProvider
.getLanguageVersionSettings(this, project)
.supportsFeature(LanguageFeature.ReleaseCoroutines)
}
private fun IdeaModuleInfo.isTypeRefinementEnabled(): Boolean {
return IDELanguageSettingsProvider
.getLanguageVersionSettings(this, project)
.isTypeRefinementEnabled()
}
private fun globalFacade(settings: PlatformAnalysisSettings) =
getOrBuildGlobalFacade(settings).facadeForModules
@@ -225,8 +243,6 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
private fun getOrBuildGlobalFacade(settings: PlatformAnalysisSettings) =
globalFacadesPerPlatformAndSdk[settings]
private val IdeaModuleInfo.sdk: Sdk? get() = dependencies().firstIsInstanceOrNull<SdkInfo>()?.sdk
private fun createFacadeForFilesWithSpecialModuleInfo(files: Set<KtFile>): ProjectResolutionFacade {
// we assume that all files come from the same module
val targetPlatform = files.map { TargetPlatformDetector.getPlatform(it) }.toSet().single()
@@ -280,7 +296,8 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
specialModuleInfo is ModuleSourceInfo -> {
val dependentModules = specialModuleInfo.getDependentModules()
val modulesFacade = globalFacade(settings)
val globalContext = modulesFacade.globalContext.contextWithCompositeExceptionTracker(settings, "facadeForSpecialModuleInfo (ModuleSourceInfo)")
val globalContext =
modulesFacade.globalContext.contextWithCompositeExceptionTracker(project, "facadeForSpecialModuleInfo (ModuleSourceInfo)")
makeProjectResolutionFacade(
"facadeForSpecialModuleInfo (ModuleSourceInfo)",
globalContext,
@@ -293,7 +310,10 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
val facadeForScriptDependencies = createFacadeForScriptDependencies(
ScriptDependenciesInfo.ForFile(project, specialModuleInfo.scriptFile, specialModuleInfo.scriptDefinition)
)
val globalContext = facadeForScriptDependencies.globalContext.contextWithCompositeExceptionTracker(settings, "facadeForSpecialModuleInfo (ScriptModuleInfo)")
val globalContext = facadeForScriptDependencies.globalContext.contextWithCompositeExceptionTracker(
project,
"facadeForSpecialModuleInfo (ScriptModuleInfo)"
)
makeProjectResolutionFacade(
"facadeForSpecialModuleInfo (ScriptModuleInfo)",
globalContext,
@@ -304,7 +324,11 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
}
specialModuleInfo is ScriptDependenciesInfo -> facadeForScriptDependenciesForProject
specialModuleInfo is ScriptDependenciesSourceInfo -> {
val globalContext = facadeForScriptDependenciesForProject.globalContext.contextWithCompositeExceptionTracker(settings, "facadeForSpecialModuleInfo (ScriptDependenciesSourceInfo)")
val globalContext =
facadeForScriptDependenciesForProject.globalContext.contextWithCompositeExceptionTracker(
project,
"facadeForSpecialModuleInfo (ScriptDependenciesSourceInfo)"
)
makeProjectResolutionFacade(
"facadeForSpecialModuleInfo (ScriptDependenciesSourceInfo)",
globalContext,
@@ -317,8 +341,7 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
specialModuleInfo is LibrarySourceInfo || specialModuleInfo === NotUnderContentRootModuleInfo -> {
val librariesFacade = librariesFacade(settings)
val debugName = "facadeForSpecialModuleInfo (LibrarySourceInfo or NotUnderContentRootModuleInfo)"
val globalContext = librariesFacade.globalContext.contextWithCompositeExceptionTracker(settings, debugName)
val globalContext = librariesFacade.globalContext.contextWithCompositeExceptionTracker(project, debugName)
makeProjectResolutionFacade(
debugName,
globalContext,
@@ -361,11 +384,11 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
when (annotated) {
is KtFile -> {
annotated.fileAnnotationList?.analyze(BodyResolveMode.PARTIAL)
?: return emptyList()
?: return emptyList()
}
is KtModifierListOwner -> {
annotated.modifierList?.analyze(BodyResolveMode.PARTIAL)
?: return emptyList()
?: return emptyList()
}
else ->
annotated.analyze(BodyResolveMode.PARTIAL)
@@ -496,7 +519,7 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
private fun KtCodeFragment.getContextFile(): KtFile? {
val contextElement = context ?: return null
val contextFile = (contextElement as? KtElement)?.containingKtFile
?: throw AssertionError("Analyzing kotlin code fragment of type ${this::class.java} with java context of type ${contextElement::class.java}")
?: throw AssertionError("Analyzing kotlin code fragment of type ${this::class.java} with java context of type ${contextElement::class.java}")
return if (contextFile is KtCodeFragment) contextFile.getContextFile() else contextFile
}
@@ -505,3 +528,10 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
}
}
fun IdeaModuleInfo.supportsAdditionalBuiltInsMembers(project: Project): Boolean {
return IDELanguageSettingsProvider
.getLanguageVersionSettings(this, project)
.supportsFeature(LanguageFeature.AdditionalBuiltInsMembers)
}
val IdeaModuleInfo.sdk: Sdk? get() = dependencies().firstIsInstanceOrNull<SdkInfo>()?.sdk
@@ -5,8 +5,10 @@
package org.jetbrains.kotlin.idea.caches.resolve.util
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.context.GlobalContextImpl
import org.jetbrains.kotlin.idea.caches.resolve.PlatformAnalysisSettings
import org.jetbrains.kotlin.idea.project.useCompositeAnalysis
import org.jetbrains.kotlin.storage.ExceptionTracker
import org.jetbrains.kotlin.storage.LockBasedStorageManager
@@ -26,8 +28,8 @@ private fun GlobalContextImpl.contextWithNewLockAndCompositeExceptionTracker(deb
)
}
internal fun GlobalContextImpl.contextWithCompositeExceptionTracker(settings: PlatformAnalysisSettings, debugName: String): GlobalContextImpl =
if (settings.isTypeRefinementEnabled) {
internal fun GlobalContextImpl.contextWithCompositeExceptionTracker(project: Project, debugName: String): GlobalContextImpl =
if (project.useCompositeAnalysis) {
this.contextWithCompositeExceptionTracker(debugName)
} else {
this.contextWithNewLockAndCompositeExceptionTracker(debugName)