[K2] Support reporting of SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS
...on regular classes and enum entries. ^KT-59979 Fixed
This commit is contained in:
committed by
Space Team
parent
32a87836c2
commit
a05b37c652
+1
-1
@@ -2512,7 +2512,7 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
override val diagnosticClass get() = ExpectedLateinitProperty::class
|
||||
}
|
||||
|
||||
interface SupertypeInitializedInExpectedClass : KtFirDiagnostic<PsiElement> {
|
||||
interface SupertypeInitializedInExpectedClass : KtFirDiagnostic<KtElement> {
|
||||
override val diagnosticClass get() = SupertypeInitializedInExpectedClass::class
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -3027,7 +3027,7 @@ internal class ExpectedLateinitPropertyImpl(
|
||||
internal class SupertypeInitializedInExpectedClassImpl(
|
||||
firDiagnostic: KtPsiDiagnostic,
|
||||
token: KtLifetimeToken,
|
||||
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.SupertypeInitializedInExpectedClass
|
||||
) : KtAbstractFirDiagnostic<KtElement>(firDiagnostic, token), KtFirDiagnostic.SupertypeInitializedInExpectedClass
|
||||
|
||||
internal class ExpectedPrivateDeclarationImpl(
|
||||
firDiagnostic: KtPsiDiagnostic,
|
||||
|
||||
+1
-1
@@ -1229,7 +1229,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
// TODO: need to cover `by` as well as delegate expression
|
||||
val EXPECTED_DELEGATED_PROPERTY by error<KtExpression>()
|
||||
val EXPECTED_LATEINIT_PROPERTY by error<KtModifierListOwner>(PositioningStrategy.LATEINIT_MODIFIER)
|
||||
val SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS by error<PsiElement>()
|
||||
val SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS by error<KtElement>(PositioningStrategy.SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS_DIAGNOSTIC)
|
||||
val EXPECTED_PRIVATE_DECLARATION by error<KtModifierListOwner>(PositioningStrategy.VISIBILITY_MODIFIER)
|
||||
val EXPECTED_EXTERNAL_DECLARATION by error<KtModifierListOwner>(PositioningStrategy.EXTERNAL_MODIFIER)
|
||||
val EXPECTED_TAILREC_FUNCTION by error<KtModifierListOwner>(PositioningStrategy.TAILREC_MODIFIER)
|
||||
|
||||
+1
@@ -117,6 +117,7 @@ enum class PositioningStrategy(private val strategy: String? = null) {
|
||||
CALL_ELEMENT_WITH_DOT,
|
||||
EXPECT_ACTUAL_MODIFIER,
|
||||
TYPEALIAS_TYPE_REFERENCE,
|
||||
SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS_DIAGNOSTIC,
|
||||
;
|
||||
|
||||
val expressionToCreate get() = "SourceElementPositioningStrategies.${strategy ?: name}"
|
||||
|
||||
+1
-1
@@ -642,7 +642,7 @@ object FirErrors {
|
||||
val EXPECTED_PROPERTY_INITIALIZER by error0<KtExpression>()
|
||||
val EXPECTED_DELEGATED_PROPERTY by error0<KtExpression>()
|
||||
val EXPECTED_LATEINIT_PROPERTY by error0<KtModifierListOwner>(SourceElementPositioningStrategies.LATEINIT_MODIFIER)
|
||||
val SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS by error0<PsiElement>()
|
||||
val SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS by error0<KtElement>(SourceElementPositioningStrategies.SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS_DIAGNOSTIC)
|
||||
val EXPECTED_PRIVATE_DECLARATION by error0<KtModifierListOwner>(SourceElementPositioningStrategies.VISIBILITY_MODIFIER)
|
||||
val EXPECTED_EXTERNAL_DECLARATION by error0<KtModifierListOwner>(SourceElementPositioningStrategies.EXTERNAL_MODIFIER)
|
||||
val EXPECTED_TAILREC_FUNCTION by error0<KtModifierListOwner>(SourceElementPositioningStrategies.TAILREC_MODIFIER)
|
||||
|
||||
+18
@@ -56,6 +56,13 @@ interface SourceNavigator {
|
||||
*/
|
||||
fun FirEnumEntry.hasBody(): Boolean?
|
||||
|
||||
/**
|
||||
* Returns whether this [FirEnumEntry] has an initializer in source, or `null` if the entry does not have a source.
|
||||
*
|
||||
* Reason of implementing this in [SourceNavigator] and not in FIR is same as in [hasBody] method.
|
||||
*/
|
||||
fun FirEnumEntry.hasInitializer(): Boolean?
|
||||
|
||||
companion object {
|
||||
|
||||
private val lightTreeInstance = LightTreeSourceNavigator()
|
||||
@@ -129,6 +136,12 @@ private open class LightTreeSourceNavigator : SourceNavigator {
|
||||
val childNodes = source.lighterASTNode.getChildren(source.treeStructure)
|
||||
return childNodes.any { it.tokenType == KtNodeTypes.CLASS_BODY }
|
||||
}
|
||||
|
||||
override fun FirEnumEntry.hasInitializer(): Boolean? {
|
||||
val source = source ?: return null
|
||||
val childNodes = source.lighterASTNode.getChildren(source.treeStructure)
|
||||
return childNodes.any { it.tokenType == KtNodeTypes.INITIALIZER_LIST }
|
||||
}
|
||||
}
|
||||
|
||||
//by default psi tree can reuse light tree manipulations
|
||||
@@ -176,4 +189,9 @@ private object PsiSourceNavigator : LightTreeSourceNavigator() {
|
||||
val enumEntryPsi = source?.psi as? KtEnumEntry ?: return null
|
||||
return enumEntryPsi.body != null
|
||||
}
|
||||
|
||||
override fun FirEnumEntry.hasInitializer(): Boolean? {
|
||||
val enumEntryPsi = source?.psi as? KtEnumEntry ?: return null
|
||||
return enumEntryPsi.initializerList != null
|
||||
}
|
||||
}
|
||||
|
||||
+18
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.fir.declarations.utils.isExpect
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isInline
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
||||
import org.jetbrains.kotlin.fir.expressions.FirDelegatedConstructorCall
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
|
||||
// See old FE's [DeclarationsChecker]
|
||||
object FirExpectConsistencyChecker : FirBasicDeclarationChecker() {
|
||||
@@ -43,6 +44,9 @@ object FirExpectConsistencyChecker : FirBasicDeclarationChecker() {
|
||||
getConstructorDelegationCall(declaration)?.let { delegatedConstructor ->
|
||||
reporter.reportOn(delegatedConstructor.source, FirErrors.EXPECTED_CLASS_CONSTRUCTOR_DELEGATION_CALL, context)
|
||||
}
|
||||
for (superTypeRef in getClassSuperTypeReferencesWithInitializers(declaration)) {
|
||||
reporter.reportOn(superTypeRef.source, FirErrors.SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS, context)
|
||||
}
|
||||
for (propertyParameter in getConstructorProhibitedPropertyParameters(declaration, lastClass)) {
|
||||
reporter.reportOn(propertyParameter.source, FirErrors.EXPECTED_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER, context)
|
||||
}
|
||||
@@ -52,6 +56,9 @@ object FirExpectConsistencyChecker : FirBasicDeclarationChecker() {
|
||||
if (isProhibitedEnumEntryWithBody(declaration)) {
|
||||
reporter.reportOn(source, FirErrors.EXPECTED_ENUM_ENTRY_WITH_BODY, context)
|
||||
}
|
||||
if (isProhibitedEnumEntryWithInitializer(declaration)) {
|
||||
reporter.reportOn(source, FirErrors.SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS, context)
|
||||
}
|
||||
|
||||
if (isProhibitedPrivateDeclaration(declaration)) {
|
||||
reporter.reportOn(source, FirErrors.EXPECTED_PRIVATE_DECLARATION, context)
|
||||
@@ -87,6 +94,13 @@ object FirExpectConsistencyChecker : FirBasicDeclarationChecker() {
|
||||
return null
|
||||
}
|
||||
|
||||
private fun getClassSuperTypeReferencesWithInitializers(declaration: FirMemberDeclaration): List<FirTypeRef> {
|
||||
if (declaration !is FirRegularClass) return emptyList()
|
||||
return declaration.withNavigator {
|
||||
declaration.superTypeRefs.filter { it.isInConstructorCallee() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun isProhibitedPrivateDeclaration(declaration: FirMemberDeclaration): Boolean {
|
||||
return declaration !is FirConstructor && declaration !is FirPropertyAccessor && Visibilities.isPrivate(declaration.visibility)
|
||||
}
|
||||
@@ -102,4 +116,8 @@ object FirExpectConsistencyChecker : FirBasicDeclarationChecker() {
|
||||
private fun isProhibitedEnumEntryWithBody(declaration: FirMemberDeclaration): Boolean {
|
||||
return declaration is FirEnumEntry && declaration.withNavigator { declaration.hasBody() == true }
|
||||
}
|
||||
|
||||
private fun isProhibitedEnumEntryWithInitializer(declaration: FirMemberDeclaration): Boolean {
|
||||
return declaration is FirEnumEntry && declaration.withNavigator { declaration.hasInitializer() == true }
|
||||
}
|
||||
}
|
||||
|
||||
+30
@@ -1233,6 +1233,29 @@ object LightTreePositioningStrategies {
|
||||
return markElement(nodeToMark, startOffset, endOffset, tree, node)
|
||||
}
|
||||
}
|
||||
|
||||
val SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS_DIAGNOSTIC: LightTreePositioningStrategy = object : LightTreePositioningStrategy() {
|
||||
override fun mark(
|
||||
node: LighterASTNode,
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
tree: FlyweightCapableTreeStructure<LighterASTNode>
|
||||
): List<TextRange> {
|
||||
val nodeToMark = when (node.tokenType) {
|
||||
KtNodeTypes.ENUM_ENTRY -> {
|
||||
tree.findChildByType(node, KtNodeTypes.INITIALIZER_LIST) ?: node
|
||||
}
|
||||
KtNodeTypes.TYPE_REFERENCE -> {
|
||||
val valueArgList = node.getParentIfTypeIs(KtNodeTypes.CONSTRUCTOR_CALLEE, tree)
|
||||
?.getParentIfTypeIs(KtNodeTypes.SUPER_TYPE_CALL_ENTRY, tree)
|
||||
?.let { tree.findChildByType(it, KtNodeTypes.VALUE_ARGUMENT_LIST) }
|
||||
valueArgList ?: node
|
||||
}
|
||||
else -> node
|
||||
}
|
||||
return markElement(nodeToMark, startOffset, endOffset, tree, node)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun KtSourceElement.hasValOrVar(): Boolean =
|
||||
@@ -1657,3 +1680,10 @@ private fun FlyweightCapableTreeStructure<LighterASTNode>.lastChild(node: Lighte
|
||||
getChildren(node, childrenRef)
|
||||
return childrenRef.get().lastOrNull { it != null }
|
||||
}
|
||||
|
||||
private fun LighterASTNode.getParentIfTypeIs(
|
||||
tokenType: IElementType,
|
||||
tree: FlyweightCapableTreeStructure<LighterASTNode>,
|
||||
): LighterASTNode? {
|
||||
return tree.getParent(this)?.takeIf { it.tokenType == tokenType }
|
||||
}
|
||||
|
||||
+15
@@ -1046,6 +1046,21 @@ object PositioningStrategies {
|
||||
}
|
||||
}
|
||||
|
||||
@JvmField
|
||||
val SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS_DIAGNOSTIC = object : PositioningStrategy<KtElement>() {
|
||||
override fun mark(element: KtElement): List<TextRange> {
|
||||
val elementToMark = when (element) {
|
||||
is KtEnumEntry -> element.initializerList ?: element
|
||||
is KtTypeReference -> {
|
||||
val superTypeCallEntry = (element.parent as? KtConstructorCalleeExpression)?.parent as? KtSuperTypeCallEntry
|
||||
superTypeCallEntry?.valueArgumentList ?: element
|
||||
}
|
||||
else -> element
|
||||
}
|
||||
return markElement(elementToMark)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param locateReferencedName whether to remove any nested parentheses while locating the reference element. This is useful for
|
||||
* diagnostics on super and unresolved references. For example, with the following, only the part inside the parentheses should be
|
||||
|
||||
+5
@@ -394,4 +394,9 @@ object SourceElementPositioningStrategies {
|
||||
LightTreePositioningStrategies.TYPEALIAS_TYPE_REFERENCE,
|
||||
PositioningStrategies.TYPEALIAS_TYPE_REFERENCE,
|
||||
)
|
||||
|
||||
val SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS_DIAGNOSTIC = SourceElementPositioningStrategy(
|
||||
LightTreePositioningStrategies.SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS_DIAGNOSTIC,
|
||||
PositioningStrategies.SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS_DIAGNOSTIC,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ open class Base {
|
||||
open operator fun plus(b: Base) = Base()
|
||||
}
|
||||
|
||||
expect open class Derived constructor() : Base() {
|
||||
expect open class Derived constructor() : Base {
|
||||
}
|
||||
|
||||
// MODULE: main()()(common)
|
||||
|
||||
+2
-2
@@ -3,12 +3,12 @@
|
||||
|
||||
<!NO_ACTUAL_FOR_EXPECT!>expect enum class En<!EXPECTED_ENUM_CONSTRUCTOR!>(x: Int)<!> {
|
||||
E1,
|
||||
E2(42),
|
||||
E2<!SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS!>(42)<!>,
|
||||
;
|
||||
|
||||
<!EXPECTED_ENUM_CONSTRUCTOR!>constructor(s: String)<!>
|
||||
}<!>
|
||||
|
||||
<!NO_ACTUAL_FOR_EXPECT!>expect enum class En2 {
|
||||
E1()
|
||||
E1<!SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS!>()<!>
|
||||
}<!>
|
||||
|
||||
+2
-2
@@ -7,9 +7,9 @@ interface J
|
||||
|
||||
expect class Foo : I, C, J
|
||||
|
||||
<!INCOMPATIBLE_MATCHING{JVM}, SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR, SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR!>expect class Bar : C()<!>
|
||||
<!INCOMPATIBLE_MATCHING{JVM}, SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR, SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR!>expect class Bar : C<!SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS, SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS!>()<!><!>
|
||||
|
||||
expect class WithExplicitPrimaryConstructor() : C()
|
||||
expect class WithExplicitPrimaryConstructor() : C<!SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS, SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS!>()<!>
|
||||
|
||||
// MODULE: m2-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
|
||||
Reference in New Issue
Block a user