diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index a3f994cc4ca..878661fb795 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -82,6 +82,10 @@ object DIAGNOSTICS_LIST : DiagnosticList() { val NO_THIS by error() } + val CALL_RESOLUTION by object : DiagnosticGroup("Call resolution") { + val CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS by error() + } + val SUPER by object : DiagnosticGroup("Super") { val SUPER_IS_NOT_AN_EXPRESSION by error(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) val SUPER_NOT_AVAILABLE by error(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 072455dce69..afb29389227 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -105,6 +105,9 @@ object FirErrors { val MISSING_STDLIB_CLASS by error0() val NO_THIS by error0() + // Call resolution + val CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS by error0() + // Super val SUPER_IS_NOT_AN_EXPRESSION by error0(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) val SUPER_NOT_AVAILABLE by error0(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirConstructorCallChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirConstructorCallChecker.kt new file mode 100644 index 00000000000..fd7cd73b936 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirConstructorCallChecker.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2010-2021 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.expression + +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClass +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn +import org.jetbrains.kotlin.fir.declarations.isAbstract +import org.jetbrains.kotlin.fir.expressions.FirFunctionCall +import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference +import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol +import org.jetbrains.kotlin.fir.types.coneType + +object FirConstructorCallChecker : FirFunctionCallChecker() { + override fun check(expression: FirFunctionCall, context: CheckerContext, reporter: DiagnosticReporter) { + val constructorSymbol = + (expression.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirConstructorSymbol ?: return + val declarationClass = constructorSymbol.fir.returnTypeRef.coneType.toRegularClass(context.session) + + if (declarationClass != null && declarationClass.isAbstract && declarationClass.classKind == ClassKind.CLASS) { + reporter.reportOn(expression.source, FirErrors.CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS, context) + } + } +} \ No newline at end of file diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt index fe0ab6f790a..da7cb0ce4f5 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt @@ -71,6 +71,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONST_VAL_WITHOUT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONST_VAL_WITH_DELEGATE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONST_VAL_WITH_GETTER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONST_VAL_WITH_NON_CONST_INITIALIZER +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CYCLIC_CONSTRUCTOR_DELEGATION_CALL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CYCLIC_GENERIC_UPPER_BOUND import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DATA_CLASS_NOT_PROPERTY_PARAMETER @@ -345,6 +346,7 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension { "Cannot access ''{0}'' before superclass constructor has been called", TO_STRING ) + map.put(CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS, "Cannot create an instance of an abstract class") // Supertypes map.put(ENUM_AS_SUPERTYPE, "Enum as supertype") diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonExpressionCheckers.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonExpressionCheckers.kt index 5870332d7d3..ebbdc213351 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonExpressionCheckers.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonExpressionCheckers.kt @@ -38,7 +38,8 @@ object CommonExpressionCheckers : ExpressionCheckers() { override val functionCallCheckers: Set get() = setOf( FirConventionFunctionCallChecker, - FirDivisionByZeroChecker + FirDivisionByZeroChecker, + FirConstructorCallChecker ) override val tryExpressionCheckers: Set diff --git a/compiler/testData/diagnostics/tests/Abstract.fir.kt b/compiler/testData/diagnostics/tests/Abstract.fir.kt index 19b0ef410ec..1a94ca4e70a 100644 --- a/compiler/testData/diagnostics/tests/Abstract.fir.kt +++ b/compiler/testData/diagnostics/tests/Abstract.fir.kt @@ -56,6 +56,6 @@ abstract class B3(i: Int) { } fun foo(c: B3) { - val a = B3(1) - val b = B1(2, "s") -} \ No newline at end of file + val a = B3(1) + val b = B1(2, "s") +} diff --git a/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorWrongClass.fir.kt b/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorWrongClass.fir.kt index e95173e0a38..1e5766db819 100644 --- a/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorWrongClass.fir.kt +++ b/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorWrongClass.fir.kt @@ -2,8 +2,8 @@ abstract class AbstractClass typealias Test1 = AbstractClass -val test1 = Test1() -val test1a = AbstractClass() +val test1 = Test1() +val test1a = AbstractClass() annotation class AnnotationClass typealias Test2 = AnnotationClass diff --git a/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-1/neg/2.1.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-1/neg/2.1.fir.kt deleted file mode 100644 index 20f4402a16f..00000000000 --- a/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-1/neg/2.1.fir.kt +++ /dev/null @@ -1,20 +0,0 @@ -// !LANGUAGE: +NewInference -// !DIAGNOSTICS: -UNUSED_VARIABLE -ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE -UNUSED_VALUE -UNUSED_PARAMETER -UNUSED_EXPRESSION -// SKIP_TXT - -// TESTCASE NUMBER: 1 -abstract class Base0() - -abstract class Base1() { - abstract fun foo() -} - -abstract class Base2(var b1: Any, val a1: Any) { - abstract fun foo() -} - -fun case1() { - val b0 = Base0() - val b1 = Base1() - val b2 = Base2(1, "1") -} diff --git a/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-1/neg/2.1.kt b/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-1/neg/2.1.kt index 69d28f1a5c4..dab3ac541aa 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-1/neg/2.1.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-1/neg/2.1.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !LANGUAGE: +NewInference // !DIAGNOSTICS: -UNUSED_VARIABLE -ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE -UNUSED_VALUE -UNUSED_PARAMETER -UNUSED_EXPRESSION // SKIP_TXT diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt index f1a991b2f2c..decdc10df6f 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -233,6 +233,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS) { firDiagnostic -> + CreatingAnInstanceOfAbstractClassImpl( + firDiagnostic as FirPsiDiagnostic<*>, + token, + ) + } add(FirErrors.SUPER_IS_NOT_AN_EXPRESSION) { firDiagnostic -> SuperIsNotAnExpressionImpl( firDiagnostic as FirPsiDiagnostic<*>, diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt index b4da34f311a..b17e278cce6 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt @@ -182,6 +182,10 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = NoThis::class } + abstract class CreatingAnInstanceOfAbstractClass : KtFirDiagnostic() { + override val diagnosticClass get() = CreatingAnInstanceOfAbstractClass::class + } + abstract class SuperIsNotAnExpression : KtFirDiagnostic() { override val diagnosticClass get() = SuperIsNotAnExpression::class } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 5c254c428d3..788026669a6 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -270,6 +270,13 @@ internal class NoThisImpl( override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) } +internal class CreatingAnInstanceOfAbstractClassImpl( + firDiagnostic: FirPsiDiagnostic<*>, + override val token: ValidityToken, +) : KtFirDiagnostic.CreatingAnInstanceOfAbstractClass(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + internal class SuperIsNotAnExpressionImpl( firDiagnostic: FirPsiDiagnostic<*>, override val token: ValidityToken, diff --git a/idea/testData/checker/Abstract.fir.kt b/idea/testData/checker/Abstract.fir.kt index 5d6d1afe539..18acaf89d36 100644 --- a/idea/testData/checker/Abstract.fir.kt +++ b/idea/testData/checker/Abstract.fir.kt @@ -169,6 +169,6 @@ abstract class B3(i: Int) { } fun foo(a: B3) { - val a = B3(1) - val b = B1(2, "s") + val a = B3(1) + val b = B1(2, "s") }