diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt index 52459e75faa..4389aa6a515 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt @@ -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): 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()?.sdk - private fun createFacadeForFilesWithSpecialModuleInfo(files: Set): 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()?.sdk \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/util/globalContextUtils.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/util/globalContextUtils.kt index 171c0692c30..cf72031daa3 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/util/globalContextUtils.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/util/globalContextUtils.kt @@ -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)