[LL API] Analyze code fragment in a separate 'FirSession'

Before, `KtCodeFragment`/`FirCodeFragment` was analyzed as a part of
its context `KtModule`. This has the following complications:

- In non-source sessions, diagnostic reporting is globally disabled.
  For code fragments, however, checking the code before passing it to
  the backend is essential.

- Special treatment for call ambiguities in libraries
  (`LLLibraryScopeAwareCallConflictResolverFactory`) becomes complicated
  as the conflict resolver has to be applied to a library module.

- `KtCodeFragment`s usually have a shorter lifetime than their own
  context. Caching may potentially be implemented differently for them.

^KT-61783 Fixed
This commit is contained in:
Yan Zhulanow
2023-09-04 22:16:33 +09:00
committed by Space Team
parent b32c083346
commit 715f7d1a35
10 changed files with 250 additions and 26 deletions
@@ -10,6 +10,7 @@ import com.intellij.psi.PsiFile
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.psi.KtCodeFragment
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
import java.nio.file.Path
@@ -214,6 +215,24 @@ public interface KtScriptDependencyModule : KtModule {
public val file: KtFile?
}
/**
* A module for a Kotlin code fragment a piece of code analyzed against a specific context element.
*/
public interface KtCodeFragmentModule : KtModule {
/**
* A code fragment PSI.
*/
public val codeFragment: KtCodeFragment
/**
* Module of the context element.
*/
public val contextModule: KtModule
override val moduleDescription: String
get() = "Code fragment"
}
/**
* A set of sources which live outside the project content root. E.g, testdata files or source files of some other project.
*/
@@ -0,0 +1,58 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.analysis.project.structure.impl
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analysis.project.structure.KtCodeFragmentModule
import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.psi.KtCodeFragment
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
import java.util.Objects
public class KtCodeFragmentModuleImpl(
override val codeFragment: KtCodeFragment,
override val contextModule: KtModule
) : KtCodeFragmentModule {
override val project: Project
get() = contextModule.project
override val platform: TargetPlatform
get() = contextModule.platform
override val analyzerServices: PlatformDependentAnalyzerServices
get() = contextModule.analyzerServices
override val contentScope: GlobalSearchScope
get() = GlobalSearchScope.fileScope(codeFragment)
override val directRegularDependencies: List<KtModule>
get() = contextModule.directRegularDependencies
override val directDependsOnDependencies: List<KtModule>
get() = contextModule.directDependsOnDependencies
override val directFriendDependencies: List<KtModule>
get() = listOf(contextModule) + contextModule.directFriendDependencies
override val transitiveDependsOnDependencies: List<KtModule>
get() = contextModule.transitiveDependsOnDependencies
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other is KtCodeFragmentModuleImpl) {
return codeFragment == other.codeFragment && contextModule == other.contextModule
}
return false
}
override fun hashCode(): Int {
return Objects.hash(codeFragment, contextModule)
}
}