Support FirDiagnostic.isValid properly

Diagnostic is considered valid in this commit if it's reported on
a syntactically non-erroneous element without erroneous last child
This commit is contained in:
Mikhail Glukhikh
2020-11-17 18:05:30 +03:00
parent c7ae176ae4
commit fa3f805573
3 changed files with 33 additions and 2 deletions
@@ -25,7 +25,7 @@ sealed class FirDiagnostic<out E : FirSourceElement> : Diagnostic {
get() = factory.getTextRanges(this)
override val isValid: Boolean
get() = true
get() = factory.isValid(this)
}
sealed class FirSimpleDiagnostic<out E : FirSourceElement> : FirDiagnostic<E>() {
@@ -29,6 +29,11 @@ sealed class AbstractFirDiagnosticFactory<out E : FirSourceElement, D : FirDiagn
fun getTextRanges(diagnostic: FirDiagnostic<*>): List<TextRange> =
positioningStrategy.markDiagnostic(diagnostic)
fun isValid(diagnostic: FirDiagnostic<*>): Boolean {
val element = diagnostic.element
return positioningStrategy.isValid(element.lighterASTNode, element.treeStructure)
}
}
class FirDiagnosticFactory0<E : FirSourceElement, P : PsiElement>(
@@ -6,9 +6,13 @@
package org.jetbrains.kotlin.fir.analysis.diagnostics
import com.intellij.lang.LighterASTNode
import com.intellij.openapi.util.Ref
import com.intellij.openapi.util.TextRange
import com.intellij.psi.TokenType
import com.intellij.util.diff.FlyweightCapableTreeStructure
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.lexer.KtSingleValueToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE
open class LightTreePositioningStrategy {
open fun markDiagnostic(diagnostic: FirDiagnostic<*>): List<TextRange> {
@@ -20,6 +24,10 @@ open class LightTreePositioningStrategy {
return markElement(node, tree)
}
open fun isValid(node: LighterASTNode, tree: FlyweightCapableTreeStructure<LighterASTNode>): Boolean {
return !hasSyntaxErrors(node, tree)
}
companion object {
val DEFAULT = LightTreePositioningStrategies.DEFAULT
}
@@ -32,3 +40,21 @@ fun markElement(node: LighterASTNode, tree: FlyweightCapableTreeStructure<Lighte
fun markRange(from: LighterASTNode, to: LighterASTNode, tree: FlyweightCapableTreeStructure<LighterASTNode>): List<TextRange> {
return listOf(TextRange(tree.getStartOffset(from), tree.getEndOffset(to)))
}
private val DOC_AND_COMMENT_TOKENS = setOf(
WHITE_SPACE, KtTokens.IDENTIFIER,
KtTokens.EOL_COMMENT, KtTokens.BLOCK_COMMENT, KtTokens.SHEBANG_COMMENT, KtTokens.DOC_COMMENT
)
private fun hasSyntaxErrors(node: LighterASTNode, tree: FlyweightCapableTreeStructure<LighterASTNode>): Boolean {
if (node.tokenType == TokenType.ERROR_ELEMENT) return true
val childrenRef = Ref<Array<LighterASTNode>>()
tree.getChildren(node, childrenRef)
val children = childrenRef.get()
return children.lastOrNull {
val tokenType = it.tokenType
tokenType !is KtSingleValueToken && tokenType !in DOC_AND_COMMENT_TOKENS
}?.let { hasSyntaxErrors(it, tree) } == true
}