FIR IDE API: add preliminary control of file in-block modifications
In this commit, we build FirFile from the beginning if in-block modifications are detected. However, better way would be to rebuild only part of FirFile in this case
This commit is contained in:
@@ -142,6 +142,7 @@ fun KtFile.getOrBuildFirWithDiagnostics(state: FirResolveState): FirFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ProgressIndicatorProvider.checkCanceled() // ???
|
||||||
if (state.hasDiagnosticsForFile(this)) return firFile
|
if (state.hasDiagnosticsForFile(this)) return firFile
|
||||||
|
|
||||||
FirIdeDiagnosticsCollector(state).collectDiagnostics(firFile)
|
FirIdeDiagnosticsCollector(state).collectDiagnostics(firFile)
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
package org.jetbrains.kotlin.idea.fir
|
package org.jetbrains.kotlin.idea.fir
|
||||||
|
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiElementVisitor
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
import org.jetbrains.kotlin.fir.*
|
import org.jetbrains.kotlin.fir.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||||
@@ -75,7 +77,7 @@ class FirResolveStateImpl(override val sessionProvider: FirSessionProvider) : Fi
|
|||||||
|
|
||||||
private val diagnosticCache = mutableMapOf<KtElement, MutableList<Diagnostic>>()
|
private val diagnosticCache = mutableMapOf<KtElement, MutableList<Diagnostic>>()
|
||||||
|
|
||||||
private val diagnosedFiles = mutableSetOf<KtFile>()
|
private val diagnosedFiles = mutableMapOf<KtFile, Long>()
|
||||||
|
|
||||||
override fun get(psi: KtElement): FirElement? = cache[psi]
|
override fun get(psi: KtElement): FirElement? = cache[psi]
|
||||||
|
|
||||||
@@ -84,7 +86,20 @@ class FirResolveStateImpl(override val sessionProvider: FirSessionProvider) : Fi
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun hasDiagnosticsForFile(file: KtFile): Boolean {
|
override fun hasDiagnosticsForFile(file: KtFile): Boolean {
|
||||||
return file in diagnosedFiles
|
val previousStamp = diagnosedFiles[file] ?: return false
|
||||||
|
if (file.modificationStamp == previousStamp) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
diagnosedFiles.remove(file)
|
||||||
|
file.accept(object : PsiElementVisitor() {
|
||||||
|
override fun visitElement(element: PsiElement) {
|
||||||
|
cache.remove(element)
|
||||||
|
diagnosticCache.remove(element)
|
||||||
|
element.acceptChildren(this)
|
||||||
|
super.visitElement(element)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun record(psi: KtElement, fir: FirElement) {
|
override fun record(psi: KtElement, fir: FirElement) {
|
||||||
@@ -101,7 +116,7 @@ class FirResolveStateImpl(override val sessionProvider: FirSessionProvider) : Fi
|
|||||||
(diagnostic.source.psi as? KtElement)?.let { record(it, diagnostic.diagnostic) }
|
(diagnostic.source.psi as? KtElement)?.let { record(it, diagnostic.diagnostic) }
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnosedFiles += file
|
diagnosedFiles[file] = file.modificationStamp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,8 +32,10 @@ class IdeFirProvider(
|
|||||||
val session: FirSession
|
val session: FirSession
|
||||||
) : FirProvider() {
|
) : FirProvider() {
|
||||||
private val cacheProvider = FirProviderImpl(session)
|
private val cacheProvider = FirProviderImpl(session)
|
||||||
// TODO: invalidation?
|
|
||||||
private val files = mutableMapOf<KtFile, FirFile>()
|
data class FirFileWithStamp(val file: FirFile, val stamp: Long)
|
||||||
|
|
||||||
|
private val files = mutableMapOf<KtFile, FirFileWithStamp>()
|
||||||
|
|
||||||
override fun getFirClassifierByFqName(classId: ClassId): FirClassLikeDeclaration<*>? {
|
override fun getFirClassifierByFqName(classId: ClassId): FirClassLikeDeclaration<*>? {
|
||||||
return cacheProvider.getFirClassifierByFqName(classId) ?: run {
|
return cacheProvider.getFirClassifierByFqName(classId) ?: run {
|
||||||
@@ -54,17 +56,31 @@ class IdeFirProvider(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getOrBuildFile(ktFile: KtFile): FirFile {
|
fun getOrBuildFile(ktFile: KtFile): FirFile {
|
||||||
files[ktFile]?.let { return it }
|
val modificationStamp = ktFile.modificationStamp
|
||||||
|
files[ktFile]?.let { (firFile, stamp) ->
|
||||||
|
if (stamp == modificationStamp) {
|
||||||
|
return firFile
|
||||||
|
}
|
||||||
|
}
|
||||||
return synchronized(ktFile) {
|
return synchronized(ktFile) {
|
||||||
files.getOrPut(ktFile) {
|
var fileWithStamp = files[ktFile]
|
||||||
|
if (fileWithStamp != null && fileWithStamp.stamp == modificationStamp) {
|
||||||
|
fileWithStamp.file
|
||||||
|
} else {
|
||||||
val file = RawFirBuilder(session, stubMode = false).buildFirFile(ktFile)
|
val file = RawFirBuilder(session, stubMode = false).buildFirFile(ktFile)
|
||||||
cacheProvider.recordFile(file)
|
cacheProvider.recordFile(file)
|
||||||
|
fileWithStamp = FirFileWithStamp(file, modificationStamp)
|
||||||
|
files[ktFile] = fileWithStamp
|
||||||
file
|
file
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getFile(ktFile: KtFile): FirFile? = files[ktFile]
|
fun getFile(ktFile: KtFile): FirFile? {
|
||||||
|
val (firFile, stamp) = files[ktFile] ?: return null
|
||||||
|
if (stamp == ktFile.modificationStamp) return firFile
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
override fun getClassLikeSymbolByFqName(classId: ClassId): FirClassLikeSymbol<*>? {
|
override fun getClassLikeSymbolByFqName(classId: ClassId): FirClassLikeSymbol<*>? {
|
||||||
return getFirClassifierByFqName(classId)?.symbol
|
return getFirClassifierByFqName(classId)?.symbol
|
||||||
|
|||||||
Reference in New Issue
Block a user