[Analysis API] Remove 'FirTowerContextProvider'
The only implementation of 'FirTowerContextProvider' that is not obsolete is inside the reference shortener.
This commit is contained in:
+9
-11
@@ -25,7 +25,6 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.resolveToFirSymbol
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolver.AllCandidatesResolver
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.ContextCollector
|
||||
import org.jetbrains.kotlin.analysis.utils.printer.parentOfType
|
||||
@@ -95,7 +94,7 @@ internal class KtFirReferenceShortener(
|
||||
kDocQualifiersToShorten = emptyList(),
|
||||
)
|
||||
|
||||
val towerContext = FirTowerContextProviderByContextCollector.create(firResolveSession, declarationToVisit)
|
||||
val towerContext = FirTowerDataContextProvider.create(firResolveSession, declarationToVisit)
|
||||
|
||||
//TODO: collect all usages of available symbols in the file and prevent importing symbols that could introduce name clashes, which
|
||||
// may alter the meaning of existing code.
|
||||
@@ -156,12 +155,11 @@ internal class KtFirReferenceShortener(
|
||||
private fun buildSymbol(firSymbol: FirBasedSymbol<*>): KtSymbol = analysisSession.firSymbolBuilder.buildSymbol(firSymbol)
|
||||
}
|
||||
|
||||
private class FirTowerContextProviderByContextCollector private constructor(
|
||||
private class FirTowerDataContextProvider private constructor(
|
||||
private val contextProvider: ContextCollector.ContextProvider
|
||||
) : FirTowerContextProvider {
|
||||
|
||||
) {
|
||||
companion object {
|
||||
fun create(firResolveSession: LLFirResolveSession, targetElement: KtElement): FirTowerContextProviderByContextCollector {
|
||||
fun create(firResolveSession: LLFirResolveSession, targetElement: KtElement): FirTowerDataContextProvider {
|
||||
val firFile = targetElement.containingKtFile.getOrBuildFirFile(firResolveSession)
|
||||
|
||||
val sessionHolder = run {
|
||||
@@ -181,11 +179,11 @@ private class FirTowerContextProviderByContextCollector private constructor(
|
||||
filter = { ContextCollector.FilterResponse.CONTINUE }
|
||||
)
|
||||
|
||||
return FirTowerContextProviderByContextCollector(contextProvider)
|
||||
return FirTowerDataContextProvider(contextProvider)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getClosestAvailableParentContext(ktElement: KtElement): FirTowerDataContext? {
|
||||
fun getClosestAvailableParentContext(ktElement: KtElement): FirTowerDataContext? {
|
||||
for (parent in ktElement.parentsWithSelf) {
|
||||
val context = contextProvider[parent, ContextCollector.ContextKind.SELF]
|
||||
|
||||
@@ -343,7 +341,7 @@ private class FirShorteningContext(val analysisSession: KtFirAnalysisSession) {
|
||||
fun findScopesAtPosition(
|
||||
position: KtElement,
|
||||
newImports: Sequence<FqName>,
|
||||
towerContextProvider: FirTowerContextProvider,
|
||||
towerContextProvider: FirTowerDataContextProvider,
|
||||
withImplicitReceivers: Boolean = true,
|
||||
): List<FirScope>? {
|
||||
val towerDataContext = towerContextProvider.getClosestAvailableParentContext(position) ?: return null
|
||||
@@ -508,7 +506,7 @@ private class CollectingVisitor(private val collector: ElementsToShortenCollecto
|
||||
private class ElementsToShortenCollector(
|
||||
private val shortenOptions: ShortenOptions,
|
||||
private val shorteningContext: FirShorteningContext,
|
||||
private val towerContextProvider: FirTowerContextProvider,
|
||||
private val towerContextProvider: FirTowerDataContextProvider,
|
||||
private val containingFile: KtFile,
|
||||
private val selection: TextRange,
|
||||
private val classShortenStrategy: (FirClassLikeSymbol<*>) -> ShortenStrategy,
|
||||
@@ -978,7 +976,7 @@ private class ElementsToShortenCollector(
|
||||
val shortClassName = classToImport.shortClassName
|
||||
if (expression.getReferencedNameAsName() != shortClassName) return
|
||||
|
||||
val contextProvider = FirTowerContextProviderByContextCollector.create(firResolveSession, expression)
|
||||
val contextProvider = FirTowerDataContextProvider.create(firResolveSession, expression)
|
||||
val positionScopes = shorteningContext.findScopesAtPosition(expression, getNamesToImport(), contextProvider) ?: return
|
||||
val availableClassifier = shorteningContext.findFirstClassifierInScopesByName(positionScopes, shortClassName) ?: return
|
||||
when {
|
||||
|
||||
-1
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.api
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLDiagnosticProvider
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLModuleResolutionStrategyProvider
|
||||
|
||||
-172
@@ -1,172 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.low.level.api.fir.element.builder
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.originalDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirTowerDataContext
|
||||
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||
import org.jetbrains.kotlin.fir.psi
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.BodyResolveContext
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirResolveContextCollector
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
interface FirTowerContextProvider {
|
||||
fun getClosestAvailableParentContext(ktElement: KtElement): FirTowerDataContext?
|
||||
}
|
||||
|
||||
internal class FileTowerProvider(
|
||||
private val file: KtFile,
|
||||
private val context: FirTowerDataContext,
|
||||
) : FirTowerContextProvider {
|
||||
override fun getClosestAvailableParentContext(ktElement: KtElement): FirTowerDataContext? =
|
||||
if (file == ktElement.containingKtFile) context else null
|
||||
}
|
||||
|
||||
internal class FirTowerDataContextAllElementsCollector : FirResolveContextCollector, FirTowerContextProvider {
|
||||
private val elementsToContext: MutableMap<KtElement, FirTowerDataContext> = hashMapOf()
|
||||
|
||||
/**
|
||||
* Class headers have context which is different from the context inside of the class, so we have
|
||||
* to collect the scopes for it separately.
|
||||
*
|
||||
* See [containsInHeader] for more info.
|
||||
*/
|
||||
private val classesToClassHeaderContext: MutableMap<KtClassOrObject, FirTowerDataContext> = hashMapOf()
|
||||
|
||||
override fun addFileContext(file: FirFile, context: FirTowerDataContext) {
|
||||
val ktFile = file.psi as? KtFile ?: return
|
||||
elementsToContext[ktFile] = context
|
||||
}
|
||||
|
||||
override fun addStatementContext(statement: FirStatement, context: BodyResolveContext) {
|
||||
val closestParentExpression = statement.psi?.closestParentExpressionWithSameContextOrSelf() ?: return
|
||||
// FIR body transform may alter the context if there are implicit receivers with smartcast
|
||||
elementsToContext[closestParentExpression] = context.towerDataContext.createSnapshot(keepMutable = false)
|
||||
}
|
||||
|
||||
override fun addDeclarationContext(declaration: FirDeclaration, context: BodyResolveContext) {
|
||||
val psi = declaration.psi as? KtElement ?: return
|
||||
|
||||
// FIR creates a fake field declaration for the delegated super calls,
|
||||
// and it makes handling class headers more difficult, so
|
||||
// we do not collect contexts for such declarations
|
||||
if (psi is KtDelegatedSuperTypeEntry) return
|
||||
|
||||
elementsToContext[psi] = context.towerDataContext.createSnapshot(keepMutable = false)
|
||||
}
|
||||
|
||||
override fun addClassHeaderContext(declaration: FirRegularClass, context: FirTowerDataContext) {
|
||||
val psi = declaration.psi as? KtElement ?: return
|
||||
if (psi !is KtClassOrObject) return
|
||||
classesToClassHeaderContext[psi] = context
|
||||
}
|
||||
|
||||
override fun getClosestAvailableParentContext(ktElement: KtElement): FirTowerDataContext? {
|
||||
var current: PsiElement? = ktElement
|
||||
while (current != null) {
|
||||
if (current is KtElement) {
|
||||
getContextForElementOnPosition(current, ktElement)?.let { return it }
|
||||
}
|
||||
if (current is KtFile) {
|
||||
break
|
||||
}
|
||||
current = current.parent
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* N.B. It is expected that [element] contains [position].
|
||||
*/
|
||||
private fun getContextForElementOnPosition(element: KtElement, position: KtElement): FirTowerDataContext? {
|
||||
val contextMapping =
|
||||
if (element is KtClassOrObject && element.containsInHeader(position)) {
|
||||
classesToClassHeaderContext
|
||||
} else {
|
||||
elementsToContext
|
||||
}
|
||||
|
||||
return getContextForElement(element, contextMapping)
|
||||
}
|
||||
|
||||
private fun getContextForElement(element: KtElement, contextMapping: Map<out KtElement, FirTowerDataContext>): FirTowerDataContext? {
|
||||
contextMapping[element]?.let { return it }
|
||||
|
||||
if (element is KtDeclaration) {
|
||||
val originalDeclaration = element.originalDeclaration
|
||||
originalDeclaration?.let { contextMapping[it] }?.let { return it }
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns [this] in case [this] is:
|
||||
* - a statement in a block
|
||||
* - an initializer of a declaration
|
||||
* - an expression in when entry
|
||||
* - a right operand in binary expression with operator `&&` or `||`
|
||||
*
|
||||
* Otherwise, invokes this function recursively on the parent.
|
||||
*/
|
||||
@Suppress("NO_TAIL_CALLS_FOUND", "NON_TAIL_RECURSIVE_CALL") // K2 warning suppression, TODO: KT-62472
|
||||
private tailrec fun PsiElement.closestParentExpressionWithSameContextOrSelf(): KtExpression? {
|
||||
if (this is KtExpression) {
|
||||
if (
|
||||
parent is KtBlockExpression ||
|
||||
parent is KtDeclarationWithInitializer ||
|
||||
isExpressionInWhenEntry ||
|
||||
isRightOperandInBinaryLogicOperation
|
||||
) return this
|
||||
}
|
||||
|
||||
return parent?.closestParentExpressionWithSameContextOrSelf()
|
||||
}
|
||||
|
||||
private val KtExpression.isExpressionInWhenEntry: Boolean
|
||||
get() = this == (parent as? KtWhenEntry)?.expression
|
||||
|
||||
private val KtExpression.isRightOperandInBinaryLogicOperation: Boolean
|
||||
get() {
|
||||
val binaryLogicOperation = (parent as? KtBinaryExpression)
|
||||
?.takeIf { it.operationToken == KtTokens.ANDAND || it.operationToken == KtTokens.OROR }
|
||||
|
||||
return this == binaryLogicOperation?.right
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if [element] is considered to be a part of [this] class header.
|
||||
*
|
||||
* Here by "header" we understand the parts of the class declaration which resolution is not affected
|
||||
* by the class own supertypes.
|
||||
*/
|
||||
private fun KtClassOrObject.containsInHeader(element: PsiElement): Boolean {
|
||||
if (this == element) return false
|
||||
|
||||
val classHeaderParts = buildSet<KtElement> {
|
||||
addIfNotNull(getContextReceiverList())
|
||||
addIfNotNull(modifierList) // for annotations declared on class
|
||||
addIfNotNull(typeParameterList)
|
||||
addIfNotNull(typeConstraintList) // `where` clause type constraints
|
||||
|
||||
for (superTypeEntry in superTypeListEntries) {
|
||||
addIfNotNull(superTypeEntry.typeReference)
|
||||
}
|
||||
}
|
||||
|
||||
if (classHeaderParts.isEmpty()) return false
|
||||
|
||||
val elementParentsUntilClass = element.parentsWithSelf.takeWhile { it != this }
|
||||
return elementParentsUntilClass.any { it in classHeaderParts }
|
||||
}
|
||||
Reference in New Issue
Block a user