[FIR] Fix disappeared INVALID_CHARACTERS_NATIVE_ERROR

https://youtrack.jetbrains.com/issue/KT-60003/K2-Disappeared-INVALIDCHARACTERSNATIVEERROR

^KT-60003 Fixed

Merge-request: KT-MR-12686
Merged-by: Vladimir Sukharev <Vladimir.Sukharev@jetbrains.com>
This commit is contained in:
Vladimir Sukharev
2023-10-24 16:28:30 +00:00
committed by Space Team
parent 07c4cd231c
commit 8395018de8
9 changed files with 134 additions and 180 deletions
@@ -37,7 +37,7 @@ object FirNativeIdentifierChecker : FirBasicDeclarationChecker() {
}
}
private fun checkNameAndReport(name: Name, source: KtSourceElement?, context: CheckerContext, reporter: DiagnosticReporter) {
internal fun checkNameAndReport(name: Name, source: KtSourceElement?, context: CheckerContext, reporter: DiagnosticReporter) {
if (source != null && source.kind !is KtFakeSourceElementKind && !name.isSpecial) {
val text = name.asString()
val message = when {
@@ -0,0 +1,29 @@
/*
* Copyright 2010-2023 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.fir.analysis.native.checkers
import org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirFileChecker
import org.jetbrains.kotlin.fir.analysis.forEachChildOfType
import org.jetbrains.kotlin.fir.analysis.native.checkers.FirNativeIdentifierChecker.checkNameAndReport
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.text
object FirNativePackageDirectiveChecker : FirFileChecker() {
override fun check(declaration: FirFile, context: CheckerContext, reporter: DiagnosticReporter) {
declaration.packageDirective.source?.forEachChildOfType(setOf(REFERENCE_EXPRESSION)) {
checkNameAndReport(
Name.identifier(it.text.toString()),
it,
context,
reporter
)
}
}
}
@@ -33,4 +33,9 @@ object NativeDeclarationCheckers : DeclarationCheckers() {
FirNativeObjCRefinementAnnotationChecker,
FirNativeHiddenFromObjCInheritanceChecker,
)
override val fileCheckers: Set<FirFileChecker>
get() = setOf(
FirNativePackageDirectiveChecker,
)
}
+4 -1
View File
@@ -2,10 +2,11 @@
## Checkers structure
There are four kinds of checkers:
There are six kinds of checkers:
- [DeclarationChecker](./src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationChecker.kt)
- [ExpressionChecker](./src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirExpressionChecker.kt)
- [FirTypeChecker](./src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirTypeChecker.kt)
- [FirLanguageVersionSettingsChecker](./src/org/jetbrains/kotlin/fir/analysis/checkers/config/FirLanguageVersionSettingsChecker.kt)
- [FirControlFlowChecker](./src/org/jetbrains/kotlin/fir/analysis/checkers/cfa/FirControlFlowChecker.kt)
The first three kinds are typed and may be restricted to checking only a specific type of declaration/expression/type ref. To simplify working with checkers for different FIR elements, there is a number of typed typealiases:
@@ -13,6 +14,8 @@ The first three kinds are typed and may be restricted to checking only a specifi
- Expressions: [FirExpressionCheckerAliases.kt](./gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirExpressionCheckerAliases.kt)
- Type refs: [FirTypeCheckerAliases.kt](./gen/org/jetbrains/kotlin/fir/analysis/checkers/type/FirTypeCheckerAliases.kt)
The next kind, `FirLanguageVersionSettingsChecker`, is to check language version settings independently of particular code pieces.
The last kind of checker, `FirControlFlowChecker`, is for checkers which perform Control Flow Analysis (CFA) and is supposed to work with every declaration that has its own Control Flow Graph (CFG)
## Checkers contracts
@@ -6,41 +6,110 @@
package org.jetbrains.kotlin.fir.analysis
import com.intellij.lang.LighterASTNode
import com.intellij.psi.PsiElement
import com.intellij.psi.tree.IElementType
import com.intellij.psi.tree.TokenSet
import com.intellij.util.diff.FlyweightCapableTreeStructure
import org.jetbrains.kotlin.*
import org.jetbrains.kotlin.fir.declarations.FirImport
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.psiUtil.allChildren
import org.jetbrains.kotlin.util.getChildren
import org.jetbrains.kotlin.utils.addToStdlib.butIf
import org.jetbrains.kotlin.utils.addToStdlib.popLast
fun KtSourceElement.getChild(type: IElementType, index: Int = 0, depth: Int = -1, reverse: Boolean = false): KtSourceElement? {
return getChild(setOf(type), index, depth, reverse)
}
fun KtSourceElement.getChild(type: IElementType, index: Int = 0, depth: Int = -1, reverse: Boolean = false): KtSourceElement? =
getChild(setOf(type), index, depth, reverse)
fun KtSourceElement.getChild(types: TokenSet, index: Int = 0, depth: Int = -1, reverse: Boolean = false): KtSourceElement? {
return getChild(types.types.toSet(), index, depth, reverse)
}
fun KtSourceElement.getChild(types: TokenSet, index: Int = 0, depth: Int = -1, reverse: Boolean = false): KtSourceElement? =
getChild(types.types.toSet(), index, depth, reverse)
fun KtSourceElement.getChild(types: Set<IElementType>, index: Int = 0, depth: Int = -1, reverse: Boolean = false): KtSourceElement? {
return when (this) {
is KtPsiSourceElement -> {
getChild(types, index, depth, reverse)
var idx = index
forEachChildOfType(types, depth, reverse) {
if (idx-- == 0) {
return it
}
is KtLightSourceElement -> {
getChild(types, index, depth, reverse)
}
else -> null
}
return null
}
/**
* Iterates recursively over all children up to the given depth.
* `processChild` is invoked for each child having a type in the `types` set.
*/
inline fun KtSourceElement.forEachChildOfType(
types: Set<IElementType>,
depth: Int = -1,
reverse: Boolean = false,
processChild: (KtSourceElement) -> Unit,
) = when (this) {
is KtPsiSourceElement -> psi.forEachChildOfType(types, depth, reverse) {
processChild(it.toKtPsiSourceElement())
}
is KtLightSourceElement -> lighterASTNode.forEachChildOfType(types, depth, reverse, treeStructure) {
processChild(it.toKtLightSourceElement(treeStructure))
}
}
private fun KtPsiSourceElement.getChild(types: Set<IElementType>, index: Int, depth: Int, reverse: Boolean): KtSourceElement? {
val visitor = PsiElementFinderByType(types, index, depth, reverse)
return visitor.find(psi)?.toKtPsiSourceElement()
}
/**
* See [KtSourceElement.forEachChildOfType]
*/
inline fun PsiElement.forEachChildOfType(
types: Set<IElementType>,
depth: Int = -1,
reverse: Boolean = false,
processChild: (PsiElement) -> Unit,
) = forEachChildOfType(
this, types, depth, reverse,
getElementType = { it.node.elementType },
getChildren = { it.allChildren.toList() },
processChild,
)
private fun KtLightSourceElement.getChild(types: Set<IElementType>, index: Int, depth: Int, reverse: Boolean): KtSourceElement? {
val visitor = LighterTreeElementFinderByType(treeStructure, types, index, depth, reverse)
val childNode = visitor.find(lighterASTNode) ?: return null
return buildChildSourceElement(childNode)
/**
* See [KtSourceElement.forEachChildOfType]
*/
inline fun LighterASTNode.forEachChildOfType(
types: Set<IElementType>,
depth: Int = -1,
reverse: Boolean = false,
treeStructure: FlyweightCapableTreeStructure<LighterASTNode>,
processChild: (LighterASTNode) -> Unit,
) = forEachChildOfType(
this, types, depth, reverse,
getElementType = { it.tokenType },
getChildren = { it.getChildren(treeStructure) },
processChild,
)
inline fun <T> forEachChildOfType(
root: T,
types: Set<IElementType>,
depth: Int = -1,
reverse: Boolean = false,
getElementType: (T) -> IElementType,
getChildren: (T) -> List<T>,
processChild: (T) -> Unit,
) {
val stack = mutableListOf(root to 0)
while (stack.isNotEmpty()) {
val (element, currentDepth) = stack.popLast()
if (currentDepth != 0 && getElementType(element) in types) {
processChild(element)
}
if (currentDepth == depth) {
continue
}
getChildren(element).butIf(!reverse) { it.asReversed() }.forEach { child ->
stack += child to (currentDepth + 1)
}
}
}
/**
@@ -1,45 +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.fir.analysis
import com.intellij.lang.LighterASTNode
import com.intellij.psi.tree.IElementType
import com.intellij.util.diff.FlyweightCapableTreeStructure
import org.jetbrains.kotlin.util.getChildren
class LighterTreeElementFinderByType(
private val tree: FlyweightCapableTreeStructure<LighterASTNode>,
private var types: Collection<IElementType>,
private var index: Int,
private val depth: Int,
private val reverse: Boolean,
) {
fun find(node: LighterASTNode?): LighterASTNode? {
if (node == null) return null
return visitNode(node, 0)
}
private fun visitNode(node: LighterASTNode, currentDepth: Int): LighterASTNode? {
if (currentDepth != 0) {
if (node.tokenType in types) {
if (index == 0) {
return node
}
index--
}
}
if (currentDepth == depth) return null
val children = if (reverse) node.getChildren(tree).asReversed() else node.getChildren(tree)
for (child in children) {
val result = visitNode(child, currentDepth + 1)
if (result != null) return result
}
return null
}
}
@@ -1,43 +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.fir.analysis
import com.intellij.psi.PsiElement
import com.intellij.psi.tree.IElementType
import org.jetbrains.kotlin.psi.psiUtil.allChildren
class PsiElementFinderByType(
private val types: Collection<IElementType>,
private var index: Int,
private val depth: Int,
private val reverse: Boolean,
) {
fun find(root: PsiElement): PsiElement? {
return visitElement(root, 0)
}
private fun visitElement(element: PsiElement, currentDepth: Int): PsiElement? {
if (currentDepth != 0) {
if (element.node.elementType in types) {
if (index == 0) {
return element
}
index--
}
}
if (currentDepth == depth) return null
val children = if (reverse) element.allChildren.toList().asReversed().iterator() else element.allChildren.iterator()
for (child in children) {
val result = visitElement(child, currentDepth + 1)
if (result != null) return result
}
return null
}
}
@@ -1,68 +0,0 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE -MISSING_DEPENDENCY_SUPERCLASS
// FIXME: rename identifiers.kt
// FILE: 1.kt
package `check.pkg`
// FILE: 2.kt
package totally.normal.pkg
class <!INVALID_CHARACTERS_NATIVE_ERROR!>`Check.Class`<!>
class NormalClass {
fun <!INVALID_CHARACTERS_NATIVE_ERROR!>`check$member`<!>() {}
}
object <!INVALID_CHARACTERS_NATIVE_ERROR!>`Check;Object`<!>
object NormalObject
data class Pair(val first: Int, val <!INVALID_CHARACTERS_NATIVE_ERROR!>`next,one`<!>: Int)
object Delegate {
operator fun getValue(thisRef: Any?, property: kotlin.reflect.KProperty<*>): Any? = null
}
fun <!INVALID_CHARACTERS_NATIVE_ERROR!>`check(function`<!>() {
val <!INVALID_CHARACTERS_NATIVE_ERROR!>`check)variable`<!> = 1
val <!INVALID_CHARACTERS_NATIVE_ERROR!>`check[delegated[variable`<!> by Delegate
val normalVariable = 2
val normalDelegatedVariable by Delegate
val (check, <!INVALID_CHARACTERS_NATIVE_ERROR!>`destructuring]declaration`<!>) = Pair(1, 2)
}
fun normalFunction() {}
val <!INVALID_CHARACTERS_NATIVE_ERROR!>`check{property`<!> = 1
val <!INVALID_CHARACTERS_NATIVE_ERROR!>`check}delegated}property`<!> by Delegate
val normalProperty = 2
val normalDelegatedProperty by Delegate
fun checkValueParameter(<!INVALID_CHARACTERS_NATIVE_ERROR!>`check/parameter`<!>: Int) {}
fun <<!INVALID_CHARACTERS_NATIVE_ERROR!>`check<type<parameter`<!>, normalTypeParameter> checkTypeParameter() {}
enum class <!INVALID_CHARACTERS_NATIVE_ERROR!>`Check>Enum>Entry`<!> {
<!INVALID_CHARACTERS_NATIVE_ERROR!>`CHECK:ENUM:ENTRY`<!>;
}
typealias <!INVALID_CHARACTERS_NATIVE_ERROR!>`check\typealias`<!> = Any
fun <!INVALID_CHARACTERS_NATIVE_ERROR!>`check&`<!>() {}
fun <!INVALID_CHARACTERS_NATIVE_ERROR!>`check~`<!>() {}
fun <!INVALID_CHARACTERS_NATIVE_ERROR!>`check*`<!>() {}
fun <!INVALID_CHARACTERS_NATIVE_ERROR!>`check?`<!>() {}
fun <!INVALID_CHARACTERS_NATIVE_ERROR!>`check#`<!>() {}
fun <!INVALID_CHARACTERS_NATIVE_ERROR!>`check|`<!>() {}
fun <!INVALID_CHARACTERS_NATIVE_ERROR!>`check§`<!>() {}
fun <!INVALID_CHARACTERS_NATIVE_ERROR!>`check%`<!>() {}
fun <!INVALID_CHARACTERS_NATIVE_ERROR!>`check@`<!>() {}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE -MISSING_DEPENDENCY_SUPERCLASS
// FIXME: rename identifiers.kt
@@ -5,6 +6,9 @@
// FILE: 1.kt
package <!INVALID_CHARACTERS_NATIVE_ERROR!>`check.pkg`<!>
// FILE: 11.kt
package one.<!INVALID_CHARACTERS_NATIVE_ERROR!>`two.three`<!>.four.<!INVALID_CHARACTERS_NATIVE_ERROR!>`five.six`<!>.seven
// FILE: 2.kt
package totally.normal.pkg