Check explicit type specification in "Might be const" inspection
So #KT-23303 Fixed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
9539212180
commit
94c5344fd1
@@ -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
|
||||||
+30
@@ -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");
|
||||||
|
|||||||
Reference in New Issue
Block a user