FIR IDE: fix collecting diagnostics multiple times for the same declaration

^KT-45199 fixed
This commit is contained in:
Ilya Kirillov
2021-02-26 17:00:31 +01:00
parent 4acca2fa16
commit 0b921ed9d8
4 changed files with 27 additions and 26 deletions
@@ -58,7 +58,7 @@ abstract class AbstractDiagnosticCollector(
@Suppress("LeakingThis") @Suppress("LeakingThis")
private var context = PersistentCheckerContext(this, returnTypeCalculator) private var context = PersistentCheckerContext(this, returnTypeCalculator)
private var currentAction = DiagnosticCollectorDeclarationAction.CHECK_CURRENT_DECLARATION_AND_CHECK_NESTED private var currentAction = DiagnosticCollectorDeclarationAction.CHECK_IN_CURRENT_DECLARATION_AND_LOOKUP_FOR_NESTED
fun initializeComponents(vararg components: AbstractDiagnosticCollectorComponent) { fun initializeComponents(vararg components: AbstractDiagnosticCollectorComponent) {
if (componentsInitialized) { if (componentsInitialized) {
@@ -72,9 +72,11 @@ abstract class AbstractDiagnosticCollector(
private inner class Visitor : FirDefaultVisitor<Unit, Nothing?>() { private inner class Visitor : FirDefaultVisitor<Unit, Nothing?>() {
private fun <T : FirElement> T.runComponents() { private fun <T : FirElement> T.runComponents() {
components.forEach { if (currentAction.checkInCurrentDeclaration) {
beforeCollecting() components.forEach {
this.accept(it, context) beforeCollecting()
this.accept(it, context)
}
} }
} }
@@ -220,13 +222,11 @@ abstract class AbstractDiagnosticCollector(
declaration: FirDeclaration, declaration: FirDeclaration,
block: () -> Unit = { declaration.acceptChildren(this, null) } block: () -> Unit = { declaration.acceptChildren(this, null) }
) { ) {
if (!currentAction.checkNested) return if (!currentAction.lookupForNestedDeclaration) return
val action = onDeclarationEnter(declaration) val action = getDeclarationActionOnDeclarationEnter(declaration)
if (action.checkCurrentDeclaration) {
declaration.runComponents()
}
withDiagnosticsAction(action) { withDiagnosticsAction(action) {
declaration.runComponents()
withDeclaration(declaration) { withDeclaration(declaration) {
block() block()
} }
@@ -258,8 +258,8 @@ abstract class AbstractDiagnosticCollector(
} }
} }
protected open fun onDeclarationEnter(declaration: FirDeclaration): DiagnosticCollectorDeclarationAction = protected open fun getDeclarationActionOnDeclarationEnter(declaration: FirDeclaration): DiagnosticCollectorDeclarationAction =
DiagnosticCollectorDeclarationAction.CHECK_CURRENT_DECLARATION_AND_CHECK_NESTED DiagnosticCollectorDeclarationAction.CHECK_IN_CURRENT_DECLARATION_AND_LOOKUP_FOR_NESTED
protected open fun onDeclarationExit(declaration: FirDeclaration) {} protected open fun onDeclarationExit(declaration: FirDeclaration) {}
@@ -334,11 +334,11 @@ abstract class AbstractDiagnosticCollector(
} }
} }
enum class DiagnosticCollectorDeclarationAction(val checkCurrentDeclaration: Boolean, val checkNested: Boolean) { enum class DiagnosticCollectorDeclarationAction(val checkInCurrentDeclaration: Boolean, val lookupForNestedDeclaration: Boolean) {
CHECK_CURRENT_DECLARATION_AND_CHECK_NESTED(checkCurrentDeclaration = true, checkNested = true), CHECK_IN_CURRENT_DECLARATION_AND_LOOKUP_FOR_NESTED(checkInCurrentDeclaration = true, lookupForNestedDeclaration = true),
CHECK_CURRENT_DECLARATION_AND_SKIP_NESTED(checkCurrentDeclaration = true, checkNested = false), CHECK_IN_CURRENT_DECLARATION_AND_DO_NOT_LOOKUP_FOR_NESTED(checkInCurrentDeclaration = true, lookupForNestedDeclaration = false),
SKIP_CURRENT_DECLARATION_AND_CHECK_NESTED(checkCurrentDeclaration = false, checkNested = true), DO_NOT_CHECK_IN_CURRENT_DECLARATION_AND_LOOKUP_FOR_NESTED(checkInCurrentDeclaration = false, lookupForNestedDeclaration = true),
SKIP(checkCurrentDeclaration = false, checkNested = false), SKIP(checkInCurrentDeclaration = false, lookupForNestedDeclaration = false),
} }
fun AbstractDiagnosticCollector.registerAllComponents() { fun AbstractDiagnosticCollector.registerAllComponents() {
@@ -10,6 +10,7 @@ import com.intellij.util.SmartList
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.idea.fir.low.level.api.api.DiagnosticCheckerFilter import org.jetbrains.kotlin.idea.fir.low.level.api.api.DiagnosticCheckerFilter
import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.FileStructureElement
internal class FileStructureElementDiagnostics( internal class FileStructureElementDiagnostics(
private val firFile: FirFile, private val firFile: FirFile,
@@ -49,7 +49,7 @@ internal class FileStructureElementDiagnosticsCollector private constructor(priv
result.addValueFor(diagnostic.psiElement, diagnostic) result.addValueFor(diagnostic.psiElement, diagnostic)
} }
override fun onDeclarationEnter( override fun getDeclarationActionOnDeclarationEnter(
declaration: FirDeclaration, declaration: FirDeclaration,
): DiagnosticCollectorDeclarationAction = ): DiagnosticCollectorDeclarationAction =
onDeclarationEnter.invoke(declaration) onDeclarationEnter.invoke(declaration)
@@ -60,10 +60,10 @@ internal sealed class ReanalyzableStructureElement<KT : KtDeclaration>(firFile:
when { when {
firDeclaration == declaration -> { firDeclaration == declaration -> {
inCurrentDeclaration = true inCurrentDeclaration = true
DiagnosticCollectorDeclarationAction.CHECK_CURRENT_DECLARATION_AND_CHECK_NESTED DiagnosticCollectorDeclarationAction.CHECK_IN_CURRENT_DECLARATION_AND_LOOKUP_FOR_NESTED
} }
inCurrentDeclaration -> DiagnosticCollectorDeclarationAction.CHECK_CURRENT_DECLARATION_AND_CHECK_NESTED inCurrentDeclaration -> DiagnosticCollectorDeclarationAction.CHECK_IN_CURRENT_DECLARATION_AND_LOOKUP_FOR_NESTED
else -> DiagnosticCollectorDeclarationAction.SKIP_CURRENT_DECLARATION_AND_CHECK_NESTED else -> DiagnosticCollectorDeclarationAction.DO_NOT_CHECK_IN_CURRENT_DECLARATION_AND_LOOKUP_FOR_NESTED
} }
}, },
onDeclarationExit = { firDeclaration -> onDeclarationExit = { firDeclaration ->
@@ -176,19 +176,19 @@ internal class NonReanalyzableDeclarationStructureElement(
// Some generated declaration contains structures that we need to check. For example the FIR representation of an // Some generated declaration contains structures that we need to check. For example the FIR representation of an
// enum entry initializer, when present, is a generated anonymous object of kind `ENUM_ENTRY`. // enum entry initializer, when present, is a generated anonymous object of kind `ENUM_ENTRY`.
firDeclaration.isGeneratedDeclaration -> firDeclaration.isGeneratedDeclaration ->
DiagnosticCollectorDeclarationAction.SKIP_CURRENT_DECLARATION_AND_CHECK_NESTED DiagnosticCollectorDeclarationAction.DO_NOT_CHECK_IN_CURRENT_DECLARATION_AND_LOOKUP_FOR_NESTED
firDeclaration is FirFile -> DiagnosticCollectorDeclarationAction.CHECK_CURRENT_DECLARATION_AND_CHECK_NESTED firDeclaration is FirFile -> DiagnosticCollectorDeclarationAction.DO_NOT_CHECK_IN_CURRENT_DECLARATION_AND_LOOKUP_FOR_NESTED
firDeclaration == fir -> { firDeclaration == fir -> {
inCurrentDeclaration = true inCurrentDeclaration = true
DiagnosticCollectorDeclarationAction.CHECK_CURRENT_DECLARATION_AND_CHECK_NESTED DiagnosticCollectorDeclarationAction.CHECK_IN_CURRENT_DECLARATION_AND_LOOKUP_FOR_NESTED
} }
FileElementFactory.isReanalyzableContainer(firDeclaration.ktDeclaration) -> { FileElementFactory.isReanalyzableContainer(firDeclaration.ktDeclaration) -> {
DiagnosticCollectorDeclarationAction.SKIP DiagnosticCollectorDeclarationAction.SKIP
} }
inCurrentDeclaration -> { inCurrentDeclaration -> {
DiagnosticCollectorDeclarationAction.CHECK_CURRENT_DECLARATION_AND_CHECK_NESTED DiagnosticCollectorDeclarationAction.CHECK_IN_CURRENT_DECLARATION_AND_LOOKUP_FOR_NESTED
} }
else -> DiagnosticCollectorDeclarationAction.SKIP_CURRENT_DECLARATION_AND_CHECK_NESTED else -> DiagnosticCollectorDeclarationAction.DO_NOT_CHECK_IN_CURRENT_DECLARATION_AND_LOOKUP_FOR_NESTED
} }
}, },
onDeclarationExit = { firDeclaration -> onDeclarationExit = { firDeclaration ->
@@ -233,7 +233,7 @@ internal class RootStructureElement(
private object DiagnosticRetriever : FileStructureElementDiagnosticRetriever() { private object DiagnosticRetriever : FileStructureElementDiagnosticRetriever() {
override fun retrieve(firFile: FirFile, collector: FileStructureElementDiagnosticsCollector): FileStructureElementDiagnosticList { override fun retrieve(firFile: FirFile, collector: FileStructureElementDiagnosticsCollector): FileStructureElementDiagnosticList {
return collector.collectForStructureElement(firFile) { firDeclaration -> return collector.collectForStructureElement(firFile) { firDeclaration ->
if (firDeclaration is FirFile) DiagnosticCollectorDeclarationAction.CHECK_CURRENT_DECLARATION_AND_SKIP_NESTED if (firDeclaration is FirFile) DiagnosticCollectorDeclarationAction.CHECK_IN_CURRENT_DECLARATION_AND_DO_NOT_LOOKUP_FOR_NESTED
else DiagnosticCollectorDeclarationAction.SKIP else DiagnosticCollectorDeclarationAction.SKIP
} }
} }