FIR checker: Add utility functions for FirModifierList.

This commit is contained in:
Mark Punzalan
2021-03-16 09:54:07 +00:00
committed by Ilya Kirillov
parent 315047b164
commit 7d31ea3e8f
12 changed files with 40 additions and 37 deletions
@@ -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)
}
@@ -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
}
@@ -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)
}
@@ -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
}
@@ -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)) {
@@ -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 &&
@@ -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) }
}
@@ -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()
@@ -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,
@@ -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)
@@ -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,
@@ -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)
}