diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/api/AbstractHLDiagnosticBasedInspection.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/api/AbstractHLDiagnosticBasedInspection.kt new file mode 100644 index 00000000000..ded580e5fbb --- /dev/null +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/api/AbstractHLDiagnosticBasedInspection.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2010-2021 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.idea.fir.api + +import org.jetbrains.kotlin.idea.fir.api.applicator.HLApplicatorInput +import org.jetbrains.kotlin.idea.fir.api.applicator.HLApplicatorInputProvider +import org.jetbrains.kotlin.idea.fir.api.applicator.inputProvider +import org.jetbrains.kotlin.idea.frontend.api.components.KtDiagnosticCheckerFilter +import org.jetbrains.kotlin.idea.frontend.api.diagnostics.KtDiagnosticWithPsi +import org.jetbrains.kotlin.psi.KtElement +import kotlin.reflect.KClass + +abstract class AbstractHLDiagnosticBasedInspection, INPUT : HLApplicatorInput>( + elementType: KClass, + private val diagnosticType: KClass, +) : AbstractHLInspection(elementType) { + abstract val inputByDiagnosticProvider: HLInputByDiagnosticProvider + + final override val inputProvider: HLApplicatorInputProvider = inputProvider { psi -> + val diagnostics = psi.getDiagnostics(KtDiagnosticCheckerFilter.ONLY_EXTENDED_CHECKERS) + val suitableDiagnostics = diagnostics.filterIsInstance(diagnosticType.java) + val diagnostic = suitableDiagnostics.firstOrNull() ?: return@inputProvider null + // TODO handle case with multiple diagnostics on single element + with(inputByDiagnosticProvider) { createInfo(diagnostic) } + } +} + + diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/api/HLInputByDiagnosticProvider.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/api/HLInputByDiagnosticProvider.kt new file mode 100644 index 00000000000..eb069c0018a --- /dev/null +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/api/HLInputByDiagnosticProvider.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2010-2021 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.idea.fir.api + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.idea.fir.api.applicator.HLApplicatorInput +import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession +import org.jetbrains.kotlin.idea.frontend.api.diagnostics.KtDiagnosticWithPsi + +sealed class HLInputByDiagnosticProvider, INPUT : HLApplicatorInput> { + abstract fun KtAnalysisSession.createInfo(diagnostic: DIAGNOSTIC): INPUT? +} + +private class HLInputByDiagnosticProviderImpl, INPUT : HLApplicatorInput>( + private val createInfo: KtAnalysisSession.(DIAGNOSTIC) -> INPUT? +) : HLInputByDiagnosticProvider() { + override fun KtAnalysisSession.createInfo(diagnostic: DIAGNOSTIC): INPUT? = + createInfo.invoke(this, diagnostic) +} + +fun , INPUT : HLApplicatorInput> inputByDiagnosticProvider( + createInfo: KtAnalysisSession.(DIAGNOSTIC) -> INPUT? +): HLInputByDiagnosticProvider = + HLInputByDiagnosticProviderImpl(createInfo) \ No newline at end of file diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/KotlinHighLevelDiagnosticHighlightingPass.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/KotlinHighLevelDiagnosticHighlightingPass.kt index cb70641cb23..bf7a6da0605 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/KotlinHighLevelDiagnosticHighlightingPass.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/KotlinHighLevelDiagnosticHighlightingPass.kt @@ -31,6 +31,7 @@ import org.jetbrains.kotlin.idea.frontend.api.diagnostics.KtDiagnosticWithPsi import org.jetbrains.kotlin.idea.frontend.api.diagnostics.getDefaultMessageWithFactoryName import org.jetbrains.kotlin.idea.frontend.api.fir.diagnostics.KtFirDiagnostic import org.jetbrains.kotlin.idea.fir.api.fixes.KtQuickFixService +import org.jetbrains.kotlin.idea.frontend.api.components.KtDiagnosticCheckerFilter import org.jetbrains.kotlin.psi.KtFile class KotlinHighLevelDiagnosticHighlightingPass( @@ -43,7 +44,7 @@ class KotlinHighLevelDiagnosticHighlightingPass( override fun doCollectInformation(progress: ProgressIndicator) { analyze(ktFile) { - ktFile.collectDiagnosticsForFile().forEach { diagnostic -> + ktFile.collectDiagnosticsForFile(KtDiagnosticCheckerFilter.ONLY_COMMON_CHECKERS).forEach { diagnostic -> addDiagnostic(diagnostic) } } diff --git a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/KtAnalysisSession.kt b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/KtAnalysisSession.kt index cf643ccf248..147134cb497 100644 --- a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/KtAnalysisSession.kt +++ b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/KtAnalysisSession.kt @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* +import kotlin.reflect.KClass /** * The entry point into all frontend-related work. Has the following contracts: @@ -91,9 +92,11 @@ abstract class KtAnalysisSession(final override val token: ValidityToken) : Vali fun KtClassOrObjectSymbol.buildSelfClassType(): KtType = typeProvider.buildSelfClassType(this) - fun KtElement.getDiagnostics(): Collection = diagnosticProvider.getDiagnosticsForElement(this) + fun KtElement.getDiagnostics(filter: KtDiagnosticCheckerFilter): Collection = + diagnosticProvider.getDiagnosticsForElement(this, filter) - fun KtFile.collectDiagnosticsForFile(): Collection> = diagnosticProvider.collectDiagnosticsForFile(this) + fun KtFile.collectDiagnosticsForFile(filter: KtDiagnosticCheckerFilter): Collection> = + diagnosticProvider.collectDiagnosticsForFile(this, filter) fun KtSymbolWithKind.getContainingSymbol(): KtSymbolWithKind? = containingDeclarationProvider.getContainingDeclaration(this) diff --git a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtDiagnosticProvider.kt b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtDiagnosticProvider.kt index 045d09f02ff..7964d4e3c17 100644 --- a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtDiagnosticProvider.kt +++ b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtDiagnosticProvider.kt @@ -10,6 +10,12 @@ import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtFile abstract class KtDiagnosticProvider : KtAnalysisSessionComponent() { - abstract fun getDiagnosticsForElement(element: KtElement): Collection> - abstract fun collectDiagnosticsForFile(ktFile: KtFile): Collection> + abstract fun getDiagnosticsForElement(element: KtElement, filter: KtDiagnosticCheckerFilter): Collection> + abstract fun collectDiagnosticsForFile(ktFile: KtFile, filter: KtDiagnosticCheckerFilter): Collection> } + +enum class KtDiagnosticCheckerFilter { + ONLY_COMMON_CHECKERS, + ONLY_EXTENDED_CHECKERS, + EXTENDED_AND_COMMON_CHECKERS, +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateForCompletion.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateForCompletion.kt index b72b9f4ebf6..0b120d530d9 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateForCompletion.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateForCompletion.kt @@ -17,11 +17,13 @@ import org.jetbrains.kotlin.fir.resolve.FirTowerDataContext import org.jetbrains.kotlin.fir.resolve.providers.FirProvider import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo import org.jetbrains.kotlin.idea.fir.low.level.api.annotations.InternalForInline +import org.jetbrains.kotlin.idea.fir.low.level.api.api.DiagnosticCheckerFilter import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.FirElementsRecorder import org.jetbrains.kotlin.idea.fir.low.level.api.util.containingKtFileIfAny import org.jetbrains.kotlin.idea.fir.low.level.api.util.originalKtFile +import org.jetbrains.kotlin.idea.frontend.api.components.KtDiagnosticCheckerFilter import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtFile @@ -84,11 +86,11 @@ internal class FirModuleResolveStateForCompletion( } - override fun getDiagnostics(element: KtElement): List> { + override fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List> { error("Diagnostics should not be retrieved in completion") } - override fun collectDiagnosticsForFile(ktFile: KtFile): Collection> { + override fun collectDiagnosticsForFile(ktFile: KtFile, filter: DiagnosticCheckerFilter): Collection> { error("Diagnostics should not be retrieved in completion") } diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateImpl.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateImpl.kt index 874301b35d0..5e2e9b90345 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateImpl.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateImpl.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo import org.jetbrains.kotlin.idea.caches.project.getModuleInfo import org.jetbrains.kotlin.idea.fir.low.level.api.annotations.InternalForInline +import org.jetbrains.kotlin.idea.fir.low.level.api.api.DiagnosticCheckerFilter import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.DiagnosticsCollector import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirElementBuilder @@ -69,11 +70,11 @@ internal class FirModuleResolveStateImpl( override fun getFirFile(ktFile: KtFile): FirFile = firFileBuilder.buildRawFirFileWithCaching(ktFile, rootModuleSession.cache, lazyBodiesMode = false) - override fun getDiagnostics(element: KtElement): List> = - diagnosticsCollector.getDiagnosticsFor(element) + override fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List> = + diagnosticsCollector.getDiagnosticsFor(element, filter) - override fun collectDiagnosticsForFile(ktFile: KtFile): Collection> = - diagnosticsCollector.collectDiagnosticsForFile(ktFile) + override fun collectDiagnosticsForFile(ktFile: KtFile, filter: DiagnosticCheckerFilter): Collection> = + diagnosticsCollector.collectDiagnosticsForFile(ktFile, filter) override fun getBuiltFirFileOrNull(ktFile: KtFile): FirFile? { val cache = sessionProvider.getModuleCache(ktFile.getModuleInfo() as ModuleSourceInfo) @@ -119,7 +120,7 @@ internal class FirModuleResolveStateImpl( container, cache, FirResolvePhase.BODY_RESOLVE, - checkPCE = false /*TODO*/, + checkPCE = false, /*TODO*/ towerDataContextCollector = collector, ) } diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/DiagnosticCheckerFilter.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/DiagnosticCheckerFilter.kt new file mode 100644 index 00000000000..bc7d1fcdc34 --- /dev/null +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/DiagnosticCheckerFilter.kt @@ -0,0 +1,12 @@ +/* + * Copyright 2010-2021 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.idea.fir.low.level.api.api + +enum class DiagnosticCheckerFilter(val runCommonCheckers: Boolean, val runExtendedCheckers: Boolean) { + ONLY_COMMON_CHECKERS(runCommonCheckers = true, runExtendedCheckers = false), + ONLY_EXTENDED_CHECKERS(runCommonCheckers = false, runExtendedCheckers = true), + EXTENDED_AND_COMMON_CHECKERS(runCommonCheckers = true, runExtendedCheckers = true), +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/FirModuleResolveState.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/FirModuleResolveState.kt index 07112416bba..2c842d4d156 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/FirModuleResolveState.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/FirModuleResolveState.kt @@ -37,9 +37,9 @@ abstract class FirModuleResolveState { internal abstract fun isFirFileBuilt(ktFile: KtFile): Boolean - internal abstract fun getDiagnostics(element: KtElement): List> + internal abstract fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List> - internal abstract fun collectDiagnosticsForFile(ktFile: KtFile): Collection> + internal abstract fun collectDiagnosticsForFile(ktFile: KtFile, filter: DiagnosticCheckerFilter): Collection> @TestOnly internal abstract fun getBuiltFirFileOrNull(ktFile: KtFile): FirFile? diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacade.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacade.kt index 5823adde819..b471486dc03 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacade.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacade.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.idea.fir.low.level.api.api -import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic import org.jetbrains.kotlin.fir.declarations.* @@ -17,7 +16,6 @@ import org.jetbrains.kotlin.idea.caches.project.getModuleInfo import org.jetbrains.kotlin.idea.fir.low.level.api.FirIdeResolveStateService import org.jetbrains.kotlin.idea.fir.low.level.api.annotations.InternalForInline import org.jetbrains.kotlin.idea.fir.low.level.api.sessions.FirIdeSourcesSession -import org.jetbrains.kotlin.idea.fir.low.level.api.util.ktDeclaration import org.jetbrains.kotlin.idea.util.getElementTextInContext import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtElement @@ -76,13 +74,13 @@ inline fun KtDeclaration.withFirDeclarationOfTyp } /** -* 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, -*/ + * 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) inline fun KtLambdaExpression.withFirDeclarationOfType( resolveState: FirModuleResolveState, @@ -121,14 +119,17 @@ fun D.withFirDeclaration( /** * Returns a list of Diagnostics compiler finds for given [KtElement] */ -fun KtElement.getDiagnostics(resolveState: FirModuleResolveState): Collection> = - resolveState.getDiagnostics(this) +fun KtElement.getDiagnostics(resolveState: FirModuleResolveState, filter: DiagnosticCheckerFilter): Collection> = + resolveState.getDiagnostics(this, filter) /** * Returns a list of Diagnostics compiler finds for given [KtFile] */ -fun KtFile.collectDiagnosticsForFile(resolveState: FirModuleResolveState): Collection> = - resolveState.collectDiagnosticsForFile(this) +fun KtFile.collectDiagnosticsForFile( + resolveState: FirModuleResolveState, + filter: DiagnosticCheckerFilter +): Collection> = + resolveState.collectDiagnosticsForFile(this, filter) /** * Resolves a given [FirDeclaration] to [phase] and returns resolved declaration diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/AbstractFirIdeDiagnosticsCollector.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/AbstractFirIdeDiagnosticsCollector.kt index e8015c33fe8..e8d1ecc99b4 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/AbstractFirIdeDiagnosticsCollector.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/AbstractFirIdeDiagnosticsCollector.kt @@ -5,24 +5,33 @@ package org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics -import com.intellij.openapi.diagnostic.Logger -import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.SessionConfiguration +import org.jetbrains.kotlin.fir.analysis.CheckersComponent import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckers +import org.jetbrains.kotlin.fir.analysis.checkers.expression.ExpressionCheckers import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector -import org.jetbrains.kotlin.fir.analysis.collectors.registerAllComponents +import org.jetbrains.kotlin.fir.analysis.collectors.components.ControlFlowAnalysisDiagnosticComponent +import org.jetbrains.kotlin.fir.analysis.collectors.components.DeclarationCheckersDiagnosticComponent +import org.jetbrains.kotlin.fir.analysis.collectors.components.ErrorNodeDiagnosticCollectorComponent +import org.jetbrains.kotlin.fir.analysis.collectors.components.ExpressionCheckersDiagnosticComponent import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnostic import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic +import org.jetbrains.kotlin.fir.checkers.CommonDeclarationCheckers +import org.jetbrains.kotlin.fir.checkers.CommonExpressionCheckers +import org.jetbrains.kotlin.fir.checkers.ExtendedDeclarationCheckers +import org.jetbrains.kotlin.fir.checkers.ExtendedExpressionCheckers import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.ImplicitBodyResolveComputationSession import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.createReturnTypeCalculatorForIDE import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirIdeDesignatedBodyResolveTransformerForReturnTypeCalculator import org.jetbrains.kotlin.idea.fir.low.level.api.util.checkCanceled -import org.jetbrains.kotlin.psi.KtElement internal abstract class AbstractFirIdeDiagnosticsCollector( session: FirSession, + useExtendedCheckers: Boolean, ) : AbstractDiagnosticCollector( session, returnTypeCalculator = createReturnTypeCalculatorForIDE( @@ -33,7 +42,16 @@ internal abstract class AbstractFirIdeDiagnosticsCollector( ) ) { init { - registerAllComponents() + val declarationCheckers = CheckersFactory.createDeclarationCheckers(useExtendedCheckers) + val expressionCheckers = CheckersFactory.createExpressionCheckers(useExtendedCheckers) + + @Suppress("LeakingThis") + initializeComponents( + DeclarationCheckersDiagnosticComponent(this, declarationCheckers), + ExpressionCheckersDiagnosticComponent(this, expressionCheckers), + ErrorNodeDiagnosticCollectorComponent(this), + ControlFlowAnalysisDiagnosticComponent(this, declarationCheckers), + ) } protected abstract fun onDiagnostic(diagnostic: FirPsiDiagnostic<*>) @@ -60,8 +78,23 @@ internal abstract class AbstractFirIdeDiagnosticsCollector( // Not necessary in IDE return emptyList() } - - companion object { - private val LOG = Logger.getInstance(AbstractFirIdeDiagnosticsCollector::class.java) - } +} + + +private object CheckersFactory { + private val extendedDeclarationCheckers = createDeclarationCheckers(ExtendedDeclarationCheckers) + private val commonDeclarationCheckers = createDeclarationCheckers(CommonDeclarationCheckers) + + fun createDeclarationCheckers(useExtendedCheckers: Boolean): DeclarationCheckers = + if (useExtendedCheckers) extendedDeclarationCheckers else commonDeclarationCheckers + + fun createExpressionCheckers(useExtendedCheckers: Boolean): ExpressionCheckers = + if (useExtendedCheckers) ExtendedExpressionCheckers else CommonExpressionCheckers + + // TODO hack to have all checkers present in DeclarationCheckers.memberDeclarationCheckers and similar + // If use ExtendedDeclarationCheckers directly when DeclarationCheckers.memberDeclarationCheckers will not contain basicDeclarationCheckers + @OptIn(SessionConfiguration::class) + private fun createDeclarationCheckers(declarationCheckers: DeclarationCheckers): DeclarationCheckers = + CheckersComponent().apply { register(declarationCheckers) }.declarationCheckers + } diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/DiagnosticsCollector.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/DiagnosticsCollector.kt index 227a091fb15..7b3d7688c0e 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/DiagnosticsCollector.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/DiagnosticsCollector.kt @@ -5,8 +5,8 @@ package org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics -import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic +import org.jetbrains.kotlin.idea.fir.low.level.api.api.DiagnosticCheckerFilter import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.FileStructureCache import org.jetbrains.kotlin.psi.KtElement @@ -16,14 +16,14 @@ internal class DiagnosticsCollector( private val fileStructureCache: FileStructureCache, private val cache: ModuleFileCache, ) { - fun getDiagnosticsFor(element: KtElement): List> = + fun getDiagnosticsFor(element: KtElement, filter: DiagnosticCheckerFilter): List> = fileStructureCache .getFileStructure(element.containingKtFile, cache) .getStructureElementFor(element) - .diagnostics.diagnosticsFor(element) + .diagnostics.diagnosticsFor(filter, element) - fun collectDiagnosticsForFile(ktFile: KtFile): Collection> = + fun collectDiagnosticsForFile(ktFile: KtFile, filter: DiagnosticCheckerFilter): Collection> = fileStructureCache .getFileStructure(ktFile, cache) - .getAllDiagnosticsForFile() + .getAllDiagnosticsForFile(filter) } \ No newline at end of file diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/FileStructureElementDiagnosticList.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/FileStructureElementDiagnosticList.kt new file mode 100644 index 00000000000..6a6686016df --- /dev/null +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/FileStructureElementDiagnosticList.kt @@ -0,0 +1,17 @@ +/* + * Copyright 2010-2021 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.idea.fir.low.level.api.diagnostics + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic + +internal class FileStructureElementDiagnosticList( + private val map: Map>> +) { + fun diagnosticsFor(element: PsiElement): List> = map[element] ?: emptyList() + + inline fun forEach(action: (List>) -> Unit) = map.values.forEach(action) +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/FileStructureElementDiagnosticRetriever.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/FileStructureElementDiagnosticRetriever.kt new file mode 100644 index 00000000000..3a3874b74f1 --- /dev/null +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/FileStructureElementDiagnosticRetriever.kt @@ -0,0 +1,12 @@ +/* + * Copyright 2010-2021 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.idea.fir.low.level.api.diagnostics + +import org.jetbrains.kotlin.fir.declarations.FirFile + +internal abstract class FileStructureElementDiagnosticRetriever { + abstract fun retrieve(firFile: FirFile, collector: FileStructureElementDiagnosticsCollector): FileStructureElementDiagnosticList +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/FileStructureElementDiagnostics.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/FileStructureElementDiagnostics.kt new file mode 100644 index 00000000000..ce824bb3554 --- /dev/null +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/FileStructureElementDiagnostics.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2010-2021 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.idea.fir.low.level.api.diagnostics + +import com.intellij.psi.PsiElement +import com.intellij.util.SmartList +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic +import org.jetbrains.kotlin.fir.declarations.FirFile +import org.jetbrains.kotlin.idea.fir.low.level.api.api.DiagnosticCheckerFilter + +internal class FileStructureElementDiagnostics( + private val firFile: FirFile, + private val retriever: FileStructureElementDiagnosticRetriever +) { + private val diagnosticByCommonCheckers: FileStructureElementDiagnosticList by lazy { + retriever.retrieve(firFile, FileStructureElementDiagnosticsCollector.USUAL_COLLECTOR) + } + + private val diagnosticByExtendedCheckers: FileStructureElementDiagnosticList by lazy { + retriever.retrieve(firFile, FileStructureElementDiagnosticsCollector.EXTENDED_COLLECTOR) + } + + fun diagnosticsFor(filter: DiagnosticCheckerFilter, element: PsiElement): List> = + SmartList>().apply { + if (filter.runCommonCheckers) { + addAll(diagnosticByCommonCheckers.diagnosticsFor(element)) + } + if (filter.runExtendedCheckers) { + addAll(diagnosticByExtendedCheckers.diagnosticsFor(element)) + } + } + + + inline fun forEach(filter: DiagnosticCheckerFilter, action: (List>) -> Unit) { + if (filter.runCommonCheckers) { + diagnosticByCommonCheckers.forEach(action) + } + if (filter.runExtendedCheckers) { + diagnosticByExtendedCheckers.forEach(action) + } + } +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/FileStructureElementDiagnosticsCollector.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/FileStructureElementDiagnosticsCollector.kt new file mode 100644 index 00000000000..fe3b6e04efe --- /dev/null +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/FileStructureElementDiagnosticsCollector.kt @@ -0,0 +1,61 @@ +/* + * 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.idea.fir.low.level.api.diagnostics + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.analysis.collectors.DiagnosticCollectorDeclarationAction +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic +import org.jetbrains.kotlin.fir.declarations.FirDeclaration +import org.jetbrains.kotlin.fir.declarations.FirFile +import org.jetbrains.kotlin.idea.fir.low.level.api.util.addValueFor + +internal class FileStructureElementDiagnosticsCollector private constructor(private val useExtendedCheckers: Boolean) { + companion object { + val USUAL_COLLECTOR = FileStructureElementDiagnosticsCollector(useExtendedCheckers = false) + val EXTENDED_COLLECTOR = FileStructureElementDiagnosticsCollector(useExtendedCheckers = true) + } + + fun collectForStructureElement( + firFile: FirFile, + onDeclarationExit: (FirDeclaration) -> Unit = {}, + onDeclarationEnter: (FirDeclaration) -> DiagnosticCollectorDeclarationAction, + ): FileStructureElementDiagnosticList = + FirIdeStructureElementDiagnosticsCollector( + firFile.session, + useExtendedCheckers, + onDeclarationEnter, + onDeclarationExit + ).let { collector -> + collector.collectDiagnostics(firFile) + FileStructureElementDiagnosticList(collector.result) + } + + private class FirIdeStructureElementDiagnosticsCollector( + session: FirSession, + useExtendedCheckers: Boolean, + private val onDeclarationEnter: (FirDeclaration) -> DiagnosticCollectorDeclarationAction, + private val onDeclarationExit: (FirDeclaration) -> Unit + ) : AbstractFirIdeDiagnosticsCollector( + session, + useExtendedCheckers, + ) { + val result = mutableMapOf>>() + + override fun onDiagnostic(diagnostic: FirPsiDiagnostic<*>) { + result.addValueFor(diagnostic.psiElement, diagnostic) + } + + override fun onDeclarationEnter( + declaration: FirDeclaration, + ): DiagnosticCollectorDeclarationAction = + onDeclarationEnter.invoke(declaration) + + override fun onDeclarationExit(declaration: FirDeclaration) { + onDeclarationExit.invoke(declaration) + } + } +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/FirIdeFileDiagnosticsCollector.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/FirIdeFileDiagnosticsCollector.kt index b75ec1041fd..e3993689532 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/FirIdeFileDiagnosticsCollector.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/FirIdeFileDiagnosticsCollector.kt @@ -5,15 +5,16 @@ package org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics -import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic import org.jetbrains.kotlin.fir.declarations.FirFile internal class FirIdeFileDiagnosticsCollector private constructor( session: FirSession, + useExtendedCheckers: Boolean, ) : AbstractFirIdeDiagnosticsCollector( session, + useExtendedCheckers, ) { private val result = mutableListOf>() @@ -22,8 +23,8 @@ internal class FirIdeFileDiagnosticsCollector private constructor( } companion object { - fun collectForFile(firFile: FirFile): List> = - FirIdeFileDiagnosticsCollector(firFile.session).let { collector -> + fun collectForFile(firFile: FirFile, useExtendedCheckers: Boolean): List> = + FirIdeFileDiagnosticsCollector(firFile.session, useExtendedCheckers).let { collector -> collector.collectDiagnostics(firFile) collector.result } diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/FirIdeStructureElementDiagnosticsCollector.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/FirIdeStructureElementDiagnosticsCollector.kt deleted file mode 100644 index 4c476d7e156..00000000000 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/FirIdeStructureElementDiagnosticsCollector.kt +++ /dev/null @@ -1,78 +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.idea.fir.low.level.api.diagnostics - -import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.diagnostics.Diagnostic -import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.analysis.collectors.DiagnosticCollectorDeclarationAction -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic -import org.jetbrains.kotlin.fir.declarations.FirDeclaration -import org.jetbrains.kotlin.fir.declarations.FirFile -import org.jetbrains.kotlin.fir.psi -import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.FileStructureElementDiagnostics -import org.jetbrains.kotlin.idea.fir.low.level.api.util.addValueFor -import org.jetbrains.kotlin.psi.KtAnnotated -import org.jetbrains.kotlin.psi.KtElement - -internal class FirIdeStructureElementDiagnosticsCollector private constructor( - session: FirSession, - private val onDeclarationEnter: (FirDeclaration) -> DiagnosticCollectorDeclarationAction, - private val onDeclarationExit: (FirDeclaration) -> Unit -) : AbstractFirIdeDiagnosticsCollector( - session, -) { - private val result = mutableMapOf>>() - - override fun onDiagnostic(diagnostic: FirPsiDiagnostic<*>) { - result.addValueFor(diagnostic.psiElement, diagnostic) - } - - override fun onDeclarationEnter( - declaration: FirDeclaration, - ): DiagnosticCollectorDeclarationAction = - onDeclarationEnter.invoke(declaration) - - override fun onDeclarationExit(declaration: FirDeclaration) { - onDeclarationExit.invoke(declaration) - } - - - companion object { - fun collectForStructureElement( - firFile: FirFile, - onDeclarationExit: (FirDeclaration) -> Unit = {}, - onDeclarationEnter: (FirDeclaration) -> DiagnosticCollectorDeclarationAction, - ): FileStructureElementDiagnostics = - FirIdeStructureElementDiagnosticsCollector(firFile.session, onDeclarationEnter, onDeclarationExit).let { collector -> - collector.collectDiagnostics(firFile) - FileStructureElementDiagnostics(collector.result) - } - - fun collectForSingleDeclaration(firFile: FirFile, declaration: FirDeclaration): FileStructureElementDiagnostics { - var inCurrentDeclaration = false - - return collectForStructureElement( - firFile, - onDeclarationEnter = { firDeclaration -> - when { - firDeclaration == declaration -> { - inCurrentDeclaration = true - DiagnosticCollectorDeclarationAction.CHECK_CURRENT_DECLARATION_AND_CHECK_NESTED - } - inCurrentDeclaration -> DiagnosticCollectorDeclarationAction.CHECK_CURRENT_DECLARATION_AND_CHECK_NESTED - else -> DiagnosticCollectorDeclarationAction.SKIP_CURRENT_DECLARATION_AND_CHECK_NESTED - } - }, - onDeclarationExit = { firDeclaration -> - if (declaration == firDeclaration) { - inCurrentDeclaration = false - } - } - ) - } - } -} diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructure.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructure.kt index fdcf235546d..7b8362dfda2 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructure.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructure.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirResolvePhase +import org.jetbrains.kotlin.idea.fir.low.level.api.api.DiagnosticCheckerFilter import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerDataContextCollector import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.getNonLocalContainingOrThisDeclaration import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.FirFileBuilder @@ -56,10 +57,21 @@ internal class FileStructure( } @OptIn(ExperimentalStdlibApi::class) - fun getAllDiagnosticsForFile(): Collection> { + fun getAllDiagnosticsForFile(diagnosticCheckerFilter: DiagnosticCheckerFilter): Collection> { val structureElements = getAllStructureElements() return buildSet { - structureElements.forEach { it.diagnostics.forEach { diagnostics -> addAll(diagnostics) } } + collectDiagnosticsFromStructureElements(structureElements, diagnosticCheckerFilter) + } + } + + private fun MutableSet>.collectDiagnosticsFromStructureElements( + structureElements: Collection, + diagnosticCheckerFilter: DiagnosticCheckerFilter + ) { + structureElements.forEach { structureElement -> + structureElement.diagnostics.forEach(diagnosticCheckerFilter) { diagnostics -> + addAll(diagnostics) + } } } diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureElement.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureElement.kt index 6d4722b34b4..24c68a085d9 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureElement.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureElement.kt @@ -5,18 +5,17 @@ package org.jetbrains.kotlin.idea.fir.low.level.api.file.structure -import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.analysis.collectors.DiagnosticCollectorDeclarationAction -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic -import org.jetbrains.kotlin.fir.containingClass import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol -import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.FirIdeStructureElementDiagnosticsCollector +import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.FileStructureElementDiagnosticList +import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.FileStructureElementDiagnosticRetriever +import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.FileStructureElementDiagnostics +import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.FileStructureElementDiagnosticsCollector 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.providers.FirIdeProvider @@ -25,22 +24,13 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.util.isGeneratedDeclaration import org.jetbrains.kotlin.idea.fir.low.level.api.util.ktDeclaration import org.jetbrains.kotlin.psi.* -internal class FileStructureElementDiagnostics( - private val map: Map>> -) { - fun diagnosticsFor(element: PsiElement): List> = map[element] ?: emptyList() - - inline fun forEach(action: (List>) -> Unit) = map.values.forEach(action) -} - -internal sealed class FileStructureElement { - abstract val firFile: FirFile +internal sealed class FileStructureElement(val firFile: FirFile) { abstract val psi: KtAnnotated abstract val mappings: Map abstract val diagnostics: FileStructureElementDiagnostics } -internal sealed class ReanalyzableStructureElement : FileStructureElement() { +internal sealed class ReanalyzableStructureElement(firFile: FirFile) : FileStructureElement(firFile) { abstract override val psi: KtDeclaration abstract val firSymbol: AbstractFirBasedSymbol<*> abstract val timestamp: Long @@ -58,8 +48,31 @@ internal sealed class ReanalyzableStructureElement : FileStr fun isUpToDate(): Boolean = psi.getModificationStamp() == timestamp - override val diagnostics: FileStructureElementDiagnostics by lazy { - FirIdeStructureElementDiagnosticsCollector.collectForSingleDeclaration(firFile, firSymbol.fir as FirDeclaration) + override val diagnostics = FileStructureElementDiagnostics(firFile, FileStructureElementSingleDeclarationDiagnosticRetriever()) + + inner class FileStructureElementSingleDeclarationDiagnosticRetriever : FileStructureElementDiagnosticRetriever() { + override fun retrieve(firFile: FirFile, collector: FileStructureElementDiagnosticsCollector): FileStructureElementDiagnosticList { + var inCurrentDeclaration = false + val declaration = firSymbol.fir as FirDeclaration + return collector.collectForStructureElement( + firFile, + onDeclarationEnter = { firDeclaration -> + when { + firDeclaration == declaration -> { + inCurrentDeclaration = true + DiagnosticCollectorDeclarationAction.CHECK_CURRENT_DECLARATION_AND_CHECK_NESTED + } + inCurrentDeclaration -> DiagnosticCollectorDeclarationAction.CHECK_CURRENT_DECLARATION_AND_CHECK_NESTED + else -> DiagnosticCollectorDeclarationAction.SKIP_CURRENT_DECLARATION_AND_CHECK_NESTED + } + }, + onDeclarationExit = { firDeclaration -> + if (declaration == firDeclaration) { + inCurrentDeclaration = false + } + } + ) + } } companion object { @@ -68,11 +81,11 @@ internal sealed class ReanalyzableStructureElement : FileStr } internal class ReanalyzableFunctionStructureElement( - override val firFile: FirFile, + firFile: FirFile, override val psi: KtNamedFunction, override val firSymbol: FirFunctionSymbol<*>, override val timestamp: Long -) : ReanalyzableStructureElement() { +) : ReanalyzableStructureElement(firFile) { override val mappings: Map = FirElementsRecorder.recordElementsFrom(firSymbol.fir, recorder) @@ -106,11 +119,11 @@ internal class ReanalyzableFunctionStructureElement( } internal class ReanalyzablePropertyStructureElement( - override val firFile: FirFile, + firFile: FirFile, override val psi: KtProperty, override val firSymbol: FirPropertySymbol, override val timestamp: Long -) : ReanalyzableStructureElement() { +) : ReanalyzableStructureElement(firFile) { override val mappings: Map = FirElementsRecorder.recordElementsFrom(firSymbol.fir, recorder) @@ -144,42 +157,47 @@ internal class ReanalyzablePropertyStructureElement( } internal class NonReanalyzableDeclarationStructureElement( - override val firFile: FirFile, - fir: FirDeclaration, + firFile: FirFile, + private val fir: FirDeclaration, override val psi: KtDeclaration, -) : FileStructureElement() { +) : FileStructureElement(firFile) { override val mappings: Map = FirElementsRecorder.recordElementsFrom(fir, recorder) - override val diagnostics: FileStructureElementDiagnostics by lazy { - var inCurrentDeclaration = false - FirIdeStructureElementDiagnosticsCollector.collectForStructureElement( - firFile, - onDeclarationEnter = { firDeclaration -> - when { - firDeclaration.isGeneratedDeclaration -> DiagnosticCollectorDeclarationAction.SKIP - firDeclaration is FirFile -> DiagnosticCollectorDeclarationAction.CHECK_CURRENT_DECLARATION_AND_CHECK_NESTED - firDeclaration == fir -> { - inCurrentDeclaration = true - DiagnosticCollectorDeclarationAction.CHECK_CURRENT_DECLARATION_AND_CHECK_NESTED + override val diagnostics = FileStructureElementDiagnostics(firFile, DiagnosticRetriever()) + + private inner class DiagnosticRetriever : FileStructureElementDiagnosticRetriever() { + override fun retrieve(firFile: FirFile, collector: FileStructureElementDiagnosticsCollector): FileStructureElementDiagnosticList { + var inCurrentDeclaration = false + return collector.collectForStructureElement( + firFile, + onDeclarationEnter = { firDeclaration -> + when { + firDeclaration.isGeneratedDeclaration -> DiagnosticCollectorDeclarationAction.SKIP + firDeclaration is FirFile -> DiagnosticCollectorDeclarationAction.CHECK_CURRENT_DECLARATION_AND_CHECK_NESTED + firDeclaration == fir -> { + inCurrentDeclaration = true + DiagnosticCollectorDeclarationAction.CHECK_CURRENT_DECLARATION_AND_CHECK_NESTED + } + FileElementFactory.isReanalyzableContainer(firDeclaration.ktDeclaration) -> { + DiagnosticCollectorDeclarationAction.SKIP + } + inCurrentDeclaration -> { + DiagnosticCollectorDeclarationAction.CHECK_CURRENT_DECLARATION_AND_CHECK_NESTED + } + else -> DiagnosticCollectorDeclarationAction.SKIP_CURRENT_DECLARATION_AND_CHECK_NESTED } - FileElementFactory.isReanalyzableContainer(firDeclaration.ktDeclaration) -> { - DiagnosticCollectorDeclarationAction.SKIP + }, + onDeclarationExit = { firDeclaration -> + if (firDeclaration == fir) { + inCurrentDeclaration = false } - inCurrentDeclaration -> { - DiagnosticCollectorDeclarationAction.CHECK_CURRENT_DECLARATION_AND_CHECK_NESTED - } - else -> DiagnosticCollectorDeclarationAction.SKIP_CURRENT_DECLARATION_AND_CHECK_NESTED - } - }, - onDeclarationExit = { firDeclaration -> - if (firDeclaration == fir) { - inCurrentDeclaration = false - } - }, - ) + }, + ) + } } + companion object { private val recorder = object : FirElementsRecorder() { override fun visitProperty(property: FirProperty, data: MutableMap) { @@ -200,17 +218,21 @@ internal class NonReanalyzableDeclarationStructureElement( } -internal data class RootStructureElement( - override val firFile: FirFile, +internal class RootStructureElement( + firFile: FirFile, override val psi: KtFile, -) : FileStructureElement() { +) : FileStructureElement(firFile) { override val mappings: Map = FirElementsRecorder.recordElementsFrom(firFile, recorder) - override val diagnostics: FileStructureElementDiagnostics by lazy { - FirIdeStructureElementDiagnosticsCollector.collectForStructureElement(firFile) { firDeclaration -> - if (firDeclaration is FirFile) DiagnosticCollectorDeclarationAction.CHECK_CURRENT_DECLARATION_AND_SKIP_NESTED - else DiagnosticCollectorDeclarationAction.SKIP + override val diagnostics = FileStructureElementDiagnostics(firFile, DiagnosticRetriever) + + private object DiagnosticRetriever : FileStructureElementDiagnosticRetriever() { + override fun retrieve(firFile: FirFile, collector: FileStructureElementDiagnosticsCollector): FileStructureElementDiagnosticList { + return collector.collectForStructureElement(firFile) { firDeclaration -> + if (firDeclaration is FirFile) DiagnosticCollectorDeclarationAction.CHECK_CURRENT_DECLARATION_AND_SKIP_NESTED + else DiagnosticCollectorDeclarationAction.SKIP + } } } diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureElementDiagnosticList.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureElementDiagnosticList.kt new file mode 100644 index 00000000000..55b0d4c0b47 --- /dev/null +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureElementDiagnosticList.kt @@ -0,0 +1,7 @@ +/* + * Copyright 2010-2021 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.idea.fir.low.level.api.file.structure + diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureElementDiagnosticRetriever.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureElementDiagnosticRetriever.kt new file mode 100644 index 00000000000..55b0d4c0b47 --- /dev/null +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureElementDiagnosticRetriever.kt @@ -0,0 +1,7 @@ +/* + * Copyright 2010-2021 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.idea.fir.low.level.api.file.structure + diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureElementDiagnostics.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureElementDiagnostics.kt new file mode 100644 index 00000000000..55b0d4c0b47 --- /dev/null +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureElementDiagnostics.kt @@ -0,0 +1,7 @@ +/* + * Copyright 2010-2021 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.idea.fir.low.level.api.file.structure + diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/sessions/FirIdeSessionFactory.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/sessions/FirIdeSessionFactory.kt index c8bfe92e09e..5967462492d 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/sessions/FirIdeSessionFactory.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/sessions/FirIdeSessionFactory.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.SessionConfiguration import org.jetbrains.kotlin.fir.backend.jvm.FirJvmTypeMapper import org.jetbrains.kotlin.fir.caches.FirCachesFactory import org.jetbrains.kotlin.fir.checkers.registerCommonCheckers +import org.jetbrains.kotlin.fir.checkers.registerExtendedCommonCheckers import org.jetbrains.kotlin.fir.dependenciesWithoutSelf import org.jetbrains.kotlin.fir.java.JavaSymbolProvider import org.jetbrains.kotlin.fir.java.deserialization.KotlinDeserializedJvmSymbolsProvider @@ -133,7 +134,7 @@ internal object FirIdeSessionFactory { registerJavaSpecificResolveComponents() FirSessionFactory.FirSessionConfigurator(this).apply { if (isRootModule) { - registerCommonCheckers() + registerExtendedCommonCheckers() } }.configure() }