Check explicit type specification in "Might be const" inspection

So #KT-23303 Fixed
This commit is contained in:
Toshiaki Kameyama
2018-03-23 19:53:47 +03:00
committed by Mikhail Glukhikh
parent 9539212180
commit 94c5344fd1
10 changed files with 50 additions and 6 deletions
@@ -9,6 +9,7 @@ import com.intellij.codeInspection.IntentionWrapper
import com.intellij.codeInspection.ProblemHighlightType import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.codeInspection.ProblemsHolder import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.PsiElementVisitor import com.intellij.psi.PsiElementVisitor
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.VariableDescriptor import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.inspections.MayBeConstantInspection.Status.* import org.jetbrains.kotlin.idea.inspections.MayBeConstantInspection.Status.*
@@ -44,10 +45,10 @@ class MayBeConstantInspection : AbstractKotlinInspection() {
MIGHT_BE_CONST_ERRONEOUS, JVM_FIELD_MIGHT_BE_CONST_ERRONEOUS -> return@propertyVisitor MIGHT_BE_CONST_ERRONEOUS, JVM_FIELD_MIGHT_BE_CONST_ERRONEOUS -> return@propertyVisitor
MIGHT_BE_CONST, JVM_FIELD_MIGHT_BE_CONST -> { MIGHT_BE_CONST, JVM_FIELD_MIGHT_BE_CONST -> {
holder.registerProblem( holder.registerProblem(
property.nameIdentifier ?: property, property.nameIdentifier ?: property,
if (status == JVM_FIELD_MIGHT_BE_CONST) "'const' might be used instead of '@JvmField'" else "Might be 'const'", if (status == JVM_FIELD_MIGHT_BE_CONST) "'const' might be used instead of '@JvmField'" else "Might be 'const'",
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
IntentionWrapper(AddConstModifierFix(property), property.containingFile) IntentionWrapper(AddConstModifierFix(property), property.containingFile)
) )
} }
} }
@@ -57,7 +58,8 @@ class MayBeConstantInspection : AbstractKotlinInspection() {
companion object { companion object {
fun KtProperty.getStatus(): Status { fun KtProperty.getStatus(): Status {
if (isLocal || isVar || getter != null || if (isLocal || isVar || getter != null ||
hasModifier(KtTokens.CONST_KEYWORD) || hasModifier(KtTokens.OVERRIDE_KEYWORD)) { hasModifier(KtTokens.CONST_KEYWORD) || hasModifier(KtTokens.OVERRIDE_KEYWORD)
) {
return NONE return NONE
} }
if (!isTopLevel && containingClassOrObject !is KtObjectDeclaration) return NONE if (!isTopLevel && containingClassOrObject !is KtObjectDeclaration) return NONE
@@ -66,13 +68,15 @@ class MayBeConstantInspection : AbstractKotlinInspection() {
// For some reason constant evaluation does not work for property.analyze() // For some reason constant evaluation does not work for property.analyze()
val context = (initializer ?: this).analyze(BodyResolveMode.PARTIAL) val context = (initializer ?: this).analyze(BodyResolveMode.PARTIAL)
val propertyDescriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, this] as? VariableDescriptor ?: return NONE val propertyDescriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, this] as? VariableDescriptor ?: return NONE
val type = propertyDescriptor.type
if (!KotlinBuiltIns.isPrimitiveType(type) && !KotlinBuiltIns.isString(type)) return NONE
val withJvmField = propertyDescriptor.hasJvmFieldAnnotation() val withJvmField = propertyDescriptor.hasJvmFieldAnnotation()
if (annotationEntries.isNotEmpty() && !withJvmField) return NONE if (annotationEntries.isNotEmpty() && !withJvmField) return NONE
return when { return when {
initializer != null -> { initializer != null -> {
val compileTimeConstant = ConstantExpressionEvaluator.getConstant( val compileTimeConstant = ConstantExpressionEvaluator.getConstant(
initializer, context initializer, context
) ?: return NONE ) ?: return NONE
val erroneousConstant = compileTimeConstant.usesNonConstValAsConstant val erroneousConstant = compileTimeConstant.usesNonConstValAsConstant
compileTimeConstant.toConstantValue(propertyDescriptor.type).takeIf { compileTimeConstant.toConstantValue(propertyDescriptor.type).takeIf {
@@ -0,0 +1 @@
val <caret>foo: Int = 0
@@ -0,0 +1 @@
const val foo: Int = 0
@@ -0,0 +1 @@
val <caret>foo: Boolean = true
@@ -0,0 +1 @@
const val foo: Boolean = true
@@ -0,0 +1 @@
val <caret>foo: String = ""
@@ -0,0 +1 @@
const val foo: String = ""
@@ -0,0 +1,2 @@
// PROBLEM: none
val <caret>foo: Any = ""
@@ -0,0 +1,2 @@
// PROBLEM: none
val <caret>foo: Number = 0
@@ -2358,6 +2358,36 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("ecplicitType.kt")
public void testEcplicitType() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/mayBeConstant/ecplicitType.kt");
doTest(fileName);
}
@TestMetadata("ecplicitType2.kt")
public void testEcplicitType2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/mayBeConstant/ecplicitType2.kt");
doTest(fileName);
}
@TestMetadata("ecplicitType3.kt")
public void testEcplicitType3() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/mayBeConstant/ecplicitType3.kt");
doTest(fileName);
}
@TestMetadata("ecplicitType4.kt")
public void testEcplicitType4() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/mayBeConstant/ecplicitType4.kt");
doTest(fileName);
}
@TestMetadata("ecplicitType5.kt")
public void testEcplicitType5() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/mayBeConstant/ecplicitType5.kt");
doTest(fileName);
}
@TestMetadata("enum.kt") @TestMetadata("enum.kt")
public void testEnum() throws Exception { public void testEnum() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/mayBeConstant/enum.kt"); String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/mayBeConstant/enum.kt");