Prohibit properties with backing fields inside inline classes
This commit is contained in:
@@ -317,6 +317,7 @@ public interface Errors {
|
|||||||
DiagnosticFactory0<KtElement> INLINE_CLASS_CONSTRUCTOR_WRONG_PARAMETERS_SIZE = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<KtElement> INLINE_CLASS_CONSTRUCTOR_WRONG_PARAMETERS_SIZE = DiagnosticFactory0.create(ERROR);
|
||||||
DiagnosticFactory0<KtParameter> INLINE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<KtParameter> INLINE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER = DiagnosticFactory0.create(ERROR);
|
||||||
DiagnosticFactory0<PsiElement> INLINE_CLASS_WITH_INITIALIZER = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<PsiElement> INLINE_CLASS_WITH_INITIALIZER = DiagnosticFactory0.create(ERROR);
|
||||||
|
DiagnosticFactory0<KtProperty> PROPERTY_WITH_BACKING_FIELD_INSIDE_INLINE_CLASS = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
||||||
|
|
||||||
// Secondary constructors
|
// Secondary constructors
|
||||||
|
|
||||||
|
|||||||
+1
@@ -631,6 +631,7 @@ public class DefaultErrorMessages {
|
|||||||
MAP.put(INLINE_CLASS_CONSTRUCTOR_WRONG_PARAMETERS_SIZE, "Inline class must have exactly one primary constructor parameter");
|
MAP.put(INLINE_CLASS_CONSTRUCTOR_WRONG_PARAMETERS_SIZE, "Inline class must have exactly one primary constructor parameter");
|
||||||
MAP.put(INLINE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER, "Inline class primary constructor must have only final read-only (val) property parameter");
|
MAP.put(INLINE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER, "Inline class primary constructor must have only final read-only (val) property parameter");
|
||||||
MAP.put(INLINE_CLASS_WITH_INITIALIZER, "Inline class cannot have an initializer block");
|
MAP.put(INLINE_CLASS_WITH_INITIALIZER, "Inline class cannot have an initializer block");
|
||||||
|
MAP.put(PROPERTY_WITH_BACKING_FIELD_INSIDE_INLINE_CLASS, "Inline class cannot have properties with backing fields");
|
||||||
|
|
||||||
MAP.put(VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED, "Variance annotations are only allowed for type parameters of classes and interfaces");
|
MAP.put(VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED, "Variance annotations are only allowed for type parameters of classes and interfaces");
|
||||||
MAP.put(BOUND_ON_TYPE_ALIAS_PARAMETER_NOT_ALLOWED, "Bounds are not allowed on type alias parameters");
|
MAP.put(BOUND_ON_TYPE_ALIAS_PARAMETER_NOT_ALLOWED, "Bounds are not allowed on type alias parameters");
|
||||||
|
|||||||
@@ -84,7 +84,8 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf(
|
|||||||
DelegationChecker(),
|
DelegationChecker(),
|
||||||
KClassWithIncorrectTypeArgumentChecker,
|
KClassWithIncorrectTypeArgumentChecker,
|
||||||
SuspendOperatorsCheckers,
|
SuspendOperatorsCheckers,
|
||||||
InlineClassDeclarationChecker
|
InlineClassDeclarationChecker,
|
||||||
|
PropertiesWithBackingFieldsInsideInlineClass()
|
||||||
)
|
)
|
||||||
|
|
||||||
private val DEFAULT_CALL_CHECKERS = listOf(
|
private val DEFAULT_CALL_CHECKERS = listOf(
|
||||||
|
|||||||
+17
-8
@@ -5,19 +5,15 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.resolve.checkers
|
package org.jetbrains.kotlin.resolve.checkers
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.KtClass
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.KtClassInitializer
|
|
||||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
|
||||||
import org.jetbrains.kotlin.psi.KtParameter
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.modalityModifier
|
import org.jetbrains.kotlin.psi.psiUtil.modalityModifier
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifier
|
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifier
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.isInlineClass
|
||||||
|
|
||||||
object InlineClassDeclarationChecker : DeclarationChecker {
|
object InlineClassDeclarationChecker : DeclarationChecker {
|
||||||
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||||
@@ -81,4 +77,17 @@ object InlineClassDeclarationChecker : DeclarationChecker {
|
|||||||
val isOpen = parameter.modalityModifier()?.node?.elementType == KtTokens.OPEN_KEYWORD
|
val isOpen = parameter.modalityModifier()?.node?.elementType == KtTokens.OPEN_KEYWORD
|
||||||
return parameter.hasValOrVar() && !parameter.isMutable && !parameter.isVarArg && !parameter.hasDefaultValue() && !isOpen
|
return parameter.hasValOrVar() && !parameter.isMutable && !parameter.isVarArg && !parameter.hasDefaultValue() && !isOpen
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PropertiesWithBackingFieldsInsideInlineClass : DeclarationChecker {
|
||||||
|
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||||
|
if (declaration !is KtProperty) return
|
||||||
|
if (descriptor !is PropertyDescriptor) return
|
||||||
|
|
||||||
|
if (!descriptor.containingDeclaration.isInlineClass()) return
|
||||||
|
|
||||||
|
if (context.trace.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor) == true) {
|
||||||
|
context.trace.report(Errors.PROPERTY_WITH_BACKING_FIELD_INSIDE_INLINE_CLASS.on(declaration))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Vendored
+34
@@ -0,0 +1,34 @@
|
|||||||
|
// !LANGUAGE: +InlineClasses
|
||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
|
||||||
|
interface A {
|
||||||
|
val goodSize: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
interface B {
|
||||||
|
val badSize: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
inline class Foo(val x: Int) : A, B {
|
||||||
|
val a0
|
||||||
|
get() = 0
|
||||||
|
|
||||||
|
<!PROPERTY_WITH_BACKING_FIELD_INSIDE_INLINE_CLASS!>val a1<!> = 0
|
||||||
|
|
||||||
|
var a2: Int
|
||||||
|
get() = 1
|
||||||
|
set(value) {}
|
||||||
|
|
||||||
|
<!PROPERTY_WITH_BACKING_FIELD_INSIDE_INLINE_CLASS!>var a3: Int<!> = 0
|
||||||
|
get() = 1
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
}
|
||||||
|
|
||||||
|
override val goodSize: Int
|
||||||
|
get() = 0
|
||||||
|
|
||||||
|
<!PROPERTY_WITH_BACKING_FIELD_INSIDE_INLINE_CLASS!>override val badSize: Int<!> = 0
|
||||||
|
|
||||||
|
<!PROPERTY_WITH_BACKING_FIELD_INSIDE_INLINE_CLASS!>lateinit var lateinitProperty: String<!>
|
||||||
|
}
|
||||||
Vendored
+30
@@ -0,0 +1,30 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public interface A {
|
||||||
|
public abstract val goodSize: kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface B {
|
||||||
|
public abstract val badSize: kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public final inline class Foo : A, B {
|
||||||
|
public constructor Foo(/*0*/ x: kotlin.Int)
|
||||||
|
public final val a0: kotlin.Int
|
||||||
|
public final val a1: kotlin.Int = 0
|
||||||
|
public final var a2: kotlin.Int
|
||||||
|
public final var a3: kotlin.Int
|
||||||
|
public open override /*1*/ val badSize: kotlin.Int = 0
|
||||||
|
public open override /*1*/ val goodSize: kotlin.Int
|
||||||
|
public final lateinit var lateinitProperty: kotlin.String
|
||||||
|
public final val x: kotlin.Int
|
||||||
|
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
@@ -10693,6 +10693,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
runTest("compiler/testData/diagnostics/tests/inlineClasses/presenceOfPublicPrimaryConstructorForInlineClass.kt");
|
runTest("compiler/testData/diagnostics/tests/inlineClasses/presenceOfPublicPrimaryConstructorForInlineClass.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("propertiesWithBackingFieldsInsideInlineClass.kt")
|
||||||
|
public void testPropertiesWithBackingFieldsInsideInlineClass() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/inlineClasses/propertiesWithBackingFieldsInsideInlineClass.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("varargsOnParametersOfInlineClassType.kt")
|
@TestMetadata("varargsOnParametersOfInlineClassType.kt")
|
||||||
public void testVarargsOnParametersOfInlineClassType() throws Exception {
|
public void testVarargsOnParametersOfInlineClassType() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/inlineClasses/varargsOnParametersOfInlineClassType.kt");
|
runTest("compiler/testData/diagnostics/tests/inlineClasses/varargsOnParametersOfInlineClassType.kt");
|
||||||
|
|||||||
Generated
+5
@@ -10693,6 +10693,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
|||||||
runTest("compiler/testData/diagnostics/tests/inlineClasses/presenceOfPublicPrimaryConstructorForInlineClass.kt");
|
runTest("compiler/testData/diagnostics/tests/inlineClasses/presenceOfPublicPrimaryConstructorForInlineClass.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("propertiesWithBackingFieldsInsideInlineClass.kt")
|
||||||
|
public void testPropertiesWithBackingFieldsInsideInlineClass() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/inlineClasses/propertiesWithBackingFieldsInsideInlineClass.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("varargsOnParametersOfInlineClassType.kt")
|
@TestMetadata("varargsOnParametersOfInlineClassType.kt")
|
||||||
public void testVarargsOnParametersOfInlineClassType() throws Exception {
|
public void testVarargsOnParametersOfInlineClassType() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/inlineClasses/varargsOnParametersOfInlineClassType.kt");
|
runTest("compiler/testData/diagnostics/tests/inlineClasses/varargsOnParametersOfInlineClassType.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user