FIR checker: Add utility functions for FirModifierList.
This commit is contained in:
committed by
Ilya Kirillov
parent
315047b164
commit
7d31ea3e8f
+1
-3
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirModifierList.Companion.getModifierList
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
@@ -21,8 +20,7 @@ object FirConstPropertyChecker : FirPropertyChecker() {
|
||||
if (!declaration.isConst) return
|
||||
|
||||
if (declaration.isVar) {
|
||||
val modifierList = with(FirModifierList) { declaration.source.getModifierList() }
|
||||
val constModifier = modifierList?.modifiers?.firstOrNull { it.token == KtTokens.CONST_KEYWORD }
|
||||
val constModifier = declaration.getModifier(KtTokens.CONST_KEYWORD)
|
||||
constModifier?.let {
|
||||
reporter.reportOn(it.source, FirErrors.WRONG_MODIFIER_TARGET, it.token, "vars", context)
|
||||
}
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ object FirConstructorAllowedChecker : FirConstructorChecker() {
|
||||
reporter.reportOn(source, FirErrors.NON_PRIVATE_CONSTRUCTOR_IN_ENUM, context)
|
||||
}
|
||||
ClassKind.CLASS -> if (containingClass is FirRegularClass && containingClass.modality == Modality.SEALED) {
|
||||
val modifierList = with(FirModifierList) { source.getModifierList() } ?: return
|
||||
val modifierList = source.getModifierList() ?: return
|
||||
val hasIllegalModifier = modifierList.modifiers.any {
|
||||
it.token != KtTokens.PROTECTED_KEYWORD && it.token != KtTokens.PRIVATE_KEYWORD
|
||||
}
|
||||
|
||||
+2
-3
@@ -85,7 +85,7 @@ internal fun checkPropertyInitializer(
|
||||
context: CheckerContext
|
||||
) {
|
||||
val inInterface = containingClass?.isInterface == true
|
||||
val hasAbstractModifier = modifierList?.modifiers?.any { it.token == KtTokens.ABSTRACT_KEYWORD } == true
|
||||
val hasAbstractModifier = KtTokens.ABSTRACT_KEYWORD in modifierList
|
||||
val isAbstract = property.isAbstract || hasAbstractModifier
|
||||
if (isAbstract) {
|
||||
if (property.initializer == null && property.delegate == null && property.returnTypeRef is FirImplicitTypeRef) {
|
||||
@@ -184,6 +184,5 @@ internal val FirClass<*>.canHaveOpenMembers: Boolean get() = modality() != Modal
|
||||
internal fun FirRegularClass.isInlineOrValueClass(): Boolean {
|
||||
if (this.classKind != ClassKind.CLASS) return false
|
||||
|
||||
val modifierList = with(FirModifierList) { source.getModifierList() }
|
||||
return isInline || modifierList?.modifiers?.any { it.token == KtTokens.VALUE_KEYWORD } == true
|
||||
return isInline || hasModifier(KtTokens.VALUE_KEYWORD)
|
||||
}
|
||||
|
||||
+1
-2
@@ -173,8 +173,7 @@ object FirInlineClassDeclarationChecker : FirRegularClassChecker() {
|
||||
private fun FirValueParameter.isNotFinalReadOnly(primaryConstructorProperty: FirProperty?): Boolean {
|
||||
if (primaryConstructorProperty == null) return true
|
||||
|
||||
val modifierList = with(FirModifierList) { source.getModifierList() }
|
||||
val isOpen = modifierList?.modifiers?.any { it.token == KtTokens.OPEN_KEYWORD } == true
|
||||
val isOpen = hasModifier(KtTokens.OPEN_KEYWORD)
|
||||
|
||||
return isVararg || !primaryConstructorProperty.isVal || isOpen
|
||||
}
|
||||
|
||||
+3
-3
@@ -34,8 +34,8 @@ object FirMemberFunctionsChecker : FirRegularClassChecker() {
|
||||
if (source.kind is FirFakeSourceElementKind) return
|
||||
// If multiple (potentially conflicting) modality modifiers are specified, not all modifiers are recorded at `status`.
|
||||
// So, our source of truth should be the full modifier list retrieved from the source.
|
||||
val modifierList = with(FirModifierList) { source.getModifierList() }
|
||||
val hasAbstractModifier = modifierList?.modifiers?.any { it.token == KtTokens.ABSTRACT_KEYWORD } == true
|
||||
val modifierList = source.getModifierList()
|
||||
val hasAbstractModifier = KtTokens.ABSTRACT_KEYWORD in modifierList
|
||||
val isAbstract = function.isAbstract || hasAbstractModifier
|
||||
if (isAbstract) {
|
||||
if (!containingDeclaration.canHaveAbstractDeclaration) {
|
||||
@@ -49,7 +49,7 @@ object FirMemberFunctionsChecker : FirRegularClassChecker() {
|
||||
}
|
||||
}
|
||||
val isInsideExpectClass = isInsideExpectClass(containingDeclaration, context)
|
||||
val hasOpenModifier = modifierList?.modifiers?.any { it.token == KtTokens.OPEN_KEYWORD } == true
|
||||
val hasOpenModifier = KtTokens.OPEN_KEYWORD in modifierList
|
||||
if (!function.hasBody) {
|
||||
if (containingDeclaration.isInterface) {
|
||||
if (Visibilities.isPrivate(function.visibility)) {
|
||||
|
||||
+3
-3
@@ -146,7 +146,7 @@ object FirMemberPropertiesChecker : FirRegularClassChecker() {
|
||||
if (source.kind is FirFakeSourceElementKind) return
|
||||
// If multiple (potentially conflicting) modality modifiers are specified, not all modifiers are recorded at `status`.
|
||||
// So, our source of truth should be the full modifier list retrieved from the source.
|
||||
val modifierList = with(FirModifierList) { property.source.getModifierList() }
|
||||
val modifierList = property.source.getModifierList()
|
||||
|
||||
checkPropertyInitializer(
|
||||
containingDeclaration,
|
||||
@@ -159,7 +159,7 @@ object FirMemberPropertiesChecker : FirRegularClassChecker() {
|
||||
checkPropertyAccessors(property, reporter, context)
|
||||
checkExpectDeclarationVisibilityAndBody(property, source, reporter, context)
|
||||
|
||||
val hasAbstractModifier = modifierList?.modifiers?.any { it.token == KtTokens.ABSTRACT_KEYWORD } == true
|
||||
val hasAbstractModifier = KtTokens.ABSTRACT_KEYWORD in modifierList
|
||||
val isAbstract = property.isAbstract || hasAbstractModifier
|
||||
if (containingDeclaration.isInterface &&
|
||||
Visibilities.isPrivate(property.visibility) &&
|
||||
@@ -203,7 +203,7 @@ object FirMemberPropertiesChecker : FirRegularClassChecker() {
|
||||
}
|
||||
}
|
||||
|
||||
val hasOpenModifier = modifierList?.modifiers?.any { it.token == KtTokens.OPEN_KEYWORD } == true
|
||||
val hasOpenModifier = KtTokens.OPEN_KEYWORD in modifierList
|
||||
if (hasOpenModifier &&
|
||||
containingDeclaration.isInterface &&
|
||||
!hasAbstractModifier &&
|
||||
|
||||
+1
-1
@@ -169,7 +169,7 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
|
||||
if (!isDeclarationMappedToSourceCorrectly(declaration, source)) return
|
||||
if (context.containingDeclarations.last() is FirDefaultPropertyAccessor) return
|
||||
|
||||
val modifierList = with(FirModifierList) { source.getModifierList() }
|
||||
val modifierList = source.getModifierList()
|
||||
modifierList?.let { checkModifiers(it, declaration, reporter, context) }
|
||||
}
|
||||
|
||||
|
||||
+22
-13
@@ -12,6 +12,7 @@ import com.intellij.util.diff.FlyweightCapableTreeStructure
|
||||
import org.jetbrains.kotlin.KtNodeTypes
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.getChildren
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtModifierList
|
||||
@@ -44,19 +45,9 @@ internal sealed class FirModifierList {
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun FirSourceElement?.getModifierList(): FirModifierList? {
|
||||
return when (this) {
|
||||
null -> null
|
||||
is FirPsiSourceElement<*> -> (psi as? KtModifierListOwner)?.modifierList?.let { FirPsiModifierList(it) }
|
||||
is FirLightSourceElement -> {
|
||||
val modifierListNode = lighterASTNode.getChildren(treeStructure).find { it?.tokenType == KtNodeTypes.MODIFIER_LIST }
|
||||
?: return null
|
||||
FirLightModifierList(modifierListNode, treeStructure)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
operator fun get(token: KtModifierKeywordToken): FirModifier<*>? = modifiers.firstOrNull { it.token == token }
|
||||
|
||||
operator fun contains(token: KtModifierKeywordToken): Boolean = modifiers.any { it.token == token }
|
||||
}
|
||||
|
||||
private val MODIFIER_KEYWORD_SET = TokenSet.orSet(KtTokens.SOFT_KEYWORDS, TokenSet.create(KtTokens.IN_KEYWORD, KtTokens.FUN_KEYWORD))
|
||||
@@ -82,3 +73,21 @@ internal sealed class FirModifier<Node : Any>(val node: Node, val token: KtModif
|
||||
|
||||
abstract val source: FirSourceElement
|
||||
}
|
||||
|
||||
internal fun FirSourceElement?.getModifierList(): FirModifierList? {
|
||||
return when (this) {
|
||||
null -> null
|
||||
is FirPsiSourceElement<*> -> (psi as? KtModifierListOwner)?.modifierList?.let { FirModifierList.FirPsiModifierList(it) }
|
||||
is FirLightSourceElement -> {
|
||||
val modifierListNode = lighterASTNode.getChildren(treeStructure).find { it?.tokenType == KtNodeTypes.MODIFIER_LIST }
|
||||
?: return null
|
||||
FirModifierList.FirLightModifierList(modifierListNode, treeStructure)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal operator fun FirModifierList?.contains(token: KtModifierKeywordToken): Boolean = this?.contains(token) == true
|
||||
|
||||
internal fun FirDeclaration.getModifier(token: KtModifierKeywordToken): FirModifier<*>? = source.getModifierList()?.get(token)
|
||||
|
||||
internal fun FirDeclaration.hasModifier(token: KtModifierKeywordToken): Boolean = token in source.getModifierList()
|
||||
|
||||
+1
-3
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.fir.FirRealSourceElementKind
|
||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirModifierList.Companion.getModifierList
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
@@ -29,7 +28,7 @@ object FirOpenMemberChecker : FirClassChecker() {
|
||||
memberDeclaration is FirConstructor
|
||||
) continue
|
||||
val source = memberDeclaration.source ?: continue
|
||||
if (memberDeclaration.isOpen || (source.hasOpenModifierInSource && source.shouldReportOpenFromSource)) {
|
||||
if (memberDeclaration.isOpen || memberDeclaration.hasModifier(KtTokens.OPEN_KEYWORD) && source.shouldReportOpenFromSource) {
|
||||
if (declaration.classKind == ClassKind.OBJECT) {
|
||||
reporter.reportOn(source, FirErrors.NON_FINAL_MEMBER_IN_OBJECT, context)
|
||||
} else {
|
||||
@@ -39,7 +38,6 @@ object FirOpenMemberChecker : FirClassChecker() {
|
||||
}
|
||||
}
|
||||
|
||||
private val FirSourceElement.hasOpenModifierInSource: Boolean get() = getModifierList()?.modifiers?.any { it.token == KtTokens.OPEN_KEYWORD } == true
|
||||
private val FirSourceElement.shouldReportOpenFromSource: Boolean
|
||||
get() = when (kind) {
|
||||
FirRealSourceElementKind,
|
||||
|
||||
+1
-2
@@ -28,8 +28,7 @@ object FirTopLevelFunctionsChecker : FirFileChecker() {
|
||||
if (source.kind is FirFakeSourceElementKind) return
|
||||
// If multiple (potentially conflicting) modality modifiers are specified, not all modifiers are recorded at `status`.
|
||||
// So, our source of truth should be the full modifier list retrieved from the source.
|
||||
val modifierList = with(FirModifierList) { source.getModifierList() }
|
||||
if (modifierList?.modifiers?.any { it.token == KtTokens.ABSTRACT_KEYWORD } == true) return
|
||||
if (function.hasModifier(KtTokens.ABSTRACT_KEYWORD)) return
|
||||
if (function.isExternal) return
|
||||
if (!function.hasBody && !function.isExpect) {
|
||||
reporter.reportOn(source, FirErrors.NON_MEMBER_FUNCTION_NO_BODY, function, context)
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ object FirTopLevelPropertiesChecker : FirFileChecker() {
|
||||
if (source.kind is FirFakeSourceElementKind) return
|
||||
// If multiple (potentially conflicting) modality modifiers are specified, not all modifiers are recorded at `status`.
|
||||
// So, our source of truth should be the full modifier list retrieved from the source.
|
||||
val modifierList = with(FirModifierList) { source.getModifierList() }
|
||||
val modifierList = source.getModifierList()
|
||||
|
||||
checkPropertyInitializer(
|
||||
containingClass = null,
|
||||
|
||||
+3
-2
@@ -9,6 +9,8 @@ import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirMemberDeclarationChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirModifierList
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.getModifier
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.getModifierList
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
@@ -29,8 +31,7 @@ object FirJvmExternalDeclarationChecker : FirMemberDeclarationChecker() {
|
||||
is FirRegularClass -> "class"
|
||||
else -> "non-function declaration"
|
||||
}
|
||||
val modifierList = with(FirModifierList) { source.getModifierList() }
|
||||
val externalModifier = modifierList?.modifiers?.firstOrNull { it.token == KtTokens.EXTERNAL_KEYWORD }
|
||||
val externalModifier = declaration.getModifier(KtTokens.EXTERNAL_KEYWORD)
|
||||
externalModifier?.let {
|
||||
reporter.reportOn(it.source, FirErrors.WRONG_MODIFIER_TARGET, it.token, target, context)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user