KT-4107 Data objects
This commit is contained in:
+2
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.descriptors.EffectiveVisibility
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.diagnostics.WhenMissingCase
|
||||
import org.jetbrains.kotlin.diagnostics.deprecationError2
|
||||
import org.jetbrains.kotlin.diagnostics.error0
|
||||
import org.jetbrains.kotlin.fir.FirModuleData
|
||||
import org.jetbrains.kotlin.fir.PrivateForInline
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.*
|
||||
@@ -901,6 +902,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val TAILREC_ON_VIRTUAL_MEMBER_ERROR by error<KtNamedFunction>(PositioningStrategy.TAILREC_MODIFIER)
|
||||
val NON_TAIL_RECURSIVE_CALL by warning<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED by warning<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val DATA_OBJECT_CUSTOM_EQUALS_OR_HASH_CODE by error<KtNamedFunction>(PositioningStrategy.OVERRIDE_MODIFIER)
|
||||
}
|
||||
|
||||
val FUN_INTERFACES by object : DiagnosticGroup("Fun interfaces") {
|
||||
|
||||
@@ -483,6 +483,7 @@ object FirErrors {
|
||||
val TAILREC_ON_VIRTUAL_MEMBER_ERROR by error0<KtNamedFunction>(SourceElementPositioningStrategies.TAILREC_MODIFIER)
|
||||
val NON_TAIL_RECURSIVE_CALL by warning0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED by warning0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val DATA_OBJECT_CUSTOM_EQUALS_OR_HASH_CODE by error0<KtNamedFunction>(SourceElementPositioningStrategies.OVERRIDE_MODIFIER)
|
||||
|
||||
// Fun interfaces
|
||||
val FUN_INTERFACE_CONSTRUCTOR_REFERENCE by error0<KtExpression>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
|
||||
+1
@@ -54,6 +54,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
||||
FirTailrecFunctionChecker,
|
||||
FirTopLevelFunctionsChecker,
|
||||
FirMemberFunctionsChecker,
|
||||
FirDataObjectContentChecker,
|
||||
)
|
||||
|
||||
override val propertyCheckers: Set<FirPropertyChecker>
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.KtFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.hasModifier
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.types.isNullableAny
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
object FirDataObjectContentChecker : FirSimpleFunctionChecker() {
|
||||
override fun check(declaration: FirSimpleFunction, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (!declaration.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return
|
||||
val source = declaration.source
|
||||
if (source == null || source.kind is KtFakeSourceElementKind) return
|
||||
|
||||
val containingClass = context.containingDeclarations.lastOrNull() as? FirClass ?: return
|
||||
if (containingClass.classKind != ClassKind.OBJECT || !containingClass.hasModifier(KtTokens.DATA_KEYWORD)) return
|
||||
|
||||
if (
|
||||
(declaration.name == OperatorNameConventions.HASH_CODE && declaration.valueParameters.isEmpty()) ||
|
||||
(declaration.name == OperatorNameConventions.EQUALS &&
|
||||
declaration.valueParameters.singleOrNull()?.returnTypeRef?.isNullableAny == true)
|
||||
) {
|
||||
reporter.reportOn(source, FirErrors.DATA_OBJECT_CUSTOM_EQUALS_OR_HASH_CODE, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-1
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget.Companion.classActualTargets
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.FirModifier
|
||||
@@ -27,6 +28,7 @@ import org.jetbrains.kotlin.fir.declarations.utils.isLocal
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.lexer.KtTokens.DATA_KEYWORD
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
|
||||
object FirModifierChecker : FirBasicDeclarationChecker() {
|
||||
@@ -182,7 +184,11 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
|
||||
}
|
||||
val set = map[modifierToken] ?: emptySet()
|
||||
val checkResult = if (factory == FirErrors.WRONG_MODIFIER_TARGET) {
|
||||
actualTargets.none { it in set }
|
||||
actualTargets.none { it in set } ||
|
||||
// TODO: Implement some generic feature-checking mechanism
|
||||
(modifierToken == DATA_KEYWORD
|
||||
&& actualTargets.contains(KotlinTarget.STANDALONE_OBJECT)
|
||||
&& !context.languageVersionSettings.supportsFeature(LanguageFeature.DataObjects))
|
||||
} else {
|
||||
actualTargets.any { it in set }
|
||||
}
|
||||
|
||||
+2
-1
@@ -136,6 +136,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DATA_CLASS_NOT_PR
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DATA_CLASS_OVERRIDE_CONFLICT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DATA_CLASS_VARARG_PARAMETER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DATA_CLASS_WITHOUT_PARAMETERS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DATA_OBJECT_CUSTOM_EQUALS_OR_HASH_CODE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DECLARATION_CANT_BE_INLINED
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DELEGATED_PROPERTY_INSIDE_VALUE_CLASS
|
||||
@@ -579,7 +580,6 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_MODIFIER_TA
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_NUMBER_OF_TYPE_ARGUMENTS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_SETTER_PARAMETER_TYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_SETTER_RETURN_TYPE
|
||||
import org.jetbrains.kotlin.psi.KtReferenceExpression
|
||||
|
||||
@Suppress("unused")
|
||||
object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
||||
@@ -1456,6 +1456,7 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
||||
map.put(TAILREC_ON_VIRTUAL_MEMBER_ERROR, "Tailrec is not allowed on open members")
|
||||
map.put(NON_TAIL_RECURSIVE_CALL, "Recursive call is not a tail call")
|
||||
map.put(TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED, "Tail recursion optimization inside try/catch/finally is not supported")
|
||||
map.put(DATA_OBJECT_CUSTOM_EQUALS_OR_HASH_CODE, "Data object cannot have a custom implementation of 'equals' or 'hashCode'")
|
||||
|
||||
// Fun interfaces
|
||||
map.put(FUN_INTERFACE_CONSTRUCTOR_REFERENCE, "Functional/SAM interface constructor references are prohibited")
|
||||
|
||||
Reference in New Issue
Block a user