FIR checker/IDE: Add checker and quickfix for VAL_WITH_SETTER.
This commit is contained in:
committed by
Ilya Kirillov
parent
99c47a0487
commit
1c94372b6c
+1
@@ -322,6 +322,7 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
|||||||
val PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY by error<FirSourceElement, KtModifierListOwner>(PositioningStrategy.PRIVATE_MODIFIER)
|
val PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY by error<FirSourceElement, KtModifierListOwner>(PositioningStrategy.PRIVATE_MODIFIER)
|
||||||
val PRIVATE_SETTER_FOR_OPEN_PROPERTY by error<FirSourceElement, KtModifierListOwner>(PositioningStrategy.PRIVATE_MODIFIER)
|
val PRIVATE_SETTER_FOR_OPEN_PROPERTY by error<FirSourceElement, KtModifierListOwner>(PositioningStrategy.PRIVATE_MODIFIER)
|
||||||
val EXPECTED_PRIVATE_DECLARATION by error<FirSourceElement, KtModifierListOwner>(PositioningStrategy.VISIBILITY_MODIFIER)
|
val EXPECTED_PRIVATE_DECLARATION by error<FirSourceElement, KtModifierListOwner>(PositioningStrategy.VISIBILITY_MODIFIER)
|
||||||
|
val VAL_WITH_SETTER by error<FirSourceElement, KtPropertyAccessor>()
|
||||||
}
|
}
|
||||||
|
|
||||||
val MPP_PROJECTS by object : DiagnosticGroup("Multi-platform projects") {
|
val MPP_PROJECTS by object : DiagnosticGroup("Multi-platform projects") {
|
||||||
|
|||||||
@@ -217,6 +217,7 @@ object FirErrors {
|
|||||||
val PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY by error0<FirSourceElement, KtModifierListOwner>(SourceElementPositioningStrategies.PRIVATE_MODIFIER)
|
val PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY by error0<FirSourceElement, KtModifierListOwner>(SourceElementPositioningStrategies.PRIVATE_MODIFIER)
|
||||||
val PRIVATE_SETTER_FOR_OPEN_PROPERTY by error0<FirSourceElement, KtModifierListOwner>(SourceElementPositioningStrategies.PRIVATE_MODIFIER)
|
val PRIVATE_SETTER_FOR_OPEN_PROPERTY by error0<FirSourceElement, KtModifierListOwner>(SourceElementPositioningStrategies.PRIVATE_MODIFIER)
|
||||||
val EXPECTED_PRIVATE_DECLARATION by error0<FirSourceElement, KtModifierListOwner>(SourceElementPositioningStrategies.VISIBILITY_MODIFIER)
|
val EXPECTED_PRIVATE_DECLARATION by error0<FirSourceElement, KtModifierListOwner>(SourceElementPositioningStrategies.VISIBILITY_MODIFIER)
|
||||||
|
val VAL_WITH_SETTER by error0<FirSourceElement, KtPropertyAccessor>()
|
||||||
|
|
||||||
// Multi-platform projects
|
// Multi-platform projects
|
||||||
val EXPECTED_DECLARATION_WITH_BODY by error0<FirSourceElement, KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
val EXPECTED_DECLARATION_WITH_BODY by error0<FirSourceElement, KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||||
|
|||||||
+8
-4
@@ -41,16 +41,14 @@ internal fun checkExpectDeclarationVisibilityAndBody(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun checkPropertyInitializer(
|
internal fun checkProperty(
|
||||||
containingClass: FirRegularClass?,
|
containingClass: FirRegularClass?,
|
||||||
property: FirProperty,
|
property: FirProperty,
|
||||||
|
modifierList: FirModifierList?,
|
||||||
reporter: DiagnosticReporter,
|
reporter: DiagnosticReporter,
|
||||||
context: CheckerContext
|
context: CheckerContext
|
||||||
) {
|
) {
|
||||||
val inInterface = containingClass?.isInterface == true
|
val inInterface = containingClass?.isInterface == true
|
||||||
// If multiple (potentially conflicting) modality modifiers are specified, not all modifiers are recorded at `status`.
|
|
||||||
// So, our source of truth should be the full modifier list retrieved from the source.
|
|
||||||
val modifierList = with(FirModifierList) { property.source.getModifierList() }
|
|
||||||
val hasAbstractModifier = modifierList?.modifiers?.any { it.token == KtTokens.ABSTRACT_KEYWORD } == true
|
val hasAbstractModifier = modifierList?.modifiers?.any { it.token == KtTokens.ABSTRACT_KEYWORD } == true
|
||||||
val isAbstract = property.isAbstract || hasAbstractModifier
|
val isAbstract = property.isAbstract || hasAbstractModifier
|
||||||
if (isAbstract) {
|
if (isAbstract) {
|
||||||
@@ -69,6 +67,12 @@ internal fun checkPropertyInitializer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
property.setter?.source?.let {
|
||||||
|
if (property.isVal) {
|
||||||
|
reporter.reportOn(it, FirErrors.VAL_WITH_SETTER, context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val isExpect = property.isExpect || modifierList?.modifiers?.any { it.token == KtTokens.EXPECT_KEYWORD } == true
|
val isExpect = property.isExpect || modifierList?.modifiers?.any { it.token == KtTokens.EXPECT_KEYWORD } == true
|
||||||
|
|
||||||
when {
|
when {
|
||||||
|
|||||||
+4
-4
@@ -39,6 +39,10 @@ object FirMemberPropertyChecker : FirRegularClassChecker() {
|
|||||||
// If multiple (potentially conflicting) modality modifiers are specified, not all modifiers are recorded at `status`.
|
// If multiple (potentially conflicting) modality modifiers are specified, not all modifiers are recorded at `status`.
|
||||||
// So, our source of truth should be the full modifier list retrieved from the source.
|
// So, our source of truth should be the full modifier list retrieved from the source.
|
||||||
val modifierList = with(FirModifierList) { property.source.getModifierList() }
|
val modifierList = with(FirModifierList) { property.source.getModifierList() }
|
||||||
|
|
||||||
|
checkProperty(containingDeclaration, property, modifierList, reporter, context)
|
||||||
|
checkExpectDeclarationVisibilityAndBody(property, source, modifierList, reporter, context)
|
||||||
|
|
||||||
val hasAbstractModifier = modifierList?.modifiers?.any { it.token == KtTokens.ABSTRACT_KEYWORD } == true
|
val hasAbstractModifier = modifierList?.modifiers?.any { it.token == KtTokens.ABSTRACT_KEYWORD } == true
|
||||||
val isAbstract = property.isAbstract || hasAbstractModifier
|
val isAbstract = property.isAbstract || hasAbstractModifier
|
||||||
if (containingDeclaration.isInterface &&
|
if (containingDeclaration.isInterface &&
|
||||||
@@ -83,8 +87,6 @@ object FirMemberPropertyChecker : FirRegularClassChecker() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkPropertyInitializer(containingDeclaration, property, reporter, context)
|
|
||||||
|
|
||||||
val hasOpenModifier = modifierList?.modifiers?.any { it.token == KtTokens.OPEN_KEYWORD } == true
|
val hasOpenModifier = modifierList?.modifiers?.any { it.token == KtTokens.OPEN_KEYWORD } == true
|
||||||
if (hasOpenModifier &&
|
if (hasOpenModifier &&
|
||||||
containingDeclaration.isInterface &&
|
containingDeclaration.isInterface &&
|
||||||
@@ -104,8 +106,6 @@ object FirMemberPropertyChecker : FirRegularClassChecker() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkExpectDeclarationVisibilityAndBody(property, source, modifierList, reporter, context)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkAccessor(
|
private fun checkAccessor(
|
||||||
|
|||||||
+3
-1
@@ -24,9 +24,11 @@ object FirTopLevelPropertyChecker : FirFileChecker() {
|
|||||||
private fun checkProperty(property: FirProperty, reporter: DiagnosticReporter, context: CheckerContext) {
|
private fun checkProperty(property: FirProperty, reporter: DiagnosticReporter, context: CheckerContext) {
|
||||||
val source = property.source ?: return
|
val source = property.source ?: return
|
||||||
if (source.kind is FirFakeSourceElementKind) return
|
if (source.kind is FirFakeSourceElementKind) return
|
||||||
|
// If multiple (potentially conflicting) modality modifiers are specified, not all modifiers are recorded at `status`.
|
||||||
|
// So, our source of truth should be the full modifier list retrieved from the source.
|
||||||
val modifierList = with(FirModifierList) { source.getModifierList() }
|
val modifierList = with(FirModifierList) { source.getModifierList() }
|
||||||
|
|
||||||
checkPropertyInitializer(null, property, reporter, context)
|
checkProperty(null, property, modifierList, reporter, context)
|
||||||
checkExpectDeclarationVisibilityAndBody(property, source, modifierList, reporter, context)
|
checkExpectDeclarationVisibilityAndBody(property, source, modifierList, reporter, context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -170,6 +170,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSAFE_OPERATOR_C
|
|||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNUSED_VARIABLE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNUSED_VARIABLE
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UPPER_BOUND_VIOLATED
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UPPER_BOUND_VIOLATED
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.USELESS_VARARG_ON_PARAMETER
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.USELESS_VARARG_ON_PARAMETER
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAL_WITH_SETTER
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VARIABLE_EXPECTED
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VARIABLE_EXPECTED
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VARIABLE_INITIALIZER_IS_REDUNDANT
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VARIABLE_INITIALIZER_IS_REDUNDANT
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VARIABLE_NEVER_READ
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VARIABLE_NEVER_READ
|
||||||
@@ -477,6 +478,7 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
|||||||
map.put(ABSTRACT_PROPERTY_WITH_SETTER, "Property with setter implementation cannot be abstract")
|
map.put(ABSTRACT_PROPERTY_WITH_SETTER, "Property with setter implementation cannot be abstract")
|
||||||
map.put(PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY, "Private setters are not allowed for abstract properties")
|
map.put(PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY, "Private setters are not allowed for abstract properties")
|
||||||
map.put(PRIVATE_SETTER_FOR_OPEN_PROPERTY, "Private setters are not allowed for open properties")
|
map.put(PRIVATE_SETTER_FOR_OPEN_PROPERTY, "Private setters are not allowed for open properties")
|
||||||
|
map.put(VAL_WITH_SETTER, "A 'val'-property cannot have a setter")
|
||||||
|
|
||||||
// Multi-platform projects
|
// Multi-platform projects
|
||||||
map.put(EXPECTED_DECLARATION_WITH_BODY, "Expected declaration must not have a body")
|
map.put(EXPECTED_DECLARATION_WITH_BODY, "Expected declaration must not have a body")
|
||||||
|
|||||||
+9
-9
@@ -1017,16 +1017,16 @@ class DeclarationsConverter(
|
|||||||
it.containingClassAttr = lookupTag
|
it.containingClassAttr = lookupTag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.setter =
|
// NOTE: We still need the setter even for a val property so we can report errors (e.g., VAL_WITH_SETTER).
|
||||||
if (isVar) {
|
this.setter = convertedAccessors.find { it.isSetter }
|
||||||
convertedAccessors.find { it.isSetter }
|
?: if (isVar) {
|
||||||
?: FirDefaultPropertySetter(
|
FirDefaultPropertySetter(
|
||||||
null, session, FirDeclarationOrigin.Source, returnType, propertyVisibility
|
null, session, FirDeclarationOrigin.Source, returnType, propertyVisibility
|
||||||
).also {
|
).also {
|
||||||
currentDispatchReceiverType()?.lookupTag?.let { lookupTag ->
|
currentDispatchReceiverType()?.lookupTag?.let { lookupTag ->
|
||||||
it.containingClassAttr = lookupTag
|
it.containingClassAttr = lookupTag
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else null
|
} else null
|
||||||
|
|
||||||
// Upward propagation of `inline` and `external` modifiers (from accessors to property)
|
// Upward propagation of `inline` and `external` modifiers (from accessors to property)
|
||||||
|
|||||||
+66
-57
@@ -334,7 +334,7 @@ class RawFirBuilder(
|
|||||||
property: KtProperty,
|
property: KtProperty,
|
||||||
propertyTypeRef: FirTypeRef,
|
propertyTypeRef: FirTypeRef,
|
||||||
isGetter: Boolean,
|
isGetter: Boolean,
|
||||||
): FirPropertyAccessor {
|
): FirPropertyAccessor? {
|
||||||
val accessorVisibility =
|
val accessorVisibility =
|
||||||
if (this?.visibility != null && this.visibility != Visibilities.Unknown) this.visibility else property.visibility
|
if (this?.visibility != null && this.visibility != Visibilities.Unknown) this.visibility else property.visibility
|
||||||
// Downward propagation of `inline` and `external` modifiers (from property to its accessors)
|
// Downward propagation of `inline` and `external` modifiers (from property to its accessors)
|
||||||
@@ -345,67 +345,78 @@ class RawFirBuilder(
|
|||||||
isExternal = property.hasModifier(EXTERNAL_KEYWORD) ||
|
isExternal = property.hasModifier(EXTERNAL_KEYWORD) ||
|
||||||
this@toFirPropertyAccessor?.hasModifier(EXTERNAL_KEYWORD) == true
|
this@toFirPropertyAccessor?.hasModifier(EXTERNAL_KEYWORD) == true
|
||||||
}
|
}
|
||||||
if (this == null || !hasBody()) {
|
return when {
|
||||||
val propertySource =
|
this != null && hasBody() -> {
|
||||||
this?.toFirSourceElement() ?: property.toFirPsiSourceElement(FirFakeSourceElementKind.DefaultAccessor)
|
// Property has a non-default getter or setter.
|
||||||
return FirDefaultPropertyAccessor
|
// NOTE: We still need the setter even for a val property so we can report errors (e.g., VAL_WITH_SETTER).
|
||||||
.createGetterOrSetter(
|
val source = this.toFirSourceElement()
|
||||||
propertySource,
|
val accessorTarget = FirFunctionTarget(labelName = null, isLambda = false)
|
||||||
baseSession,
|
buildPropertyAccessor {
|
||||||
FirDeclarationOrigin.Source,
|
this.source = source
|
||||||
propertyTypeRef,
|
session = baseSession
|
||||||
accessorVisibility,
|
origin = FirDeclarationOrigin.Source
|
||||||
isGetter
|
returnTypeRef = if (isGetter) {
|
||||||
)
|
returnTypeReference?.convertSafe() ?: propertyTypeRef
|
||||||
.also {
|
} else {
|
||||||
if (this != null) {
|
returnTypeReference.toFirOrUnitType()
|
||||||
it.extractAnnotationsFrom(this)
|
|
||||||
}
|
}
|
||||||
it.status = status
|
this.isGetter = isGetter
|
||||||
|
this.status = status
|
||||||
|
extractAnnotationsTo(this)
|
||||||
|
this@RawFirBuilder.context.firFunctionTargets += accessorTarget
|
||||||
|
extractValueParametersTo(this, propertyTypeRef)
|
||||||
|
if (!isGetter && valueParameters.isEmpty()) {
|
||||||
|
valueParameters += buildDefaultSetterValueParameter {
|
||||||
|
this.source = source.fakeElement(FirFakeSourceElementKind.DefaultAccessor)
|
||||||
|
session = baseSession
|
||||||
|
origin = FirDeclarationOrigin.Source
|
||||||
|
returnTypeRef = propertyTypeRef
|
||||||
|
symbol = FirVariableSymbol(NAME_FOR_DEFAULT_VALUE_PARAMETER)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
symbol = FirPropertyAccessorSymbol()
|
||||||
|
val outerContractDescription = this@toFirPropertyAccessor.obtainContractDescription()
|
||||||
|
val bodyWithContractDescription = this@toFirPropertyAccessor.buildFirBody()
|
||||||
|
this.body = bodyWithContractDescription.first
|
||||||
|
val contractDescription = outerContractDescription ?: bodyWithContractDescription.second
|
||||||
|
contractDescription?.let {
|
||||||
|
this.contractDescription = it
|
||||||
|
}
|
||||||
|
}.also {
|
||||||
currentDispatchReceiverType()?.lookupTag?.let { lookupTag ->
|
currentDispatchReceiverType()?.lookupTag?.let { lookupTag ->
|
||||||
it.containingClassAttr = lookupTag
|
it.containingClassAttr = lookupTag
|
||||||
}
|
}
|
||||||
}
|
accessorTarget.bind(it)
|
||||||
}
|
this@RawFirBuilder.context.firFunctionTargets.removeLast()
|
||||||
val source = this.toFirSourceElement()
|
|
||||||
val accessorTarget = FirFunctionTarget(labelName = null, isLambda = false)
|
|
||||||
return buildPropertyAccessor {
|
|
||||||
this.source = source
|
|
||||||
session = baseSession
|
|
||||||
origin = FirDeclarationOrigin.Source
|
|
||||||
returnTypeRef = if (isGetter) {
|
|
||||||
returnTypeReference?.convertSafe() ?: propertyTypeRef
|
|
||||||
} else {
|
|
||||||
returnTypeReference.toFirOrUnitType()
|
|
||||||
}
|
|
||||||
this.isGetter = isGetter
|
|
||||||
this.status = status
|
|
||||||
extractAnnotationsTo(this)
|
|
||||||
this@RawFirBuilder.context.firFunctionTargets += accessorTarget
|
|
||||||
extractValueParametersTo(this, propertyTypeRef)
|
|
||||||
if (!isGetter && valueParameters.isEmpty()) {
|
|
||||||
valueParameters += buildDefaultSetterValueParameter {
|
|
||||||
this.source = source.fakeElement(FirFakeSourceElementKind.DefaultAccessor)
|
|
||||||
session = baseSession
|
|
||||||
origin = FirDeclarationOrigin.Source
|
|
||||||
returnTypeRef = propertyTypeRef
|
|
||||||
symbol = FirVariableSymbol(NAME_FOR_DEFAULT_VALUE_PARAMETER)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
symbol = FirPropertyAccessorSymbol()
|
isGetter || property.isVar -> {
|
||||||
val outerContractDescription = this@toFirPropertyAccessor.obtainContractDescription()
|
// Default getter for val/var properties, and default setter for var properties.
|
||||||
val bodyWithContractDescription = this@toFirPropertyAccessor.buildFirBody()
|
val propertySource =
|
||||||
this.body = bodyWithContractDescription.first
|
this?.toFirSourceElement() ?: property.toFirPsiSourceElement(FirFakeSourceElementKind.DefaultAccessor)
|
||||||
val contractDescription = outerContractDescription ?: bodyWithContractDescription.second
|
FirDefaultPropertyAccessor
|
||||||
contractDescription?.let {
|
.createGetterOrSetter(
|
||||||
this.contractDescription = it
|
propertySource,
|
||||||
|
baseSession,
|
||||||
|
FirDeclarationOrigin.Source,
|
||||||
|
propertyTypeRef,
|
||||||
|
accessorVisibility,
|
||||||
|
isGetter
|
||||||
|
)
|
||||||
|
.also {
|
||||||
|
if (this != null) {
|
||||||
|
it.extractAnnotationsFrom(this)
|
||||||
|
}
|
||||||
|
it.status = status
|
||||||
|
currentDispatchReceiverType()?.lookupTag?.let { lookupTag ->
|
||||||
|
it.containingClassAttr = lookupTag
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}.also {
|
else -> {
|
||||||
currentDispatchReceiverType()?.lookupTag?.let { lookupTag ->
|
// No default setter for val properties.
|
||||||
it.containingClassAttr = lookupTag
|
null
|
||||||
}
|
}
|
||||||
accessorTarget.bind(it)
|
|
||||||
this@RawFirBuilder.context.firFunctionTargets.removeLast()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1268,9 +1279,7 @@ class RawFirBuilder(
|
|||||||
} else null
|
} else null
|
||||||
|
|
||||||
getter = this@toFirProperty.getter.toFirPropertyAccessor(this@toFirProperty, propertyType, isGetter = true)
|
getter = this@toFirProperty.getter.toFirPropertyAccessor(this@toFirProperty, propertyType, isGetter = true)
|
||||||
setter = if (isVar) {
|
setter = this@toFirProperty.setter.toFirPropertyAccessor(this@toFirProperty, propertyType, isGetter = false)
|
||||||
this@toFirProperty.setter.toFirPropertyAccessor(this@toFirProperty, propertyType, isGetter = false)
|
|
||||||
} else null
|
|
||||||
|
|
||||||
// Upward propagation of `inline` and `external` modifiers (from accessors to property)
|
// Upward propagation of `inline` and `external` modifiers (from accessors to property)
|
||||||
// Note that, depending on `var` or `val`, checking setter's modifiers should be careful: for `val`, setter doesn't
|
// Note that, depending on `var` or `val`, checking setter's modifiers should be careful: for `val`, setter doesn't
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@ var x : Int = 1 + x
|
|||||||
|
|
||||||
val xx : Int = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>1 + x<!>
|
val xx : Int = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>1 + x<!>
|
||||||
get() : Int = 1
|
get() : Int = 1
|
||||||
set(value : Long) {}
|
<!VAL_WITH_SETTER!>set(value : Long) {}<!>
|
||||||
|
|
||||||
val p : Int = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>1<!>
|
val p : Int = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>1<!>
|
||||||
get() = 1
|
get() = 1
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_COMPARISON
|
||||||
val a: Int = 1
|
val a: Int = 1
|
||||||
get() {
|
get() {
|
||||||
return field
|
return field
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ class MainKtQuickFixRegistrar : KtQuickFixRegistrar() {
|
|||||||
registerPsiQuickFixes(KtFirDiagnostic.VarOverriddenByVal::class, ChangeVariableMutabilityFix.VAR_OVERRIDDEN_BY_VAL_FACTORY)
|
registerPsiQuickFixes(KtFirDiagnostic.VarOverriddenByVal::class, ChangeVariableMutabilityFix.VAR_OVERRIDDEN_BY_VAL_FACTORY)
|
||||||
registerPsiQuickFixes(KtFirDiagnostic.VarAnnotationParameter::class, ChangeVariableMutabilityFix.VAR_ANNOTATION_PARAMETER_FACTORY)
|
registerPsiQuickFixes(KtFirDiagnostic.VarAnnotationParameter::class, ChangeVariableMutabilityFix.VAR_ANNOTATION_PARAMETER_FACTORY)
|
||||||
registerPsiQuickFixes(KtFirDiagnostic.InapplicableLateinitModifier::class, ChangeVariableMutabilityFix.LATEINIT_VAL_FACTORY)
|
registerPsiQuickFixes(KtFirDiagnostic.InapplicableLateinitModifier::class, ChangeVariableMutabilityFix.LATEINIT_VAL_FACTORY)
|
||||||
|
registerPsiQuickFixes(KtFirDiagnostic.ValWithSetter::class, ChangeVariableMutabilityFix.VAL_WITH_SETTER_FACTORY)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val list: KtQuickFixesList = KtQuickFixesList.createCombined(
|
override val list: KtQuickFixesList = KtQuickFixesList.createCombined(
|
||||||
|
|||||||
+6
@@ -944,6 +944,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
add(FirErrors.VAL_WITH_SETTER) { firDiagnostic ->
|
||||||
|
ValWithSetterImpl(
|
||||||
|
firDiagnostic as FirPsiDiagnostic<*>,
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
}
|
||||||
add(FirErrors.EXPECTED_DECLARATION_WITH_BODY) { firDiagnostic ->
|
add(FirErrors.EXPECTED_DECLARATION_WITH_BODY) { firDiagnostic ->
|
||||||
ExpectedDeclarationWithBodyImpl(
|
ExpectedDeclarationWithBodyImpl(
|
||||||
firDiagnostic as FirPsiDiagnostic<*>,
|
firDiagnostic as FirPsiDiagnostic<*>,
|
||||||
|
|||||||
+4
@@ -666,6 +666,10 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
override val diagnosticClass get() = ExpectedPrivateDeclaration::class
|
override val diagnosticClass get() = ExpectedPrivateDeclaration::class
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class ValWithSetter : KtFirDiagnostic<KtPropertyAccessor>() {
|
||||||
|
override val diagnosticClass get() = ValWithSetter::class
|
||||||
|
}
|
||||||
|
|
||||||
abstract class ExpectedDeclarationWithBody : KtFirDiagnostic<KtDeclaration>() {
|
abstract class ExpectedDeclarationWithBody : KtFirDiagnostic<KtDeclaration>() {
|
||||||
override val diagnosticClass get() = ExpectedDeclarationWithBody::class
|
override val diagnosticClass get() = ExpectedDeclarationWithBody::class
|
||||||
}
|
}
|
||||||
|
|||||||
+7
@@ -1075,6 +1075,13 @@ internal class ExpectedPrivateDeclarationImpl(
|
|||||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class ValWithSetterImpl(
|
||||||
|
firDiagnostic: FirPsiDiagnostic<*>,
|
||||||
|
override val token: ValidityToken,
|
||||||
|
) : KtFirDiagnostic.ValWithSetter(), KtAbstractFirDiagnostic<KtPropertyAccessor> {
|
||||||
|
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||||
|
}
|
||||||
|
|
||||||
internal class ExpectedDeclarationWithBodyImpl(
|
internal class ExpectedDeclarationWithBodyImpl(
|
||||||
firDiagnostic: FirPsiDiagnostic<*>,
|
firDiagnostic: FirPsiDiagnostic<*>,
|
||||||
override val token: ValidityToken,
|
override val token: ValidityToken,
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ class A() {
|
|||||||
val a: Int = 0
|
val a: Int = 0
|
||||||
<caret>set(v: Int) {}
|
<caret>set(v: Int) {}
|
||||||
}
|
}
|
||||||
|
/* FIR_COMPARISON */
|
||||||
@@ -3,3 +3,4 @@ class A() {
|
|||||||
var a: Int = 0
|
var a: Int = 0
|
||||||
set(v: Int) {}
|
set(v: Int) {}
|
||||||
}
|
}
|
||||||
|
/* FIR_COMPARISON */
|
||||||
Reference in New Issue
Block a user