[FIR] Report MISSING_CONSTRUCTOR_KEYWORD
^KT-59407 Fixed
This commit is contained in:
committed by
Space Team
parent
f238ffa4bf
commit
c33f1cda69
+6
@@ -278,6 +278,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.MISSING_CONSTRUCTOR_KEYWORD) { firDiagnostic ->
|
||||
MissingConstructorKeywordImpl(
|
||||
firDiagnostic as KtPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.INVISIBLE_REFERENCE) { firDiagnostic ->
|
||||
InvisibleReferenceImpl(
|
||||
firSymbolBuilder.buildSymbol(firDiagnostic.a),
|
||||
|
||||
+4
@@ -237,6 +237,10 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
val diagnosticName: String
|
||||
}
|
||||
|
||||
interface MissingConstructorKeyword : KtFirDiagnostic<PsiElement> {
|
||||
override val diagnosticClass get() = MissingConstructorKeyword::class
|
||||
}
|
||||
|
||||
interface InvisibleReference : KtFirDiagnostic<PsiElement> {
|
||||
override val diagnosticClass get() = InvisibleReference::class
|
||||
val reference: KtSymbol
|
||||
|
||||
+5
@@ -270,6 +270,11 @@ internal class ErrorSuppressionImpl(
|
||||
token: KtLifetimeToken,
|
||||
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.ErrorSuppression
|
||||
|
||||
internal class MissingConstructorKeywordImpl(
|
||||
firDiagnostic: KtPsiDiagnostic,
|
||||
token: KtLifetimeToken,
|
||||
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.MissingConstructorKeyword
|
||||
|
||||
internal class InvisibleReferenceImpl(
|
||||
override val reference: KtSymbol,
|
||||
override val visible: Visibility,
|
||||
|
||||
+1
@@ -108,6 +108,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val ERROR_SUPPRESSION by warning<PsiElement> {
|
||||
parameter<String>("diagnosticName")
|
||||
}
|
||||
val MISSING_CONSTRUCTOR_KEYWORD by error<PsiElement>()
|
||||
}
|
||||
|
||||
val UNRESOLVED by object : DiagnosticGroup("Unresolved") {
|
||||
|
||||
@@ -153,6 +153,7 @@ object FirErrors {
|
||||
val INVISIBLE_SETTER by error3<PsiElement, FirPropertySymbol, Visibility, CallableId>(SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED)
|
||||
val INNER_ON_TOP_LEVEL_SCRIPT_CLASS by deprecationError0<PsiElement>(ProhibitScriptTopLevelInnerClasses)
|
||||
val ERROR_SUPPRESSION by warning1<PsiElement, String>()
|
||||
val MISSING_CONSTRUCTOR_KEYWORD by error0<PsiElement>()
|
||||
|
||||
// Unresolved
|
||||
val INVISIBLE_REFERENCE by error3<PsiElement, FirBasedSymbol<*>, Visibility, ClassId?>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
|
||||
+1
@@ -40,6 +40,7 @@ val FIR_NON_SUPPRESSIBLE_ERROR_NAMES: Set<String> = setOf(
|
||||
"VAL_OR_VAR_ON_CATCH_PARAMETER",
|
||||
"VAL_OR_VAR_ON_SECONDARY_CONSTRUCTOR_PARAMETER",
|
||||
"INVISIBLE_SETTER",
|
||||
"MISSING_CONSTRUCTOR_KEYWORD",
|
||||
"INVISIBLE_REFERENCE",
|
||||
"UNRESOLVED_REFERENCE",
|
||||
"UNRESOLVED_LABEL",
|
||||
|
||||
+7
-8
@@ -8,20 +8,20 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.KtNodeTypes
|
||||
import org.jetbrains.kotlin.descriptors.isEnumEntry
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.SourceNavigator
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirErrorPrimaryConstructor
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isInterface
|
||||
import org.jetbrains.kotlin.fir.declarations.primaryConstructorIfAny
|
||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isErrorPrimaryConstructor
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isInterface
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirImplicitAnyTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.toRegularClassSymbol
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.lastIsInstanceOrNull
|
||||
|
||||
@@ -43,8 +43,7 @@ object FirPrimaryConstructorSuperTypeChecker : FirClassChecker() {
|
||||
|
||||
val primaryConstructorSymbol = declaration.primaryConstructorIfAny(context.session)
|
||||
|
||||
@OptIn(SymbolInternals::class)
|
||||
if (primaryConstructorSymbol == null || primaryConstructorSymbol.fir is FirErrorPrimaryConstructor) {
|
||||
if (primaryConstructorSymbol == null || primaryConstructorSymbol.isErrorPrimaryConstructor) {
|
||||
checkSupertypeInitializedWithoutPrimaryConstructor(declaration, reporter, context)
|
||||
} else {
|
||||
checkSuperTypeNotInitialized(primaryConstructorSymbol, declaration, context, reporter)
|
||||
|
||||
+3
@@ -122,6 +122,9 @@ abstract class AbstractDiagnosticCollectorVisitor(
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitErrorPrimaryConstructor(errorPrimaryConstructor: FirErrorPrimaryConstructor, data: Nothing?) =
|
||||
visitConstructor(errorPrimaryConstructor, data)
|
||||
|
||||
override fun visitAnonymousFunctionExpression(anonymousFunctionExpression: FirAnonymousFunctionExpression, data: Nothing?) {
|
||||
visitAnonymousFunction(anonymousFunctionExpression.anonymousFunction, data)
|
||||
}
|
||||
|
||||
+2
@@ -355,6 +355,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MANY_INTERFACES_M
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MANY_LAMBDA_EXPRESSION_ARGUMENTS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MISPLACED_TYPE_PARAMETER_CONSTRAINTS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MISSING_CONSTRUCTOR_KEYWORD
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MISSING_STDLIB_CLASS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MISSING_VAL_ON_ANNOTATION_PARAMETER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MIXING_FUNCTIONAL_KINDS_IN_SUPERTYPES
|
||||
@@ -765,6 +766,7 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
||||
"This code uses error suppression for ''{0}''. While it might compile and work, the compiler behavior is UNSPECIFIED and WON''T BE PRESERVED. Please report your use case to the Kotlin issue tracker instead: https://kotl.in/issue",
|
||||
TO_STRING
|
||||
)
|
||||
map.put(MISSING_CONSTRUCTOR_KEYWORD, "Use the 'constructor' keyword after the modifiers of the primary constructor.")
|
||||
map.put(UNRESOLVED_REFERENCE, "Unresolved reference ''{0}''.", NULLABLE_STRING)
|
||||
map.put(UNRESOLVED_IMPORT, "Unresolved reference ''{0}''.", NULLABLE_STRING) // &
|
||||
map.put(UNRESOLVED_LABEL, "Unresolved label.")
|
||||
|
||||
+1
@@ -153,6 +153,7 @@ private fun ConeDiagnostic.toKtDiagnostic(
|
||||
FirErrors.AMBIGUOUS_ANNOTATION_ARGUMENT.createOn(source, listOfNotNull(symbolFromCompilerPhase, symbolFromAnnotationArgumentsPhase))
|
||||
is ConeAmbiguousFunctionTypeKinds -> FirErrors.AMBIGUOUS_FUNCTION_TYPE_KIND.createOn(source, kinds)
|
||||
is ConeUnsupportedClassLiteralsWithEmptyLhs -> FirErrors.UNSUPPORTED_CLASS_LITERALS_WITH_EMPTY_LHS.createOn(source)
|
||||
is ConeMissingConstructorKeyword -> FirErrors.MISSING_CONSTRUCTOR_KEYWORD.createOn(source)
|
||||
else -> throw IllegalArgumentException("Unsupported diagnostic type: ${this.javaClass}")
|
||||
}
|
||||
|
||||
|
||||
+9
-8
@@ -904,14 +904,17 @@ class LightTreeRawFirDeclarationBuilder(
|
||||
}
|
||||
|
||||
val constructorSymbol = FirConstructorSymbol(callableIdForClassConstructor())
|
||||
var modifiers = Modifier()
|
||||
var modifiersIfPresent: Modifier? = null
|
||||
val valueParameters = mutableListOf<ValueParameter>()
|
||||
var hasConstructorKeyword = false
|
||||
primaryConstructor?.forEachChildren {
|
||||
when (it.tokenType) {
|
||||
MODIFIER_LIST -> modifiers = convertModifierList(it)
|
||||
MODIFIER_LIST -> modifiersIfPresent = convertModifierList(it)
|
||||
CONSTRUCTOR_KEYWORD -> hasConstructorKeyword = true
|
||||
VALUE_PARAMETER_LIST -> valueParameters += convertValueParameters(it, constructorSymbol, ValueParameterDeclaration.PRIMARY_CONSTRUCTOR)
|
||||
}
|
||||
}
|
||||
val modifiers = modifiersIfPresent ?: Modifier()
|
||||
|
||||
val defaultVisibility = classWrapper.defaultConstructorVisibility()
|
||||
val firDelegatedCall = runUnless(containingClassIsExpectClass) {
|
||||
@@ -968,12 +971,10 @@ class LightTreeRawFirDeclarationBuilder(
|
||||
isFromEnumClass = classWrapper.isEnum()
|
||||
}
|
||||
|
||||
val builder = if (isErrorConstructor) {
|
||||
FirErrorConstructorBuilder().apply {
|
||||
diagnostic = ConeNoConstructorError
|
||||
}
|
||||
} else {
|
||||
FirPrimaryConstructorBuilder()
|
||||
val builder = when {
|
||||
modifiersIfPresent != null && !hasConstructorKeyword -> createErrorConstructorBuilder(ConeMissingConstructorKeyword)
|
||||
isErrorConstructor -> createErrorConstructorBuilder(ConeNoConstructorError)
|
||||
else -> FirPrimaryConstructorBuilder()
|
||||
}
|
||||
builder.apply {
|
||||
source = primaryConstructor?.toFirSourceElement()
|
||||
|
||||
+5
-6
@@ -1059,12 +1059,11 @@ open class PsiRawFirBuilder(
|
||||
isFromSealedClass = owner.hasModifier(SEALED_KEYWORD) && explicitVisibility !== Visibilities.Private
|
||||
isFromEnumClass = owner.hasModifier(ENUM_KEYWORD)
|
||||
}
|
||||
val builder = if (isErrorConstructor) {
|
||||
FirErrorConstructorBuilder().apply {
|
||||
diagnostic = ConeNoConstructorError
|
||||
}
|
||||
} else {
|
||||
FirPrimaryConstructorBuilder()
|
||||
val hasConstructorKeyword = this@toFirConstructor?.getConstructorKeyword() != null
|
||||
val builder = when {
|
||||
this?.modifierList != null && !hasConstructorKeyword -> createErrorConstructorBuilder(ConeMissingConstructorKeyword)
|
||||
isErrorConstructor -> createErrorConstructorBuilder(ConeNoConstructorError)
|
||||
else -> FirPrimaryConstructorBuilder()
|
||||
}
|
||||
builder.apply {
|
||||
source = constructorSource
|
||||
|
||||
+3
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.fir.declarations.utils
|
||||
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||
@@ -68,3 +69,5 @@ val FirNamedFunctionSymbol.isMethodOfAny: Boolean
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
val FirConstructorSymbol.isErrorPrimaryConstructor get() = fir is FirErrorPrimaryConstructor
|
||||
|
||||
@@ -83,6 +83,10 @@ object ConeNoConstructorError : ConeDiagnostic {
|
||||
override val reason: String get() = "This type does not have a constructor"
|
||||
}
|
||||
|
||||
object ConeMissingConstructorKeyword : ConeDiagnostic {
|
||||
override val reason: String get() = "Use the 'constructor' keyword after the modifiers of the primary constructor."
|
||||
}
|
||||
|
||||
enum class DiagnosticKind {
|
||||
ExpressionExpected,
|
||||
NotLoopLabel,
|
||||
|
||||
+4
-4
@@ -1,9 +1,9 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
annotation class Ann(val x: Int = 1)
|
||||
class A private (val x: Int) {
|
||||
inner class B @Ann(2) (val y: Int)
|
||||
class A <!MISSING_CONSTRUCTOR_KEYWORD!>private (val x: Int)<!> {
|
||||
inner class B <!MISSING_CONSTRUCTOR_KEYWORD!>@Ann(2) (val y: Int)<!>
|
||||
|
||||
fun foo() {
|
||||
class C private @Ann(3) (args: Int)
|
||||
fun foo() {
|
||||
class C <!MISSING_CONSTRUCTOR_KEYWORD!>private @Ann(3) (args: Int)<!>
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,9 +1,9 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
annotation class Ann(val x: Int = 1)
|
||||
class A <!MISSING_CONSTRUCTOR_KEYWORD!>private<!> (val x: Int) {
|
||||
inner class B <!MISSING_CONSTRUCTOR_KEYWORD!>@Ann(2)<!> (val y: Int)
|
||||
inner class B <!MISSING_CONSTRUCTOR_KEYWORD!>@Ann(2)<!> (val y: Int)
|
||||
|
||||
fun foo() {
|
||||
class C <!MISSING_CONSTRUCTOR_KEYWORD!>private @Ann(3)<!> (args: Int)
|
||||
fun foo() {
|
||||
class C <!MISSING_CONSTRUCTOR_KEYWORD!>private @Ann(3)<!> (args: Int)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user