FIR IDE: add docs for LowLevelFirApiFacade functions

This commit is contained in:
Ilya Kirillov
2020-11-26 11:26:05 +01:00
parent 93648e6cd3
commit b4d63b9b13
2 changed files with 66 additions and 16 deletions
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.idea.fir.low.level.api.api
import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
@@ -19,23 +20,25 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtLambdaExpression import org.jetbrains.kotlin.psi.KtLambdaExpression
import kotlin.reflect.KClass import kotlin.reflect.KClass
/**
* Returns [FirModuleResolveState] which corresponds to containing module
*/
fun KtElement.getResolveState(): FirModuleResolveState = fun KtElement.getResolveState(): FirModuleResolveState =
getModuleInfo().getResolveState() getModuleInfo().getResolveState()
/**
* Returns [FirModuleResolveState] which corresponds to containing module
*/
fun IdeaModuleInfo.getResolveState(): FirModuleResolveState = fun IdeaModuleInfo.getResolveState(): FirModuleResolveState =
FirIdeResolveStateService.getInstance(project!!).getResolveState(this) FirIdeResolveStateService.getInstance(project!!).getResolveState(this)
fun KtFile.getFirFile(resolveState: FirModuleResolveState) =
resolveState.getFirFile(this)
/** /**
* Creates [FirDeclaration] by [KtDeclaration] and runs an [action] with it * Creates [FirDeclaration] by [KtDeclaration] and executes an [action] on it
* [this@withFirDeclaration] * [FirDeclaration] passed to [action] will be resolved at least to [phase] when executing [action] on it
* [FirDeclaration] passed to [action] should not be leaked outside [action] lambda
* [FirDeclaration] passed to [action] will be resolved at least to [phase]
* Otherwise, some threading problems may arise,
* *
* [this@withFirDeclaration] should be non-local declaration (should have fully qualified name) * [FirDeclaration] passed to [action] should not be leaked outside [action] lambda
* Otherwise, some threading problems may arise,
*/ */
@OptIn(InternalForInline::class) @OptIn(InternalForInline::class)
inline fun <R> KtDeclaration.withFirDeclaration( inline fun <R> KtDeclaration.withFirDeclaration(
@@ -48,16 +51,33 @@ inline fun <R> KtDeclaration.withFirDeclaration(
return action(firDeclaration) return action(firDeclaration)
} }
/**
* Creates [FirDeclaration] by [KtDeclaration] and executes an [action] on it
* [FirDeclaration] passed to [action] will be resolved at least to [phase] when executing [action] on it
*
* If resulted [FirDeclaration] is not [F] throws [InvalidFirElementTypeException]
*
* [FirDeclaration] passed to [action] should not be leaked outside [action] lambda
* Otherwise, some threading problems may arise,
*/
@OptIn(InternalForInline::class) @OptIn(InternalForInline::class)
inline fun <reified F : FirDeclaration, R> KtDeclaration.withFirDeclarationOfType( inline fun <reified F : FirDeclaration, R> KtDeclaration.withFirDeclarationOfType(
resolveState: FirModuleResolveState, resolveState: FirModuleResolveState,
phase: FirResolvePhase = FirResolvePhase.RAW_FIR,
action: (F) -> R action: (F) -> R
): R { ): R = withFirDeclaration(resolveState, phase) { firDeclaration ->
val firDeclaration = resolveState.findSourceFirDeclaration(this)
if (firDeclaration !is F) throw InvalidFirElementTypeException(this, F::class, firDeclaration::class) if (firDeclaration !is F) throw InvalidFirElementTypeException(this, F::class, firDeclaration::class)
return action(firDeclaration) action(firDeclaration)
} }
/**
* Creates [FirDeclaration] by [KtLambdaExpression] and executes an [action] on it
*
* If resulted [FirDeclaration] is not [F] throws [InvalidFirElementTypeException]
*
* [FirDeclaration] passed to [action] should not be leaked outside [action] lambda
* Otherwise, some threading problems may arise,
*/
@OptIn(InternalForInline::class) @OptIn(InternalForInline::class)
inline fun <reified F : FirDeclaration, R> KtLambdaExpression.withFirDeclarationOfType( inline fun <reified F : FirDeclaration, R> KtLambdaExpression.withFirDeclarationOfType(
resolveState: FirModuleResolveState, resolveState: FirModuleResolveState,
@@ -68,12 +88,23 @@ inline fun <reified F : FirDeclaration, R> KtLambdaExpression.withFirDeclaration
return action(firDeclaration) return action(firDeclaration)
} }
fun getDiagnosticsFor(element: KtElement, resolveState: FirModuleResolveState): Collection<Diagnostic> = /**
resolveState.getDiagnostics(element) * Returns a list of Diagnostics compiler finds for given [KtElement]
*/
fun KtElement.getDiagnostics(resolveState: FirModuleResolveState): Collection<Diagnostic> =
resolveState.getDiagnostics(this)
/**
* Returns a list of Diagnostics compiler finds for given [KtFile]
*/
fun KtFile.collectDiagnosticsForFile(resolveState: FirModuleResolveState): Collection<Diagnostic> = fun KtFile.collectDiagnosticsForFile(resolveState: FirModuleResolveState): Collection<Diagnostic> =
resolveState.collectDiagnosticsForFile(this) resolveState.collectDiagnosticsForFile(this)
/**
* Resolves a given [FirDeclaration] to [phase] and returns resolved declaration
*
* Should not be called form [withFirDeclaration], [withFirDeclarationOfType] functions, as it it may cause deadlock
*/
fun <D : FirDeclaration> D.resolvedFirToPhase( fun <D : FirDeclaration> D.resolvedFirToPhase(
phase: FirResolvePhase, phase: FirResolvePhase,
resolveState: FirModuleResolveState resolveState: FirModuleResolveState
@@ -81,14 +112,26 @@ fun <D : FirDeclaration> D.resolvedFirToPhase(
resolveState.resolvedFirToPhase(this, phase) resolveState.resolvedFirToPhase(this, phase)
/**
* Get a [FirElement] which was created by [KtElement]
* Returned [FirElement] is guaranteed to be resolved to [FirResolvePhase.BODY_RESOLVE] phase
*/
fun KtElement.getOrBuildFir( fun KtElement.getOrBuildFir(
resolveState: FirModuleResolveState, resolveState: FirModuleResolveState,
) = resolveState.getOrBuildFirFor(this) ): FirElement = resolveState.getOrBuildFirFor(this)
/**
* Get a [FirElement] which was created by [KtElement], but only if it is subtype of [E], `null` otherwise
* Returned [FirElement] is guaranteed to be resolved to [FirResolvePhase.BODY_RESOLVE] phase
*/
inline fun <reified E : FirElement> KtElement.getOrBuildFirSafe( inline fun <reified E : FirElement> KtElement.getOrBuildFirSafe(
resolveState: FirModuleResolveState, resolveState: FirModuleResolveState,
) = getOrBuildFir(resolveState) as? E ) = getOrBuildFir(resolveState) as? E
/**
* Get a [FirElement] which was created by [KtElement], but only if it is subtype of [E], throws [InvalidFirElementTypeException] otherwise
* Returned [FirElement] is guaranteed to be resolved to [FirResolvePhase.BODY_RESOLVE] phase
*/
inline fun <reified E : FirElement> KtElement.getOrBuildFirOfType( inline fun <reified E : FirElement> KtElement.getOrBuildFirOfType(
resolveState: FirModuleResolveState, resolveState: FirModuleResolveState,
): E { ): E {
@@ -97,6 +140,13 @@ inline fun <reified E : FirElement> KtElement.getOrBuildFirOfType(
throw InvalidFirElementTypeException(this, E::class, fir::class) throw InvalidFirElementTypeException(this, E::class, fir::class)
} }
/**
* Get a [FirFile] which was created by [KtElement]
* Returned [FirFile] can be resolved to any phase from [FirResolvePhase.RAW_FIR] to [FirResolvePhase.BODY_RESOLVE]
*/
fun KtFile.getFirFile(resolveState: FirModuleResolveState): FirFile =
resolveState.getFirFile(this)
class InvalidFirElementTypeException( class InvalidFirElementTypeException(
ktElement: KtElement, ktElement: KtElement,
expectedFirClass: KClass<out FirElement>, expectedFirClass: KClass<out FirElement>,
@@ -7,7 +7,7 @@ package org.jetbrains.kotlin.idea.frontend.api.fir.components
import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.fir.low.level.api.api.collectDiagnosticsForFile import org.jetbrains.kotlin.idea.fir.low.level.api.api.collectDiagnosticsForFile
import org.jetbrains.kotlin.idea.fir.low.level.api.api.getDiagnosticsFor import org.jetbrains.kotlin.idea.fir.low.level.api.api.getDiagnostics
import org.jetbrains.kotlin.idea.frontend.api.ValidityToken import org.jetbrains.kotlin.idea.frontend.api.ValidityToken
import org.jetbrains.kotlin.idea.frontend.api.components.KtDiagnosticProvider import org.jetbrains.kotlin.idea.frontend.api.components.KtDiagnosticProvider
import org.jetbrains.kotlin.idea.frontend.api.fir.KtFirAnalysisSession import org.jetbrains.kotlin.idea.frontend.api.fir.KtFirAnalysisSession
@@ -20,7 +20,7 @@ internal class KtFirDiagnosticProvider(
override val token: ValidityToken, override val token: ValidityToken,
) : KtDiagnosticProvider(), KtFirAnalysisSessionComponent { ) : KtDiagnosticProvider(), KtFirAnalysisSessionComponent {
override fun getDiagnosticsForElement(element: KtElement): Collection<Diagnostic> = withValidityAssertion { override fun getDiagnosticsForElement(element: KtElement): Collection<Diagnostic> = withValidityAssertion {
getDiagnosticsFor(element, firResolveState) element.getDiagnostics(firResolveState)
} }
override fun collectDiagnosticsForFile(ktFile: KtFile): Collection<Diagnostic> = override fun collectDiagnosticsForFile(ktFile: KtFile): Collection<Diagnostic> =