Do not report 'const' inapplicability on property of error type

#KT-12477 Fixed
This commit is contained in:
Mikhail Zarechenskiy
2017-02-07 20:59:58 +03:00
parent e7ea076093
commit d84c303029
4 changed files with 37 additions and 16 deletions
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2016 JetBrains s.r.o. * Copyright 2010-2017 JetBrains s.r.o.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -37,46 +37,59 @@ object ConstModifierChecker : SimpleDeclarationChecker {
val constModifierPsiElement = declaration.modifierList!!.getModifier(KtTokens.CONST_KEYWORD)!! val constModifierPsiElement = declaration.modifierList!!.getModifier(KtTokens.CONST_KEYWORD)!!
val diagnostic = checkCanBeConst(declaration, constModifierPsiElement, descriptor) val diagnostic = checkCanBeConst(declaration, constModifierPsiElement, descriptor).diagnostic
if (diagnostic != null) { if (diagnostic != null) {
diagnosticHolder.report(diagnostic) diagnosticHolder.report(diagnostic)
} }
} }
fun checkCanBeConst(declaration: KtDeclaration, fun canBeConst(declaration: KtDeclaration, constModifierPsiElement: PsiElement, descriptor: VariableDescriptor): Boolean =
checkCanBeConst(declaration, constModifierPsiElement, descriptor).canBeConst
private fun checkCanBeConst(declaration: KtDeclaration,
constModifierPsiElement: PsiElement, constModifierPsiElement: PsiElement,
descriptor: VariableDescriptor): Diagnostic? { descriptor: VariableDescriptor): ConstApplicability {
if (descriptor.isVar) { if (descriptor.isVar) {
return Errors.WRONG_MODIFIER_TARGET.on(constModifierPsiElement, KtTokens.CONST_KEYWORD, "vars") return Errors.WRONG_MODIFIER_TARGET.on(constModifierPsiElement, KtTokens.CONST_KEYWORD, "vars").nonApplicable()
} }
val containingDeclaration = descriptor.containingDeclaration val containingDeclaration = descriptor.containingDeclaration
if (containingDeclaration is ClassDescriptor && containingDeclaration.kind != ClassKind.OBJECT) { if (containingDeclaration is ClassDescriptor && containingDeclaration.kind != ClassKind.OBJECT) {
return Errors.CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT.on(constModifierPsiElement) return Errors.CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT.on(constModifierPsiElement).nonApplicable()
} }
if (declaration !is KtProperty || descriptor !is PropertyDescriptor) return null if (declaration !is KtProperty || descriptor !is PropertyDescriptor) return ConstApplicability.NonApplicable()
if (declaration.hasDelegate()) { if (declaration.hasDelegate()) {
return Errors.CONST_VAL_WITH_DELEGATE.on(declaration.delegate!!) return Errors.CONST_VAL_WITH_DELEGATE.on(declaration.delegate!!).nonApplicable()
} }
if (descriptor is PropertyDescriptor && !descriptor.getter!!.isDefault) { if (descriptor is PropertyDescriptor && !descriptor.getter!!.isDefault) {
return Errors.CONST_VAL_WITH_GETTER.on(declaration.getter!!) return Errors.CONST_VAL_WITH_GETTER.on(declaration.getter!!).nonApplicable()
} }
if (descriptor.type.isError) return ConstApplicability.NonApplicable()
// Report errors about const initializer only on property of resolved types
if (!descriptor.type.canBeUsedForConstVal()) { if (!descriptor.type.canBeUsedForConstVal()) {
return Errors.TYPE_CANT_BE_USED_FOR_CONST_VAL.on(constModifierPsiElement, descriptor.type) return Errors.TYPE_CANT_BE_USED_FOR_CONST_VAL.on(constModifierPsiElement, descriptor.type).nonApplicable()
} }
if (declaration.initializer == null) { if (declaration.initializer == null) {
return Errors.CONST_VAL_WITHOUT_INITIALIZER.on(constModifierPsiElement) return Errors.CONST_VAL_WITHOUT_INITIALIZER.on(constModifierPsiElement).nonApplicable()
} }
if (descriptor.compileTimeInitializer == null) { if (descriptor.compileTimeInitializer == null) {
return Errors.CONST_VAL_WITH_NON_CONST_INITIALIZER.on(declaration.initializer!!) return Errors.CONST_VAL_WITH_NON_CONST_INITIALIZER.on(declaration.initializer!!).nonApplicable()
} }
return null return ConstApplicability.Applicable
} }
} }
sealed class ConstApplicability(val canBeConst: Boolean, val diagnostic: Diagnostic?) {
object Applicable : ConstApplicability(true, null)
class NonApplicable(diagnostic: Diagnostic? = null) : ConstApplicability(false, diagnostic)
}
private fun Diagnostic.nonApplicable() = ConstApplicability.NonApplicable(this)
@@ -10,3 +10,8 @@ enum class MyEnum { A }
<!TYPE_CANT_BE_USED_FOR_CONST_VAL!>const<!> val enumConst: MyEnum = MyEnum.A <!TYPE_CANT_BE_USED_FOR_CONST_VAL!>const<!> val enumConst: MyEnum = MyEnum.A
<!TYPE_CANT_BE_USED_FOR_CONST_VAL!>const<!> val arrayConst: Array<String> = arrayOf("1") <!TYPE_CANT_BE_USED_FOR_CONST_VAL!>const<!> val arrayConst: Array<String> = arrayOf("1")
<!TYPE_CANT_BE_USED_FOR_CONST_VAL!>const<!> val intArrayConst: IntArray = intArrayOf() <!TYPE_CANT_BE_USED_FOR_CONST_VAL!>const<!> val intArrayConst: IntArray = intArrayOf()
const val unresolvedConst1 = <!UNRESOLVED_REFERENCE!>Unresolved<!>
<!WRONG_MODIFIER_TARGET!>const<!> var unresolvedConst2 = <!UNRESOLVED_REFERENCE!>Unresolved<!>
const val unresolvedConst3 = <!UNRESOLVED_REFERENCE, PROPERTY_INITIALIZER_NO_BACKING_FIELD!>Unresolved<!>
<!CONST_VAL_WITH_GETTER!>get() = 10<!>
@@ -7,6 +7,9 @@ public const val intArrayConst: kotlin.IntArray
public const val intConst: kotlin.Int = 1 public const val intConst: kotlin.Int = 1
public const val longConst: kotlin.Long = 1.toLong() public const val longConst: kotlin.Long = 1.toLong()
public const val stringConst: kotlin.String = "empty" public const val stringConst: kotlin.String = "empty"
public const val unresolvedConst1: [ERROR : Type for Unresolved]
public const var unresolvedConst2: [ERROR : Type for Unresolved]
public const val unresolvedConst3: [ERROR : Type for Unresolved]
public final enum class MyEnum : kotlin.Enum<MyEnum> { public final enum class MyEnum : kotlin.Enum<MyEnum> {
enum entry A enum entry A
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2015 JetBrains s.r.o. * Copyright 2010-2017 JetBrains s.r.o.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -77,7 +77,7 @@ class AddConstModifierIntention : SelfTargetingIntention<KtProperty>(KtProperty:
return false return false
} }
val propertyDescriptor = element.descriptor as? VariableDescriptor ?: return false val propertyDescriptor = element.descriptor as? VariableDescriptor ?: return false
return ConstModifierChecker.checkCanBeConst(element, element, propertyDescriptor) == null return ConstModifierChecker.canBeConst(element, element, propertyDescriptor)
} }
} }
} }
@@ -89,7 +89,7 @@ object ConstFixFactory : KotlinSingleIntentionActionFactory() {
val bindingContext = expr.analyze(BodyResolveMode.PARTIAL) val bindingContext = expr.analyze(BodyResolveMode.PARTIAL)
val targetDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expr) as? VariableDescriptor ?: return null val targetDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expr) as? VariableDescriptor ?: return null
val declaration = (targetDescriptor.source as? PsiSourceElement)?.psi as? KtProperty ?: return null val declaration = (targetDescriptor.source as? PsiSourceElement)?.psi as? KtProperty ?: return null
if (ConstModifierChecker.checkCanBeConst(declaration, declaration, targetDescriptor) == null) { if (ConstModifierChecker.canBeConst(declaration, declaration, targetDescriptor)) {
return AddConstModifierFix(declaration) return AddConstModifierFix(declaration)
} }
return null return null