[FIR] Supertype and inheritance checkers group

This commit is contained in:
Nick
2020-07-24 18:33:52 +03:00
parent 252eb1ad23
commit 28700ed64c
61 changed files with 1205 additions and 190 deletions
@@ -0,0 +1,5 @@
class A
interface C
enum class B : C, <!CLASS_IN_SUPERTYPE_FOR_ENUM!>A<!>(), Any()
@@ -0,0 +1,21 @@
FILE: classInSupertypeForEnum.kt
public final class A : R|kotlin/Any| {
public constructor(): R|A| {
super<R|kotlin/Any|>()
}
}
public abstract interface C : R|kotlin/Any| {
}
public final enum class B : R|C|, R|A|, R|kotlin/Any|, R|kotlin/Enum<B>| {
private constructor(): R|B| {
super<R|kotlin/Enum<B>|>()
}
public final static fun values(): R|kotlin/Array<B>| {
}
public final static fun valueOf(value: R|kotlin/String|): R|B| {
}
}
@@ -0,0 +1,7 @@
interface <!CONSTRUCTOR_IN_INTERFACE!>A(val s: String)<!>
interface <!CONSTRUCTOR_IN_INTERFACE!>B constructor(val s: String)<!>
interface C {
<!CONSTRUCTOR_IN_INTERFACE!>constructor(val s: String)<!> {}
}
@@ -0,0 +1,11 @@
FILE: constructorInInterface.kt
public abstract interface A : R|kotlin/Any| {
}
public abstract interface B : R|kotlin/Any| {
}
public abstract interface C : R|kotlin/Any| {
public constructor(s: R|kotlin/String|): R|C| {
super<R|kotlin/Any|>()
}
}
@@ -0,0 +1,9 @@
class A
interface B : <!DELEGATION_IN_INTERFACE, INTERFACE_WITH_SUPERCLASS!>A<!> by a {
val a: A
}
val test = A()
interface C : <!DELEGATION_IN_INTERFACE, INTERFACE_WITH_SUPERCLASS!>A<!> by test
@@ -0,0 +1,20 @@
FILE: delegationInInterface.kt
public final class A : R|kotlin/Any| {
public constructor(): R|A| {
super<R|kotlin/Any|>()
}
}
public abstract interface B : R|A| {
local final field <$$delegate_0>: R|A|
public abstract val a: R|A|
public get(): R|A|
}
public final val test: R|A| = R|/A.A|()
public get(): R|A|
public abstract interface C : R|A| {
local final field <$$delegate_0>: R|A|
}
@@ -0,0 +1,8 @@
class A
interface B : <!INTERFACE_WITH_SUPERCLASS, SUPERTYPE_INITIALIZED_IN_INTERFACE!>A<!>()
interface C
class D
interface E : <!INTERFACE_WITH_SUPERCLASS, SUPERTYPE_INITIALIZED_IN_INTERFACE!>A<!>(), C, D()
@@ -0,0 +1,19 @@
FILE: interfaceWithSuperclass.kt
public final class A : R|kotlin/Any| {
public constructor(): R|A| {
super<R|kotlin/Any|>()
}
}
public abstract interface B : R|A| {
}
public abstract interface C : R|kotlin/Any| {
}
public final class D : R|kotlin/Any| {
public constructor(): R|D| {
super<R|kotlin/Any|>()
}
}
public abstract interface E : R|A|, R|C|, R|D| {
}
@@ -0,0 +1,25 @@
interface A {
<!ANY_METHOD_IMPLEMENTED_IN_INTERFACE!>override fun toString() = "Hello"<!>
<!ANY_METHOD_IMPLEMENTED_IN_INTERFACE!>override fun equals(other: Any?) = true<!>
<!ANY_METHOD_IMPLEMENTED_IN_INTERFACE!>override fun hashCode(): Int {
return 42;
}<!>
}
interface B {
override fun toString(): String
override fun equals(other: Any?): Boolean
override fun hashCode(): Int
}
interface C {
<!ANY_METHOD_IMPLEMENTED_IN_INTERFACE!>override operator fun toString(): String = "Rest"<!>
<!ANY_METHOD_IMPLEMENTED_IN_INTERFACE!>override operator fun equals(other: Any?): Boolean = false<!>
<!ANY_METHOD_IMPLEMENTED_IN_INTERFACE!>override operator fun hashCode(): Int = 2<!>
}
interface D {
override operator fun toString(): String
override operator fun equals(other: Any?): Boolean
override operator fun hashCode(): Int
}
@@ -0,0 +1,45 @@
FILE: methodOfAnyImplementedInInterface.kt
public abstract interface A : R|kotlin/Any| {
public open override fun toString(): R|kotlin/String| {
^toString String(Hello)
}
public open override fun equals(other: R|kotlin/Any?|): R|kotlin/Boolean| {
^equals Boolean(true)
}
public open override fun hashCode(): R|kotlin/Int| {
^hashCode Int(42)
}
}
public abstract interface B : R|kotlin/Any| {
public abstract override fun toString(): R|kotlin/String|
public abstract override fun equals(other: R|kotlin/Any?|): R|kotlin/Boolean|
public abstract override fun hashCode(): R|kotlin/Int|
}
public abstract interface C : R|kotlin/Any| {
public open override operator fun toString(): R|kotlin/String| {
^toString String(Rest)
}
public open override operator fun equals(other: R|kotlin/Any?|): R|kotlin/Boolean| {
^equals Boolean(false)
}
public open override operator fun hashCode(): R|kotlin/Int| {
^hashCode Int(2)
}
}
public abstract interface D : R|kotlin/Any| {
public abstract override operator fun toString(): R|kotlin/String|
public abstract override operator fun equals(other: R|kotlin/Any?|): R|kotlin/Boolean|
public abstract override operator fun hashCode(): R|kotlin/Int|
}
@@ -0,0 +1,3 @@
sealed class A
val b = <!SEALED_CLASS_CONSTRUCTOR_CALL!>A<!>()
@@ -0,0 +1,9 @@
FILE: sealedClassConstructorCall.kt
public sealed class A : R|kotlin/Any| {
private constructor(): R|A| {
super<R|kotlin/Any|>()
}
}
public final val b: R|A| = R|/A.A|()
public get(): R|A|
@@ -0,0 +1,40 @@
sealed class A
<!REDECLARATION!>class B : A()<!>
interface C : <!INTERFACE_WITH_SUPERCLASS!>A<!>
interface D : C, <!INTERFACE_WITH_SUPERCLASS!>A<!>
class E : B, A()
sealed class P {
object H: P()
class J : P()
object T {
object V : P()
class M : P()
}
val p: P = object : <!SEALED_SUPERTYPE_IN_LOCAL_CLASS!>P<!>() {
}
val r = object : <!SEALED_SUPERTYPE_IN_LOCAL_CLASS!>P<!>() {
}
}
class K : P()
<!REDECLARATION!>object B<!> {
class I : <!SEALED_SUPERTYPE!>P<!>()
}
fun test() {
class L : <!SEALED_SUPERTYPE_IN_LOCAL_CLASS!>P<!>()
val a = object : <!SEALED_SUPERTYPE_IN_LOCAL_CLASS!>P<!>() {
}
}
@@ -0,0 +1,117 @@
FILE: sealedSupertype.kt
public sealed class A : R|kotlin/Any| {
private constructor(): R|A| {
super<R|kotlin/Any|>()
}
}
public final class B : R|A| {
public constructor(): R|B| {
super<R|A|>()
}
}
public abstract interface C : R|A| {
}
public abstract interface D : R|C|, R|A| {
}
public final class E : R|B|, R|A| {
public constructor(): R|E| {
super<R|A|>()
}
}
public sealed class P : R|kotlin/Any| {
private constructor(): R|P| {
super<R|kotlin/Any|>()
}
public final object H : R|P| {
private constructor(): R|P.H| {
super<R|P|>()
}
}
public final class J : R|P| {
public constructor(): R|P.J| {
super<R|P|>()
}
}
public final object T : R|kotlin/Any| {
private constructor(): R|P.T| {
super<R|kotlin/Any|>()
}
public final object V : R|P| {
private constructor(): R|P.T.V| {
super<R|P|>()
}
}
public final class M : R|P| {
public constructor(): R|P.T.M| {
super<R|P|>()
}
}
}
public final val p: R|P| = object : R|P| {
private constructor(): R|<anonymous>| {
super<R|P|>()
}
}
public get(): R|P|
public final val r: R|<anonymous>| = object : R|P| {
private constructor(): R|<anonymous>| {
super<R|P|>()
}
}
public get(): R|<anonymous>|
}
public final class K : R|P| {
public constructor(): R|K| {
super<R|P|>()
}
}
public final object B : R|kotlin/Any| {
private constructor(): R|B| {
super<R|kotlin/Any|>()
}
public final class I : R|P| {
public constructor(): R|B.I| {
super<R|P|>()
}
}
}
public final fun test(): R|kotlin/Unit| {
local final class L : R|P| {
public constructor(): R|L| {
super<R|P|>()
}
}
lval a: R|<anonymous>| = object : R|P| {
private constructor(): R|<anonymous>| {
super<R|P|>()
}
}
}
@@ -2,7 +2,7 @@ open class A {
open fun foo() {}
}
interface ATrait : A {
interface ATrait : <!INTERFACE_WITH_SUPERCLASS!>A<!> {
override fun foo() {
<!SUPERCLASS_NOT_ACCESSIBLE_FROM_INTERFACE!>super<A><!>.foo()
}
@@ -0,0 +1,13 @@
interface A
interface B : <!SUPERTYPE_INITIALIZED_IN_INTERFACE!>A<!>()
class C
interface D : <!INTERFACE_WITH_SUPERCLASS, SUPERTYPE_INITIALIZED_IN_INTERFACE!>C<!>()
interface E : <!INTERFACE_WITH_SUPERCLASS, SUPERTYPE_INITIALIZED_IN_INTERFACE!>Any<!>()
interface F : A, <!SUPERTYPE_INITIALIZED_IN_INTERFACE!>B<!>(), <!INTERFACE_WITH_SUPERCLASS!>C<!>, D(), Any() {
}
@@ -0,0 +1,17 @@
FILE: supertypeInitializedInInterface.kt
public abstract interface A : R|kotlin/Any| {
}
public abstract interface B : R|A| {
}
public final class C : R|kotlin/Any| {
public constructor(): R|C| {
super<R|kotlin/Any|>()
}
}
public abstract interface D : R|C| {
}
public abstract interface E : R|kotlin/Any| {
}
public abstract interface F : R|A|, R|B|, R|C|, R|D|, R|kotlin/Any| {
}
@@ -0,0 +1,3 @@
enum class A<<!TYPE_PARAMETERS_IN_ENUM!>B<!>, C : B, D>
enum class B
@@ -0,0 +1,25 @@
FILE: typeParametersInEnum.kt
public final enum class A<B, C : R|B|, D> : R|kotlin/Enum<A<B, C, D>>| {
private constructor<B, C : R|B|, D>(): R|A<B, C, D>| {
super<R|kotlin/Enum<A<B, C, D>>|>()
}
public final static fun values(): R|kotlin/Array<A>| {
}
public final static fun valueOf(value: R|kotlin/String|): R|A| {
}
}
public final enum class B : R|kotlin/Enum<B>| {
private constructor(): R|B| {
super<R|kotlin/Enum<B>|>()
}
public final static fun values(): R|kotlin/Array<B>| {
}
public final static fun valueOf(value: R|kotlin/String|): R|B| {
}
}
@@ -1,6 +1,6 @@
class Out<out T>
interface X : Out<String>
interface X : <!INTERFACE_WITH_SUPERCLASS!>Out<String><!>
abstract class Base<E> {
fun <D : Out<E>> f(t: MutableList<D>, e: MutableList<E>) {}
@@ -936,6 +936,21 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/explicitDelegationCallRequired.kt");
}
@TestMetadata("classInSupertypeForEnum.kt")
public void testClassInSupertypeForEnum() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/classInSupertypeForEnum.kt");
}
@TestMetadata("constructorInInterface.kt")
public void testConstructorInInterface() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/constructorInInterface.kt");
}
@TestMetadata("delegationInInterface.kt")
public void testDelegationInInterface() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/delegationInInterface.kt");
}
@TestMetadata("incompatibleModifiers.kt")
public void testIncompatibleModifiers() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/incompatibleModifiers.kt");
@@ -946,6 +961,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/infixFunctions.kt");
}
@TestMetadata("interfaceWithSuperclass.kt")
public void testInterfaceWithSuperclass() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/interfaceWithSuperclass.kt");
}
@TestMetadata("localAnnotationClass.kt")
public void testLocalAnnotationClass() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/localAnnotationClass.kt");
@@ -961,6 +981,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/manyCompanionObjects.kt");
}
@TestMetadata("methodOfAnyImplementedInInterface.kt")
public void testMethodOfAnyImplementedInInterface() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/methodOfAnyImplementedInInterface.kt");
}
@TestMetadata("notASupertype.kt")
public void testNotASupertype() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/notASupertype.kt");
@@ -991,6 +1016,16 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/repeatedModifier.kt");
}
@TestMetadata("sealedClassConstructorCall.kt")
public void testSealedClassConstructorCall() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/sealedClassConstructorCall.kt");
}
@TestMetadata("sealedSupertype.kt")
public void testSealedSupertype() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/sealedSupertype.kt");
}
@TestMetadata("superIsNotAnExpression.kt")
public void testSuperIsNotAnExpression() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/superIsNotAnExpression.kt");
@@ -1016,6 +1051,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/typeArgumentsNotAllowed.kt");
}
@TestMetadata("supertypeInitializedInInterface.kt")
public void testSupertypeInitializedInInterface() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/supertypeInitializedInInterface.kt");
}
@TestMetadata("typeOfAnnotationMember.kt")
public void testTypeOfAnnotationMember() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/typeOfAnnotationMember.kt");
@@ -1026,6 +1066,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/typeParametersInObject.kt");
}
@TestMetadata("typeParametersInEnum.kt")
public void testTypeParametersInEnum() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/typeParametersInEnum.kt");
}
@TestMetadata("upperBoundViolated.kt")
public void testUpperBoundViolated() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/upperBoundViolated.kt");
@@ -936,6 +936,21 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/explicitDelegationCallRequired.kt");
}
@TestMetadata("classInSupertypeForEnum.kt")
public void testClassInSupertypeForEnum() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/classInSupertypeForEnum.kt");
}
@TestMetadata("constructorInInterface.kt")
public void testConstructorInInterface() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/constructorInInterface.kt");
}
@TestMetadata("delegationInInterface.kt")
public void testDelegationInInterface() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/delegationInInterface.kt");
}
@TestMetadata("incompatibleModifiers.kt")
public void testIncompatibleModifiers() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/incompatibleModifiers.kt");
@@ -946,6 +961,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/infixFunctions.kt");
}
@TestMetadata("interfaceWithSuperclass.kt")
public void testInterfaceWithSuperclass() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/interfaceWithSuperclass.kt");
}
@TestMetadata("localAnnotationClass.kt")
public void testLocalAnnotationClass() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/localAnnotationClass.kt");
@@ -961,6 +981,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/manyCompanionObjects.kt");
}
@TestMetadata("methodOfAnyImplementedInInterface.kt")
public void testMethodOfAnyImplementedInInterface() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/methodOfAnyImplementedInInterface.kt");
}
@TestMetadata("notASupertype.kt")
public void testNotASupertype() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/notASupertype.kt");
@@ -991,6 +1016,16 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/repeatedModifier.kt");
}
@TestMetadata("sealedClassConstructorCall.kt")
public void testSealedClassConstructorCall() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/sealedClassConstructorCall.kt");
}
@TestMetadata("sealedSupertype.kt")
public void testSealedSupertype() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/sealedSupertype.kt");
}
@TestMetadata("superIsNotAnExpression.kt")
public void testSuperIsNotAnExpression() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/superIsNotAnExpression.kt");
@@ -1016,6 +1051,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/typeArgumentsNotAllowed.kt");
}
@TestMetadata("supertypeInitializedInInterface.kt")
public void testSupertypeInitializedInInterface() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/supertypeInitializedInInterface.kt");
}
@TestMetadata("typeOfAnnotationMember.kt")
public void testTypeOfAnnotationMember() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/typeOfAnnotationMember.kt");
@@ -1026,6 +1066,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/typeParametersInObject.kt");
}
@TestMetadata("typeParametersInEnum.kt")
public void testTypeParametersInEnum() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/typeParametersInEnum.kt");
}
@TestMetadata("upperBoundViolated.kt")
public void testUpperBoundViolated() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/upperBoundViolated.kt");
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.fir.analysis.checkers
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.symbols.CallableId
@@ -14,71 +15,86 @@ import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
private open class RepresentationBuilder {
var receiver = ""
var name = ""
/**
* Provides representations for FirElement's.
*/
interface FirDeclarationPresenter {
open class RepresentationBuilder {
var receiver = ""
var name = ""
open fun build() = "[$receiver] $name"
open fun build() = "[$receiver] $name"
}
fun buildRepresentation(init: RepresentationBuilder.() -> Unit): String {
return RepresentationBuilder().apply(init).build()
}
class FunctionRepresentationBuilder : RepresentationBuilder() {
var representsOperator = false
var typeArguments = ""
var parameters = ""
override fun build() = "<$typeArguments> [$receiver] ${if (representsOperator) "operator " else ""}$name ($parameters)"
}
fun buildFunctionRepresentation(init: FunctionRepresentationBuilder.() -> Unit): String {
return FunctionRepresentationBuilder().apply(init).build()
}
fun represent(it: FirElement) = "NO_REPRESENTATION"
fun represent(it: ClassId) = it.packageFqName.asString() + '/' + it.relativeClassName.asString()
fun represent(it: CallableId) = if (it.className != null) {
it.packageName.asString() + '/' + it.className + '.' + it.callableName
} else {
it.packageName.asString() + '/' + it.callableName
}
fun represent(it: FirTypeRef) = when (it) {
is FirResolvedTypeRef -> it.type.toString()
is FirErrorTypeRef -> "ERROR"
else -> "?"
}
fun represent(it: FirTypeParameter) = it.name.asString() + " : " + it.bounds
.map { represent(it) }
.sorted()
.joinToString()
fun represent(it: FirValueParameter): String {
val prefix = if (it.isVararg) "vararg " else ""
return prefix + " " + represent(it.returnTypeRef)
}
fun represent(it: FirProperty) = buildRepresentation {
it.receiverTypeRef?.let {
receiver = represent(it)
}
name = represent(it.symbol.callableId)
}
fun represent(it: FirSimpleFunction) = buildFunctionRepresentation {
typeArguments = it.typeParameters.joinToString { represent(it) }
it.receiverTypeRef?.let {
receiver = represent(it)
}
representsOperator = it.isOperator
name = represent(it.symbol.callableId)
parameters = it.valueParameters.joinToString { represent(it) }
}
fun represent(it: FirTypeAlias) = buildRepresentation {
name = represent(it.symbol.classId)
}
fun represent(it: FirRegularClass) = buildRepresentation {
name = represent(it.symbol.classId)
}
}
private fun buildRepresentation(init: RepresentationBuilder.() -> Unit): String {
return RepresentationBuilder().apply(init).build()
}
private class FunctionRepresentationBuilder : RepresentationBuilder() {
var typeArguments = ""
var parameters = ""
override fun build() = "<$typeArguments> [$receiver] $name ($parameters)"
}
private fun buildFunctionRepresentation(init: FunctionRepresentationBuilder.() -> Unit): String {
return FunctionRepresentationBuilder().apply(init).build()
}
private fun ClassId.represent() = packageFqName.asString() + '/' + relativeClassName.asString()
private fun CallableId.represent() = if (className != null) {
packageName.asString() + '/' + className + '.' + callableName
} else {
packageName.asString() + '/' + callableName
}
private fun FirTypeRef.represent() = when (this) {
is FirResolvedTypeRef -> type.toString()
is FirErrorTypeRef -> "ERROR"
else -> "?"
}
private fun FirTypeParameter.represent() = name.asString() + " : " + bounds
.map { it.represent() }
.sorted()
.joinToString()
private fun FirValueParameter.represent(): String {
val prefix = if (this.isVararg) "vararg " else ""
return prefix + " " + this.returnTypeRef.represent()
}
private fun FirProperty.represent() = buildRepresentation {
receiver = receiverTypeRef?.represent() ?: ""
name = symbol.callableId.represent()
}
private fun FirSimpleFunction.represent() = buildFunctionRepresentation {
typeArguments = typeParameters.joinToString { it.represent() }
receiver = receiverTypeRef?.represent() ?: ""
name = symbol.callableId.represent()
parameters = valueParameters.joinToString { it.represent() }
}
private fun FirTypeAlias.represent() = buildRepresentation {
name = symbol.classId.represent()
}
private fun FirRegularClass.represent() = buildRepresentation {
name = symbol.classId.represent()
}
private class FirDefaultDeclarationPresenter : FirDeclarationPresenter
private val NO_NAME_PROVIDED = Name.special("<no name provided>")
@@ -94,7 +110,12 @@ private fun FirDeclaration.isCollectable() = when (this) {
else -> true
}
class FirDeclarationInspector {
/**
* Collects FirDeclarations for further analysis.
*/
class FirDeclarationInspector(
private val presenter: FirDeclarationPresenter = FirDefaultDeclarationPresenter()
) {
val otherDeclarations = mutableMapOf<String, MutableList<FirDeclaration>>()
val functionDeclarations = mutableMapOf<String, MutableList<FirSimpleFunction>>()
@@ -108,9 +129,9 @@ class FirDeclarationInspector {
}
val key = when (declaration) {
is FirRegularClass -> declaration.represent()
is FirTypeAlias -> declaration.represent()
is FirProperty -> declaration.represent()
is FirRegularClass -> presenter.represent(declaration)
is FirTypeAlias -> presenter.represent(declaration)
is FirProperty -> presenter.represent(declaration)
else -> return
}
@@ -125,7 +146,7 @@ class FirDeclarationInspector {
}
private fun collectFunction(declaration: FirSimpleFunction) {
val key = declaration.represent()
val key = presenter.represent(declaration)
var value = functionDeclarations[key]
if (value == null) {
@@ -136,11 +157,11 @@ class FirDeclarationInspector {
value.add(declaration)
}
private fun contains(declaration: FirDeclaration) = when (declaration) {
is FirSimpleFunction -> declaration.represent() in functionDeclarations
is FirRegularClass -> declaration.represent() in otherDeclarations
is FirTypeAlias -> declaration.represent() in otherDeclarations
is FirProperty -> declaration.represent() in otherDeclarations
fun contains(declaration: FirDeclaration) = when (declaration) {
is FirSimpleFunction -> presenter.represent(declaration) in functionDeclarations
is FirRegularClass -> presenter.represent(declaration) in otherDeclarations
is FirTypeAlias -> presenter.represent(declaration) in otherDeclarations
is FirProperty -> presenter.represent(declaration) in otherDeclarations
else -> false
}
}
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyExpressionBlock
import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.fir.resolve.toSymbol
@@ -208,7 +207,7 @@ fun FirSimpleFunction.overriddenFunctions(
val firTypeScope = containingClass.unsubstitutedScope(
context.sessionHolder.session,
context.sessionHolder.scopeSession
) as FirTypeScope
)
val overriddenFunctions = mutableListOf<FirFunctionSymbol<*>>()
firTypeScope.processFunctionsByName(symbol.fir.name) { }
@@ -272,4 +271,27 @@ private fun FirDeclaration.hasBody(): Boolean = when (this) {
is FirSimpleFunction -> this.body != null && this.body !is FirEmptyExpressionBlock
is FirProperty -> this.setter?.body !is FirEmptyExpressionBlock? || this.getter?.body !is FirEmptyExpressionBlock?
else -> false
}
}
/**
* Finds any non-interface supertype and returns it
* or null if couldn't find any.
*/
fun FirClass<*>.findNonInterfaceSupertype(context: CheckerContext): FirTypeRef? {
for (it in superTypeRefs) {
val classId = it.safeAs<FirResolvedTypeRef>()
?.type.safeAs<ConeClassLikeType>()
?.lookupTag?.classId
?: continue
val fir = context.session.firSymbolProvider.getClassLikeSymbolByFqName(classId)
?.fir.safeAs<FirClass<*>>()
?: continue
if (fir.classKind != ClassKind.INTERFACE) {
return it
}
}
return null
}
@@ -22,6 +22,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
FirLocalEntityNotAllowedChecker,
FirTypeParametersInObjectChecker,
FirConflictsChecker,
FirConstructorInInterfaceChecker,
)
override val memberDeclarationCheckers: List<FirMemberDeclarationChecker> = listOf(
@@ -31,6 +32,12 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
FirSupertypeInitializedWithoutPrimaryConstructor,
FirDelegationSuperCallInEnumConstructorChecker,
FirPrimaryConstructorRequiredForDataClassChecker,
FirMethodOfAnyImplementedInInterfaceChecker,
FirSupertypeInitializedInInterfaceChecker,
FirDelegationInInterfaceChecker,
FirInterfaceWithSuperclassChecker,
FirEnumClassSimpleChecker,
FirSealedSupertypeChecker,
)
override val regularClassCheckers: List<FirRegularClassChecker> = listOf(
@@ -0,0 +1,68 @@
/*
* 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.checkers.declaration
import com.intellij.lang.LighterASTNode
import com.intellij.openapi.util.Ref
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiErrorElement
import com.intellij.util.diff.FlyweightCapableTreeStructure
import org.jetbrains.kotlin.KtNodeTypes.PRIMARY_CONSTRUCTOR
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirLightSourceElement
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.lightNode
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.psi.KtPrimaryConstructor
object FirConstructorInInterfaceChecker : FirBasicDeclarationChecker() {
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration !is FirClass<*> || declaration.classKind != ClassKind.INTERFACE) {
return
}
if (declaration.source?.hasPrimaryConstructor() == true) {
reporter.report(declaration.source)
}
}
private fun FirSourceElement.hasPrimaryConstructor(): Boolean {
val localPsi = psi
val localLightNode = lightNode
if (localPsi != null && localPsi !is PsiErrorElement) {
return localPsi.hasPrimaryConstructor()
} else if (localLightNode != null && this is FirLightSourceElement) {
return localLightNode.hasPrimaryConstructor(tree)
}
return false
}
private fun PsiElement.hasPrimaryConstructor(): Boolean {
return lastChild !is PsiErrorElement && lastChild is KtPrimaryConstructor
}
private fun LighterASTNode.hasPrimaryConstructor(tree: FlyweightCapableTreeStructure<LighterASTNode>): Boolean {
val children = getChildren(tree)
return children.lastOrNull()?.tokenType == PRIMARY_CONSTRUCTOR
}
private fun LighterASTNode.getChildren(tree: FlyweightCapableTreeStructure<LighterASTNode>): List<LighterASTNode> {
val children = Ref<Array<LighterASTNode?>>()
val count = tree.getChildren(this, children)
return if (count > 0) children.get().filterNotNull() else emptyList()
}
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let { report(FirErrors.CONSTRUCTOR_IN_INTERFACE.on(it)) }
}
}
@@ -0,0 +1,77 @@
/*
* 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.checkers.declaration
import com.intellij.lang.LighterASTNode
import com.intellij.openapi.util.Ref
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiErrorElement
import com.intellij.util.diff.FlyweightCapableTreeStructure
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirLightSourceElement
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.lightNode
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.psi.KtDelegatedSuperTypeEntry
object FirDelegationInInterfaceChecker : FirMemberDeclarationChecker() {
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration !is FirClass<*> || declaration.classKind != ClassKind.INTERFACE) {
return
}
declaration.source?.findSuperTypeDelegation()?.let {
reporter.report(declaration.superTypeRefs.getOrNull(it)?.source)
}
}
private fun FirSourceElement.findSuperTypeDelegation(): Int {
val localPsi = psi
val localLightNode = lightNode
if (localPsi != null && localPsi !is PsiErrorElement) {
return localPsi.findSuperTypeDelegation()
} else if (localLightNode != null && this is FirLightSourceElement) {
return localLightNode.findSuperTypeDelegation(tree)
}
return -1
}
private fun PsiElement.findSuperTypeDelegation() = if (children.isNotEmpty() && children[0] !is PsiErrorElement) {
children[0].children.indexOfFirst { it is KtDelegatedSuperTypeEntry }
} else {
-1
}
private fun LighterASTNode.findSuperTypeDelegation(tree: FlyweightCapableTreeStructure<LighterASTNode>): Int {
val children = getChildren(tree)
return if (children.isNotEmpty()) {
children.find { it.tokenType == KtNodeTypes.SUPER_TYPE_LIST }
?.getChildren(tree)
?.indexOfFirst { it.tokenType == KtNodeTypes.DELEGATED_SUPER_TYPE_ENTRY }
?: -1
} else {
-1
}
}
private fun LighterASTNode.getChildren(tree: FlyweightCapableTreeStructure<LighterASTNode>): List<LighterASTNode> {
val children = Ref<Array<LighterASTNode?>>()
val count = tree.getChildren(this, children)
return if (count > 0) children.get().filterNotNull() else emptyList()
}
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let { report(FirErrors.DELEGATION_IN_INTERFACE.on(it)) }
}
}
@@ -0,0 +1,39 @@
/*
* 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.checkers.declaration
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.findNonInterfaceSupertype
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
object FirEnumClassSimpleChecker : FirMemberDeclarationChecker() {
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration !is FirClass<*> || declaration.classKind != ClassKind.ENUM_CLASS) {
return
}
declaration.findNonInterfaceSupertype(context)?.let {
reporter.reportClassInSupertypeForEnum(it.source)
}
if (declaration.typeParameters.isNotEmpty()) {
reporter.reportTypeParametersInEnum(declaration.typeParameters.firstOrNull()?.source)
}
}
private fun DiagnosticReporter.reportClassInSupertypeForEnum(source: FirSourceElement?) {
source?.let { report(FirErrors.CLASS_IN_SUPERTYPE_FOR_ENUM.on(it)) }
}
private fun DiagnosticReporter.reportTypeParametersInEnum(source: FirSourceElement?) {
source?.let { report(FirErrors.TYPE_PARAMETERS_IN_ENUM.on(it)) }
}
}
@@ -0,0 +1,31 @@
/*
* 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.checkers.declaration
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.findNonInterfaceSupertype
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
object FirInterfaceWithSuperclassChecker : FirMemberDeclarationChecker() {
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration !is FirClass<*> || declaration.classKind != ClassKind.INTERFACE) {
return
}
declaration.findNonInterfaceSupertype(context)?.let {
reporter.report(it.source)
}
}
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let { report(FirErrors.INTERFACE_WITH_SUPERCLASS.on(it)) }
}
}
@@ -0,0 +1,63 @@
/*
* 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.checkers.declaration
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationInspector
import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationPresenter
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
object FirMethodOfAnyImplementedInInterfaceChecker : FirMemberDeclarationChecker(), FirDeclarationPresenter {
private var inspector: FirDeclarationInspector? = null
private fun getInspector(context: CheckerContext) = inspector ?: FirDeclarationInspector(this).apply {
val anyClassId = context.session.builtinTypes.anyType.id
context.session.firSymbolProvider.getClassLikeSymbolByFqName(anyClassId)
?.fir.safeAs<FirRegularClass>()
?.declarations
?.filterIsInstance<FirSimpleFunction>()
?.filter { it !is FirConstructor }
?.forEach {
collect(it)
}
inspector = this
}
override fun represent(it: FirSimpleFunction) = buildFunctionRepresentation {
typeArguments = it.typeParameters.joinToString { represent(it) }
it.receiverTypeRef?.let {
receiver = represent(it)
}
name = it.name.asString()
parameters = it.valueParameters.joinToString { represent(it) }
}
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration !is FirClass<*> || declaration.classKind != ClassKind.INTERFACE) {
return
}
for (it in declaration.declarations) {
val inspector = getInspector(context)
if (it is FirSimpleFunction && inspector.contains(it) && it.body != null && it.isOverride) {
reporter.report(it.source)
}
}
}
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let { report(FirErrors.ANY_METHOD_IMPLEMENTED_IN_INTERFACE.on(it)) }
}
}
@@ -0,0 +1,58 @@
/*
* 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.checkers.declaration
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirQualifiedAccessChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.classId
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
object FirSealedClassConstructorCallChecker : FirQualifiedAccessChecker() {
override fun check(functionCall: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
val constructorFir = functionCall.calleeReference.safeAs<FirResolvedNamedReference>()
?.resolvedSymbol
?.fir.safeAs<FirConstructor>()
?: return
val typeClassId = constructorFir.returnTypeRef.safeAs<FirResolvedTypeRef>()
?.type.safeAs<ConeClassLikeType>()
?.lookupTag
?.classId
?: return
val typeFir = typeClassId.toRegularClass(context)
?: return
if (typeFir.status.modality == Modality.SEALED) {
reporter.report(functionCall.calleeReference.source)
}
}
private fun ClassId.toRegularClass(context: CheckerContext): FirRegularClass? = if (!isLocal) {
context.session.firSymbolProvider.getClassLikeSymbolByFqName(this)
?.fir.safeAs()
} else {
context.containingDeclarations
.lastOrNull { it.safeAs<FirRegularClass>()?.classId == this }
.safeAs()
}
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let { report(FirErrors.SEALED_CLASS_CONSTRUCTOR_CALL.on(it)) }
}
}
@@ -0,0 +1,115 @@
/*
* 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.checkers.declaration
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
object FirSealedSupertypeChecker : FirMemberDeclarationChecker() {
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration is FirClass<*>) {
// only the file declaration is present
when {
context.containingDeclarations.size == 1 -> {
checkTopLevelDeclaration(declaration, context, reporter)
}
declaration.classId.isLocal -> {
checkLocalDeclaration(declaration, context, reporter)
}
else -> {
checkInnerDeclaration(declaration, context, reporter)
}
}
} else if (declaration is FirProperty) {
val initializer = declaration.initializer.safeAs<FirClass<*>>()
?: return
checkLocalDeclaration(initializer, context, reporter)
}
}
private fun checkTopLevelDeclaration(declaration: FirClass<*>, context: CheckerContext, reporter: DiagnosticReporter) {
for (it in declaration.superTypeRefs) {
val classId = it.safeAs<FirResolvedTypeRef>()
?.type.safeAs<ConeClassLikeType>()
?.lookupTag?.classId
?: continue
if (classId.isLocal) {
continue
}
val fir = context.session.firSymbolProvider.getClassLikeSymbolByFqName(classId)
?.fir.safeAs<FirRegularClass>()
?: continue
if (fir.status.modality == Modality.SEALED && classId.outerClassId != null) {
reporter.report(it.source)
return
}
}
}
private fun checkLocalDeclaration(declaration: FirClass<*>, context: CheckerContext, reporter: DiagnosticReporter) {
for (it in declaration.superTypeRefs) {
val classId = it.safeAs<FirResolvedTypeRef>()
?.type.safeAs<ConeClassLikeType>()
?.lookupTag?.classId
?: continue
if (classId.isLocal) {
continue
}
val fir = context.session.firSymbolProvider.getClassLikeSymbolByFqName(classId)
?.fir.safeAs<FirRegularClass>()
?: continue
if (fir.status.modality == Modality.SEALED) {
reporter.reportInLocal(it.source)
return
}
}
}
private fun checkInnerDeclaration(declaration: FirClass<*>, context: CheckerContext, reporter: DiagnosticReporter) {
for (it in declaration.superTypeRefs) {
val classId = it.safeAs<FirResolvedTypeRef>()
?.type.safeAs<ConeClassLikeType>()
?.lookupTag?.classId
?: continue
if (classId.isLocal) {
continue
}
val fir = context.session.firSymbolProvider.getClassLikeSymbolByFqName(classId)
?.fir.safeAs<FirRegularClass>()
?: continue
if (fir.status.modality == Modality.SEALED && !context.containingDeclarations.contains(fir)) {
reporter.report(it.source)
return
}
}
}
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let { report(FirErrors.SEALED_SUPERTYPE.on(it)) }
}
private fun DiagnosticReporter.reportInLocal(source: FirSourceElement?) {
source?.let { report(FirErrors.SEALED_SUPERTYPE_IN_LOCAL_CLASS.on(it)) }
}
}
@@ -0,0 +1,77 @@
/*
* 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.checkers.declaration
import com.intellij.lang.LighterASTNode
import com.intellij.openapi.util.Ref
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiErrorElement
import com.intellij.util.diff.FlyweightCapableTreeStructure
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirLightSourceElement
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.lightNode
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.psi.KtSuperTypeCallEntry
object FirSupertypeInitializedInInterfaceChecker : FirMemberDeclarationChecker() {
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration !is FirClass<*> || declaration.classKind != ClassKind.INTERFACE) {
return
}
declaration.source?.findSuperTypeCall()?.let {
reporter.report(declaration.superTypeRefs.getOrNull(it)?.source)
}
}
private fun FirSourceElement.findSuperTypeCall(): Int {
val localPsi = psi
val localLightNode = lightNode
if (localPsi != null && localPsi !is PsiErrorElement) {
return localPsi.findSuperTypeCall()
} else if (localLightNode != null && this is FirLightSourceElement) {
return localLightNode.findSuperTypeCall(tree)
}
return -1
}
private fun PsiElement.findSuperTypeCall() = if (children.isNotEmpty() && children[0] !is PsiErrorElement) {
children[0].children.indexOfFirst { it is KtSuperTypeCallEntry }
} else {
-1
}
private fun LighterASTNode.findSuperTypeCall(tree: FlyweightCapableTreeStructure<LighterASTNode>): Int {
val children = getChildren(tree)
return if (children.isNotEmpty()) {
children.find { it.tokenType == KtNodeTypes.SUPER_TYPE_LIST }
?.getChildren(tree)
?.indexOfFirst { it.tokenType == KtNodeTypes.SUPER_TYPE_CALL_ENTRY }
?: -1
} else {
-1
}
}
private fun LighterASTNode.getChildren(tree: FlyweightCapableTreeStructure<LighterASTNode>): List<LighterASTNode> {
val children = Ref<Array<LighterASTNode?>>()
val count = tree.getChildren(this, children)
return if (count > 0) children.get().filterNotNull() else emptyList()
}
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let { report(FirErrors.SUPERTYPE_INITIALIZED_IN_INTERFACE.on(it)) }
}
}
@@ -5,6 +5,8 @@
package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirSealedClassConstructorCallChecker
object CommonExpressionCheckers : ExpressionCheckers() {
override val expressionCheckers: List<FirBasicExpresionChecker> = listOf()
override val qualifiedAccessCheckers: List<FirQualifiedAccessChecker> = listOf(
@@ -16,6 +18,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
FirProjectionsOnNonClassTypeArgumentChecker,
FirUpperBoundViolatedChecker,
FirTypeArgumentsNotAllowedExpressionChecker,
FirSealedClassConstructorCallChecker,
)
override val functionCallCheckers: List<FirFunctionCallChecker> = listOf()
}
@@ -17,12 +17,15 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_SUPER_CA
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.AMBIGUITY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_CLASS_MEMBER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_PARAMETER_DEFAULT_VALUE_MUST_BE_CONSTANT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANY_METHOD_IMPLEMENTED_IN_INTERFACE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGN_OPERATOR_AMBIGUITY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.BREAK_OR_CONTINUE_OUTSIDE_A_LOOP
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CLASS_IN_SUPERTYPE_FOR_ENUM
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_OVERLOADS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONSTRUCTOR_IN_INTERFACE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONSTRUCTOR_IN_OBJECT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CYCLIC_CONSTRUCTOR_DELEGATION_CALL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DELEGATION_IN_INTERFACE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DELEGATION_SUPER_CALL_IN_ENUM_CONSTRUCTOR
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DEPRECATED_MODIFIER_PAIR
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DESERIALIZATION_ERROR
@@ -44,6 +47,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_CAND
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_INFIX_MODIFIER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INCOMPATIBLE_MODIFIERS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INFERENCE_ERROR
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INTERFACE_WITH_SUPERCLASS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVALID_TYPE_OF_ANNOTATION_MEMBER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LEAKED_IN_PLACE_LAMBDA
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LOCAL_ANNOTATION_CLASS_ERROR
@@ -70,13 +74,18 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDECLARATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_MODIFIER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REPEATED_MODIFIER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_NOT_ALLOWED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SEALED_CLASS_CONSTRUCTOR_CALL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SEALED_SUPERTYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SEALED_SUPERTYPE_IN_LOCAL_CLASS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPERCLASS_NOT_ACCESSIBLE_FROM_INTERFACE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPERTYPE_INITIALIZED_IN_INTERFACE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPER_IS_NOT_AN_EXPRESSION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPER_NOT_AVAILABLE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SYNTAX_ERROR
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_ARGUMENTS_NOT_ALLOWED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_MISMATCH
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETERS_IN_ENUM
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETERS_IN_OBJECT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_AS_SUPERTYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNINITIALIZED_VARIABLE
@@ -112,6 +121,7 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
map.put(NOT_A_LOOP_LABEL, "The label does not denote a loop") // *
map.put(VARIABLE_EXPECTED, "Variable expected")
map.put(RETURN_NOT_ALLOWED, "'return' is not allowed here")
map.put(DELEGATION_IN_INTERFACE, "Interfaces cannot use delegation")
// Unresolved
map.put(HIDDEN, "Symbol {0} is invisible", SYMBOL)
@@ -138,6 +148,11 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
"Explicitly qualified supertype is extended by another supertype ''{0}''",
TO_STRING
)
map.put(SUPERTYPE_INITIALIZED_IN_INTERFACE, "Interfaces cannot initialize supertypes")
map.put(INTERFACE_WITH_SUPERCLASS, "An interface cannot inherit from a class")
map.put(CLASS_IN_SUPERTYPE_FOR_ENUM, "Enum class cannot inherit from classes")
map.put(SEALED_SUPERTYPE, "This type is sealed, so it can be inherited by only its own nested classes or objects")
map.put(SEALED_SUPERTYPE_IN_LOCAL_CLASS, "Local class cannot extend a sealed class")
// Constructor problems
map.put(CONSTRUCTOR_IN_OBJECT, "Constructors are not allowed for objects")
@@ -153,6 +168,7 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
EXPLICIT_DELEGATION_CALL_REQUIRED,
"Explicit 'this' or 'super' call is required. There is no constructor in superclass that can be called without arguments"
)
map.put(SEALED_CLASS_CONSTRUCTOR_CALL, "Sealed types cannot be instantiated")
// Annotations
map.put(ANNOTATION_CLASS_MEMBER, "Members are not allowed in annotation class")
@@ -226,11 +242,13 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
map.put(NO_TYPE_FOR_TYPE_PARAMETER, "There're no types suitable for this type parameter") // &
map.put(TYPE_PARAMETERS_IN_OBJECT, "Type parameters are not allowed for objects")
// map.put(ILLEGAL_PROJECTION_USAGE, ...) // &
map.put(TYPE_PARAMETERS_IN_ENUM, "Enum class cannot have type parameters")
// Redeclarations
map.put(MANY_COMPANION_OBJECTS, "Only one companion object is allowed per class")
map.put(CONFLICTING_OVERLOADS, "Conflicting overloads: {0}", TO_STRING) // *
map.put(REDECLARATION, "Conflicting declarations: {0}", TO_STRING) // *
map.put(ANY_METHOD_IMPLEMENTED_IN_INTERFACE, "An interface may not implement a method of 'Any'") // &
// Invalid local declarations
map.put(
@@ -36,6 +36,7 @@ object FirErrors {
val NOT_A_LOOP_LABEL by error0<FirSourceElement, PsiElement>()
val VARIABLE_EXPECTED by error0<FirSourceElement, PsiElement>()
val RETURN_NOT_ALLOWED by error0<FirSourceElement, PsiElement>()
val DELEGATION_IN_INTERFACE by error0<FirSourceElement, PsiElement>()
// Unresolved
val HIDDEN by error1<FirSourceElement, PsiElement, AbstractFirBasedSymbol<*>>()
@@ -58,6 +59,11 @@ object FirErrors {
val NOT_A_SUPERTYPE by error0<FirSourceElement, PsiElement>()
val SUPERCLASS_NOT_ACCESSIBLE_FROM_INTERFACE by error0<FirSourceElement, PsiElement>()
val QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE by error1<FirSourceElement, PsiElement, FirClass<*>>()
val SUPERTYPE_INITIALIZED_IN_INTERFACE by error0<FirSourceElement, PsiElement>()
val INTERFACE_WITH_SUPERCLASS by error0<FirSourceElement, PsiElement>()
val CLASS_IN_SUPERTYPE_FOR_ENUM by error0<FirSourceElement, PsiElement>()
val SEALED_SUPERTYPE by error0<FirSourceElement, PsiElement>()
val SEALED_SUPERTYPE_IN_LOCAL_CLASS by error0<FirSourceElement, PsiElement>()
// Constructor problems
val CONSTRUCTOR_IN_OBJECT by existing<FirSourceElement, KtDeclaration>(Errors.CONSTRUCTOR_IN_OBJECT)
@@ -70,6 +76,7 @@ object FirErrors {
val DELEGATION_SUPER_CALL_IN_ENUM_CONSTRUCTOR by warning0<FirSourceElement, PsiElement>()
val PRIMARY_CONSTRUCTOR_REQUIRED_FOR_DATA_CLASS by warning0<FirSourceElement, PsiElement>()
val EXPLICIT_DELEGATION_CALL_REQUIRED by warning0<FirSourceElement, PsiElement>()
val SEALED_CLASS_CONSTRUCTOR_CALL by error0<FirSourceElement, PsiElement>()
// Annotations
val ANNOTATION_CLASS_MEMBER by existing<FirSourceElement, PsiElement>(Errors.ANNOTATION_CLASS_MEMBER)
@@ -117,11 +124,13 @@ object FirErrors {
val NO_TYPE_FOR_TYPE_PARAMETER by error0<FirSourceElement, PsiElement>()
val TYPE_PARAMETERS_IN_OBJECT by error0<FirSourceElement, PsiElement>()
val ILLEGAL_PROJECTION_USAGE by error0<FirSourceElement, PsiElement>()
val TYPE_PARAMETERS_IN_ENUM by error0<FirSourceElement, PsiElement>()
// Redeclarations
val MANY_COMPANION_OBJECTS by error0<FirSourceElement, PsiElement>()
val CONFLICTING_OVERLOADS by error1<FirSourceElement, PsiElement, String>()
val REDECLARATION by error1<FirSourceElement, PsiElement, String>()
val ANY_METHOD_IMPLEMENTED_IN_INTERFACE by error0<FirSourceElement, PsiElement>()
// Invalid local declarations
val LOCAL_OBJECT_NOT_ALLOWED by error1<FirSourceElement, PsiElement, Name>()