[LL API] Streamline target declaration processing
This commit is contained in:
+26
-25
@@ -9,10 +9,7 @@ import com.intellij.openapi.progress.ProgressManager
|
|||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import kotlinx.collections.immutable.PersistentMap
|
import kotlinx.collections.immutable.PersistentMap
|
||||||
import kotlinx.collections.immutable.persistentMapOf
|
import kotlinx.collections.immutable.persistentMapOf
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignationWithFile
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignation
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirResolveTarget
|
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirWholeFileResolveTarget
|
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.asResolveTarget
|
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.getNonLocalContainingOrThisDeclaration
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.getNonLocalContainingOrThisDeclaration
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.ContextCollector.ContextKind
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.ContextCollector.ContextKind
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.ContextCollector.Context
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.ContextCollector.Context
|
||||||
@@ -64,7 +61,7 @@ internal object ContextCollector {
|
|||||||
* Get the most precise context available for the [targetElement] in the [file].
|
* Get the most precise context available for the [targetElement] in the [file].
|
||||||
*
|
*
|
||||||
* @param file The file to process.
|
* @param file The file to process.
|
||||||
* @param holder A [SessionHolder] for the session that owns a [file].
|
* @param holder The [SessionHolder] for the session that owns a [file].
|
||||||
* @param targetElement The most precise element for which the context is required.
|
* @param targetElement The most precise element for which the context is required.
|
||||||
* @param bodyElement An element for which the [ContextKind.BODY] context is preferred.
|
* @param bodyElement An element for which the [ContextKind.BODY] context is preferred.
|
||||||
*
|
*
|
||||||
@@ -75,7 +72,7 @@ internal object ContextCollector {
|
|||||||
val isBodyContextCollected = bodyElement != null
|
val isBodyContextCollected = bodyElement != null
|
||||||
val acceptedElements = targetElement.parentsWithSelf.toSet()
|
val acceptedElements = targetElement.parentsWithSelf.toSet()
|
||||||
|
|
||||||
val contextProvider = process(computeResolveTarget(file, targetElement), holder, isBodyContextCollected) { candidate ->
|
val contextProvider = process(file, computeDesignation(file, targetElement), holder, isBodyContextCollected) { candidate ->
|
||||||
when (candidate) {
|
when (candidate) {
|
||||||
targetElement -> FilterResponse.STOP
|
targetElement -> FilterResponse.STOP
|
||||||
in acceptedElements -> FilterResponse.CONTINUE
|
in acceptedElements -> FilterResponse.CONTINUE
|
||||||
@@ -100,44 +97,52 @@ internal object ContextCollector {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun computeResolveTarget(file: FirFile, targetElement: PsiElement): LLFirResolveTarget {
|
private fun computeDesignation(file: FirFile, targetElement: PsiElement): FirDesignation? {
|
||||||
val contextKtDeclaration = targetElement.getNonLocalContainingOrThisDeclaration()
|
val contextKtDeclaration = targetElement.getNonLocalContainingOrThisDeclaration()
|
||||||
if (contextKtDeclaration != null) {
|
if (contextKtDeclaration != null) {
|
||||||
val designationPath = FirElementFinder.collectDesignationPath(file, contextKtDeclaration)
|
val designationPath = FirElementFinder.collectDesignationPath(file, contextKtDeclaration)
|
||||||
if (designationPath != null) {
|
if (designationPath != null) {
|
||||||
return FirDesignationWithFile(designationPath.path, designationPath.target, file).asResolveTarget()
|
return FirDesignation(designationPath.path, designationPath.target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return LLFirWholeFileResolveTarget(file)
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processes the [FirFile] that owns the [target], collecting contexts for elements matching the [filter].
|
* Processes the [FirFile], collecting contexts for elements matching the [filter].
|
||||||
*
|
*
|
||||||
* @param target The target to process.
|
* @param file The file to process.
|
||||||
* @param holder The [SessionHolder] for the session that owns a [target].
|
* @param designation The declaration to process. If `null`, all declarations in the [file] are processed.
|
||||||
|
* @param holder The [SessionHolder] for the session that owns a [file].
|
||||||
* @param shouldCollectBodyContext If `true`, [ContextKind.BODY] is collected where available.
|
* @param shouldCollectBodyContext If `true`, [ContextKind.BODY] is collected where available.
|
||||||
* @param filter The filter predicate. Context is collected only for [PsiElement]s for which the [filter] returns `true`.
|
* @param filter The filter predicate. Context is collected only for [PsiElement]s for which the [filter] returns `true`.
|
||||||
*/
|
*/
|
||||||
fun process(
|
fun process(
|
||||||
target: LLFirResolveTarget,
|
file: FirFile,
|
||||||
|
designation: FirDesignation?,
|
||||||
holder: SessionHolder,
|
holder: SessionHolder,
|
||||||
shouldCollectBodyContext: Boolean,
|
shouldCollectBodyContext: Boolean,
|
||||||
filter: (PsiElement) -> FilterResponse
|
filter: (PsiElement) -> FilterResponse
|
||||||
): ContextProvider {
|
): ContextProvider {
|
||||||
val pathIterator = target.path.iterator()
|
val interceptor = designation?.let(::DesignationInterceptor) ?: { null }
|
||||||
|
val visitor = ContextCollectorVisitor(holder, shouldCollectBodyContext, filter, interceptor)
|
||||||
val visitor = ContextCollectorVisitor(holder, shouldCollectBodyContext, filter) {
|
file.accept(visitor)
|
||||||
if (pathIterator.hasNext()) pathIterator.next() else null
|
|
||||||
}
|
|
||||||
|
|
||||||
target.firFile.accept(visitor)
|
|
||||||
visitor.processTarget(target)
|
|
||||||
|
|
||||||
return ContextProvider { element, kind -> visitor[element, kind] }
|
return ContextProvider { element, kind -> visitor[element, kind] }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class DesignationInterceptor(private val designation: FirDesignation) : () -> FirElement? {
|
||||||
|
private val targetIterator = iterator {
|
||||||
|
yieldAll(designation.path)
|
||||||
|
yield(designation.target)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun invoke(): FirElement? {
|
||||||
|
return if (targetIterator.hasNext()) targetIterator.next() else null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun interface ContextProvider {
|
fun interface ContextProvider {
|
||||||
operator fun get(element: PsiElement, kind: ContextKind): Context?
|
operator fun get(element: PsiElement, kind: ContextKind): Context?
|
||||||
}
|
}
|
||||||
@@ -170,10 +175,6 @@ private class ContextCollectorVisitor(
|
|||||||
|
|
||||||
private val result = HashMap<ContextKey, Context>()
|
private val result = HashMap<ContextKey, Context>()
|
||||||
|
|
||||||
fun processTarget(target: LLFirResolveTarget) {
|
|
||||||
target.firFile.accept(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitElement(element: FirElement) {
|
override fun visitElement(element: FirElement) {
|
||||||
dumpContext(element.psi, ContextKind.SELF)
|
dumpContext(element.psi, ContextKind.SELF)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user