FIR IDE: collect diagnostics context under read lock

This commit is contained in:
Ilya Kirillov
2021-03-25 16:59:29 +01:00
parent ce62348709
commit ac993754e1
5 changed files with 53 additions and 23 deletions
@@ -12,17 +12,28 @@ import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.resolve.SessionHolderImpl import org.jetbrains.kotlin.fir.resolve.SessionHolderImpl
import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.fir.PersistenceContextCollector import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.fir.PersistenceContextCollector
import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.fir.PersistentCheckerContextFactory import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.fir.PersistentCheckerContextFactory
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.LockProvider
internal abstract class FileStructureElementDiagnosticRetriever { internal abstract class FileStructureElementDiagnosticRetriever {
abstract fun retrieve(firFile: FirFile, collector: FileStructureElementDiagnosticsCollector): FileStructureElementDiagnosticList abstract fun retrieve(
firFile: FirFile,
collector: FileStructureElementDiagnosticsCollector,
lockProvider: LockProvider<FirFile>
): FileStructureElementDiagnosticList
} }
internal class SingleNonLocalDeclarationDiagnosticRetriever( internal class SingleNonLocalDeclarationDiagnosticRetriever (
private val declaration: FirDeclaration private val declaration: FirDeclaration
) : FileStructureElementDiagnosticRetriever() { ) : FileStructureElementDiagnosticRetriever() {
override fun retrieve(firFile: FirFile, collector: FileStructureElementDiagnosticsCollector): FileStructureElementDiagnosticList { override fun retrieve(
firFile: FirFile,
collector: FileStructureElementDiagnosticsCollector,
lockProvider: LockProvider<FirFile>
): FileStructureElementDiagnosticList {
val sessionHolder = SessionHolderImpl.createWithEmptyScopeSession(firFile.session) val sessionHolder = SessionHolderImpl.createWithEmptyScopeSession(firFile.session)
val context = PersistenceContextCollector.collectContext(sessionHolder, firFile, declaration) val context = lockProvider.withReadLock(firFile) {
PersistenceContextCollector.collectContext(sessionHolder, firFile, declaration)
}
return collector.collectForStructureElement(declaration) { components -> return collector.collectForStructureElement(declaration) { components ->
FirIdeDiagnosticVisitor(context, components) FirIdeDiagnosticVisitor(context, components)
} }
@@ -30,7 +41,11 @@ internal class SingleNonLocalDeclarationDiagnosticRetriever(
} }
internal object FileDiagnosticRetriever : FileStructureElementDiagnosticRetriever() { internal object FileDiagnosticRetriever : FileStructureElementDiagnosticRetriever() {
override fun retrieve(firFile: FirFile, collector: FileStructureElementDiagnosticsCollector): FileStructureElementDiagnosticList = override fun retrieve(
firFile: FirFile,
collector: FileStructureElementDiagnosticsCollector,
lockProvider: LockProvider<FirFile>
): FileStructureElementDiagnosticList =
collector.collectForStructureElement(firFile) { components -> collector.collectForStructureElement(firFile) { components ->
Visitor(firFile, components) Visitor(firFile, components)
} }
@@ -10,18 +10,19 @@ import com.intellij.util.SmartList
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.idea.fir.low.level.api.api.DiagnosticCheckerFilter import org.jetbrains.kotlin.idea.fir.low.level.api.api.DiagnosticCheckerFilter
import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.FileStructureElement import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.LockProvider
internal class FileStructureElementDiagnostics( internal class FileStructureElementDiagnostics(
private val firFile: FirFile, private val firFile: FirFile,
private val lockProvider: LockProvider<FirFile>,
private val retriever: FileStructureElementDiagnosticRetriever private val retriever: FileStructureElementDiagnosticRetriever
) { ) {
private val diagnosticByCommonCheckers: FileStructureElementDiagnosticList by lazy { private val diagnosticByCommonCheckers: FileStructureElementDiagnosticList by lazy {
retriever.retrieve(firFile, FileStructureElementDiagnosticsCollector.USUAL_COLLECTOR) retriever.retrieve(firFile, FileStructureElementDiagnosticsCollector.USUAL_COLLECTOR, lockProvider)
} }
private val diagnosticByExtendedCheckers: FileStructureElementDiagnosticList by lazy { private val diagnosticByExtendedCheckers: FileStructureElementDiagnosticList by lazy {
retriever.retrieve(firFile, FileStructureElementDiagnosticsCollector.EXTENDED_COLLECTOR) retriever.retrieve(firFile, FileStructureElementDiagnosticsCollector.EXTENDED_COLLECTOR, lockProvider)
} }
fun diagnosticsFor(filter: DiagnosticCheckerFilter, element: PsiElement): List<FirPsiDiagnostic<*>> = fun diagnosticsFor(filter: DiagnosticCheckerFilter, element: PsiElement): List<FirPsiDiagnostic<*>> =
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirProperty import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.LockProvider
import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtProperty import org.jetbrains.kotlin.psi.KtProperty
@@ -21,25 +22,29 @@ internal object FileElementFactory {
firDeclaration: FirDeclaration, firDeclaration: FirDeclaration,
ktDeclaration: KtDeclaration, ktDeclaration: KtDeclaration,
firFile: FirFile, firFile: FirFile,
firFileLockProvider: LockProvider<FirFile>,
): FileStructureElement = when { ): FileStructureElement = when {
ktDeclaration is KtNamedFunction && ktDeclaration.isReanalyzableContainer() -> ReanalyzableFunctionStructureElement( ktDeclaration is KtNamedFunction && ktDeclaration.isReanalyzableContainer() -> ReanalyzableFunctionStructureElement(
firFile, firFile,
ktDeclaration, ktDeclaration,
(firDeclaration as FirSimpleFunction).symbol, (firDeclaration as FirSimpleFunction).symbol,
ktDeclaration.modificationStamp ktDeclaration.modificationStamp,
firFileLockProvider,
) )
ktDeclaration is KtProperty && ktDeclaration.isReanalyzableContainer() -> ReanalyzablePropertyStructureElement( ktDeclaration is KtProperty && ktDeclaration.isReanalyzableContainer() -> ReanalyzablePropertyStructureElement(
firFile, firFile,
ktDeclaration, ktDeclaration,
(firDeclaration as FirProperty).symbol, (firDeclaration as FirProperty).symbol,
ktDeclaration.modificationStamp ktDeclaration.modificationStamp,
firFileLockProvider,
) )
else -> NonReanalyzableDeclarationStructureElement( else -> NonReanalyzableDeclarationStructureElement(
firFile, firFile,
firDeclaration, firDeclaration,
ktDeclaration, ktDeclaration,
firFileLockProvider,
) )
} }
@@ -115,7 +115,7 @@ internal class FileStructure(
towerDataContextCollector = collector towerDataContextCollector = collector
) )
return moduleFileCache.firFileLockProvider.withReadLock(firFile) { return moduleFileCache.firFileLockProvider.withReadLock(firFile) {
FileElementFactory.createFileStructureElement(firDeclaration, declaration, firFile) FileElementFactory.createFileStructureElement(firDeclaration, declaration, firFile, moduleFileCache.firFileLockProvider)
} }
} }
@@ -133,6 +133,7 @@ internal class FileStructure(
RootStructureElement( RootStructureElement(
firFile, firFile,
container, container,
moduleFileCache.firFileLockProvider,
) )
} }
is KtDeclaration -> createDeclarationStructure(container) is KtDeclaration -> createDeclarationStructure(container)
@@ -15,22 +15,24 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.FileDiagnosticRet
import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.FileStructureElementDiagnostics import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.FileStructureElementDiagnostics
import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.SingleNonLocalDeclarationDiagnosticRetriever import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.SingleNonLocalDeclarationDiagnosticRetriever
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerDataContextCollector import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerDataContextCollector
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.LockProvider
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache
import org.jetbrains.kotlin.idea.fir.low.level.api.lazy.resolve.FirLazyDeclarationResolver import org.jetbrains.kotlin.idea.fir.low.level.api.lazy.resolve.FirLazyDeclarationResolver
import org.jetbrains.kotlin.idea.fir.low.level.api.providers.FirIdeProvider import org.jetbrains.kotlin.idea.fir.low.level.api.providers.FirIdeProvider
import org.jetbrains.kotlin.idea.fir.low.level.api.util.hasFqName import org.jetbrains.kotlin.idea.fir.low.level.api.util.hasFqName
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
internal sealed class FileStructureElement(val firFile: FirFile) { internal sealed class FileStructureElement(val firFile: FirFile, protected val lockProvider: LockProvider<FirFile>) {
abstract val psi: KtAnnotated abstract val psi: KtAnnotated
abstract val mappings: Map<KtElement, FirElement> abstract val mappings: Map<KtElement, FirElement>
abstract val diagnostics: FileStructureElementDiagnostics abstract val diagnostics: FileStructureElementDiagnostics
} }
internal sealed class ReanalyzableStructureElement<KT : KtDeclaration, S: AbstractFirBasedSymbol<*>>( internal sealed class ReanalyzableStructureElement<KT : KtDeclaration, S : AbstractFirBasedSymbol<*>>(
firFile: FirFile, firFile: FirFile,
protected val firSymbol: S, protected val firSymbol: S,
) : FileStructureElement(firFile) { lockProvider: LockProvider<FirFile>,
) : FileStructureElement(firFile, lockProvider) {
abstract override val psi: KtDeclaration abstract override val psi: KtDeclaration
abstract val timestamp: Long abstract val timestamp: Long
@@ -48,7 +50,7 @@ internal sealed class ReanalyzableStructureElement<KT : KtDeclaration, S: Abstra
fun isUpToDate(): Boolean = psi.getModificationStamp() == timestamp fun isUpToDate(): Boolean = psi.getModificationStamp() == timestamp
override val diagnostics = FileStructureElementDiagnostics(firFile, SingleNonLocalDeclarationDiagnosticRetriever(firSymbol.fir as FirDeclaration)) override val diagnostics = FileStructureElementDiagnostics(firFile, lockProvider, SingleNonLocalDeclarationDiagnosticRetriever(firSymbol.fir as FirDeclaration))
companion object { companion object {
val recorder = FirElementsRecorder() val recorder = FirElementsRecorder()
@@ -59,8 +61,9 @@ internal class ReanalyzableFunctionStructureElement(
firFile: FirFile, firFile: FirFile,
override val psi: KtNamedFunction, override val psi: KtNamedFunction,
firSymbol: FirFunctionSymbol<*>, firSymbol: FirFunctionSymbol<*>,
override val timestamp: Long override val timestamp: Long,
) : ReanalyzableStructureElement<KtNamedFunction, FirFunctionSymbol<*>>(firFile, firSymbol) { lockProvider: LockProvider<FirFile>,
) : ReanalyzableStructureElement<KtNamedFunction, FirFunctionSymbol<*>>(firFile, firSymbol, lockProvider) {
override val mappings: Map<KtElement, FirElement> = override val mappings: Map<KtElement, FirElement> =
FirElementsRecorder.recordElementsFrom(firSymbol.fir, recorder) FirElementsRecorder.recordElementsFrom(firSymbol.fir, recorder)
@@ -89,6 +92,7 @@ internal class ReanalyzableFunctionStructureElement(
newKtDeclaration, newKtDeclaration,
newFunction.symbol, newFunction.symbol,
newKtDeclaration.modificationStamp, newKtDeclaration.modificationStamp,
lockProvider,
) )
} }
} }
@@ -99,8 +103,9 @@ internal class ReanalyzablePropertyStructureElement(
firFile: FirFile, firFile: FirFile,
override val psi: KtProperty, override val psi: KtProperty,
firSymbol: FirPropertySymbol, firSymbol: FirPropertySymbol,
override val timestamp: Long override val timestamp: Long,
) : ReanalyzableStructureElement<KtProperty, FirPropertySymbol>(firFile, firSymbol) { lockProvider: LockProvider<FirFile>,
) : ReanalyzableStructureElement<KtProperty, FirPropertySymbol>(firFile, firSymbol, lockProvider) {
override val mappings: Map<KtElement, FirElement> = override val mappings: Map<KtElement, FirElement> =
FirElementsRecorder.recordElementsFrom(firSymbol.fir, recorder) FirElementsRecorder.recordElementsFrom(firSymbol.fir, recorder)
@@ -129,6 +134,7 @@ internal class ReanalyzablePropertyStructureElement(
newKtDeclaration, newKtDeclaration,
newProperty.symbol, newProperty.symbol,
newKtDeclaration.modificationStamp, newKtDeclaration.modificationStamp,
lockProvider,
) )
} }
} }
@@ -139,11 +145,12 @@ internal class NonReanalyzableDeclarationStructureElement(
firFile: FirFile, firFile: FirFile,
fir: FirDeclaration, fir: FirDeclaration,
override val psi: KtDeclaration, override val psi: KtDeclaration,
) : FileStructureElement(firFile) { lockProvider: LockProvider<FirFile>,
) : FileStructureElement(firFile, lockProvider) {
override val mappings: Map<KtElement, FirElement> = override val mappings: Map<KtElement, FirElement> =
FirElementsRecorder.recordElementsFrom(fir, recorder) FirElementsRecorder.recordElementsFrom(fir, recorder)
override val diagnostics = FileStructureElementDiagnostics(firFile, SingleNonLocalDeclarationDiagnosticRetriever(fir)) override val diagnostics = FileStructureElementDiagnostics(firFile, lockProvider, SingleNonLocalDeclarationDiagnosticRetriever(fir))
companion object { companion object {
@@ -169,11 +176,12 @@ internal class NonReanalyzableDeclarationStructureElement(
internal class RootStructureElement( internal class RootStructureElement(
firFile: FirFile, firFile: FirFile,
override val psi: KtFile, override val psi: KtFile,
) : FileStructureElement(firFile) { lockProvider: LockProvider<FirFile>,
) : FileStructureElement(firFile, lockProvider) {
override val mappings: Map<KtElement, FirElement> = override val mappings: Map<KtElement, FirElement> =
FirElementsRecorder.recordElementsFrom(firFile, recorder) FirElementsRecorder.recordElementsFrom(firFile, recorder)
override val diagnostics = FileStructureElementDiagnostics(firFile, FileDiagnosticRetriever) override val diagnostics = FileStructureElementDiagnostics(firFile, lockProvider, FileDiagnosticRetriever)
companion object { companion object {
private val recorder = object : FirElementsRecorder() { private val recorder = object : FirElementsRecorder() {