map.get() with not-null assertion: add quick-fixes
#KT-30010 Fixed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
84a3239cdf
commit
d67c793a9b
@@ -1,5 +1,5 @@
|
|||||||
<html>
|
<html>
|
||||||
<body>
|
<body>
|
||||||
This inspection reports <b>map.get()!!</b> that can be replaced with <b>map.getValue()</b>.
|
This inspection reports <b>map.get()!!</b> that can be replaced with <b>map.getValue()</b>, <b>map.getOrElse()</b>, etc.
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
+36
-1
@@ -10,6 +10,7 @@ import com.intellij.codeInspection.ProblemDescriptor
|
|||||||
import com.intellij.codeInspection.ProblemHighlightType
|
import com.intellij.codeInspection.ProblemHighlightType
|
||||||
import com.intellij.codeInspection.ProblemsHolder
|
import com.intellij.codeInspection.ProblemsHolder
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.PsiDocumentManager
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
|
||||||
import org.jetbrains.kotlin.idea.core.replaced
|
import org.jetbrains.kotlin.idea.core.replaced
|
||||||
import org.jetbrains.kotlin.idea.intentions.callExpression
|
import org.jetbrains.kotlin.idea.intentions.callExpression
|
||||||
@@ -17,6 +18,7 @@ import org.jetbrains.kotlin.lexer.KtTokens
|
|||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
|
|
||||||
class MapGetWithNotNullAssertionOperatorInspection : AbstractKotlinInspection() {
|
class MapGetWithNotNullAssertionOperatorInspection : AbstractKotlinInspection() {
|
||||||
@@ -29,7 +31,9 @@ class MapGetWithNotNullAssertionOperatorInspection : AbstractKotlinInspection()
|
|||||||
expression.operationReference,
|
expression.operationReference,
|
||||||
"map.get() with not-null assertion operator (!!)",
|
"map.get() with not-null assertion operator (!!)",
|
||||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
|
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
|
||||||
ReplaceWithGetValueCallFix()
|
ReplaceWithGetValueCallFix(),
|
||||||
|
ReplaceWithGetOrElseFix(),
|
||||||
|
ReplaceWithElvisErrorFix()
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -43,6 +47,37 @@ class MapGetWithNotNullAssertionOperatorInspection : AbstractKotlinInspection()
|
|||||||
replaced.findExistingEditor()?.caretModel?.moveToOffset(replaced.endOffset)
|
replaced.findExistingEditor()?.caretModel?.moveToOffset(replaced.endOffset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ReplaceWithGetOrElseFix : LocalQuickFix {
|
||||||
|
override fun getName() = "Replace with 'getOrElse' call"
|
||||||
|
override fun getFamilyName() = name
|
||||||
|
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||||
|
val expression = descriptor.psiElement.parent as? KtPostfixExpression ?: return
|
||||||
|
val (reference, index) = expression.getReplacementData() ?: return
|
||||||
|
val replaced = expression.replaced(KtPsiFactory(expression).createExpressionByPattern("$0.getOrElse($1){}", reference, index))
|
||||||
|
|
||||||
|
val editor = replaced.findExistingEditor() ?: return
|
||||||
|
val offset = (replaced as KtQualifiedExpression).callExpression?.lambdaArguments?.firstOrNull()?.startOffset ?: return
|
||||||
|
val document = editor.document
|
||||||
|
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(document)
|
||||||
|
document.insertString(offset + 1, " ")
|
||||||
|
editor.caretModel.moveToOffset(offset + 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ReplaceWithElvisErrorFix : LocalQuickFix {
|
||||||
|
override fun getName() = "Replace with '?: error(\"\")'"
|
||||||
|
override fun getFamilyName() = name
|
||||||
|
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||||
|
val expression = descriptor.psiElement.parent as? KtPostfixExpression ?: return
|
||||||
|
val (reference, index) = expression.getReplacementData() ?: return
|
||||||
|
val replaced = expression.replace(KtPsiFactory(expression).createExpressionByPattern("$0[$1] ?: error(\"\")", reference, index))
|
||||||
|
|
||||||
|
val editor = replaced.findExistingEditor() ?: return
|
||||||
|
val offset = (replaced as? KtBinaryExpression)?.right?.endOffset ?: return
|
||||||
|
editor.caretModel.moveToOffset(offset - 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KtPostfixExpression.getReplacementData(): Pair<KtExpression, KtExpression>? {
|
private fun KtPostfixExpression.getReplacementData(): Pair<KtExpression, KtExpression>? {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIX: Replace with 'getValue' call
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
fun test(map: Map<Int, String>) {
|
fun test(map: Map<Int, String>) {
|
||||||
val s = map.get(1)!!<caret>
|
val s = map.get(1)!!<caret>
|
||||||
|
|||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIX: Replace with 'getValue' call
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
fun test(map: Map<Int, String>) {
|
fun test(map: Map<Int, String>) {
|
||||||
val s = map.getValue(1)<caret>
|
val s = map.getValue(1)<caret>
|
||||||
|
|||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIX: Replace with 'getValue' call
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
fun test(map: Map<Int, String>) {
|
fun test(map: Map<Int, String>) {
|
||||||
val s = map[1]<caret>!!
|
val s = map[1]<caret>!!
|
||||||
|
|||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIX: Replace with 'getValue' call
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
fun test(map: Map<Int, String>) {
|
fun test(map: Map<Int, String>) {
|
||||||
val s = map.getValue(1)<caret>
|
val s = map.getValue(1)<caret>
|
||||||
|
|||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
// FIX: Replace with '?: error("")'
|
||||||
|
// WITH_RUNTIME
|
||||||
|
fun test(map: Map<Int, String>) {
|
||||||
|
val s = map[1]<caret>!!
|
||||||
|
}
|
||||||
Vendored
+5
@@ -0,0 +1,5 @@
|
|||||||
|
// FIX: Replace with '?: error("")'
|
||||||
|
// WITH_RUNTIME
|
||||||
|
fun test(map: Map<Int, String>) {
|
||||||
|
val s = map[1] ?: error("<caret>")
|
||||||
|
}
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
// FIX: Replace with 'getOrElse' call
|
||||||
|
// DISABLE-ERRORS
|
||||||
|
// WITH_RUNTIME
|
||||||
|
fun test(map: Map<Int, String>) {
|
||||||
|
val s = map[1]<caret>!!
|
||||||
|
}
|
||||||
Vendored
+6
@@ -0,0 +1,6 @@
|
|||||||
|
// FIX: Replace with 'getOrElse' call
|
||||||
|
// DISABLE-ERRORS
|
||||||
|
// WITH_RUNTIME
|
||||||
|
fun test(map: Map<Int, String>) {
|
||||||
|
val s = map.getOrElse(1) { <caret> }
|
||||||
|
}
|
||||||
+10
@@ -3840,6 +3840,16 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
|
|||||||
public void testNoNotNullAssersion() throws Exception {
|
public void testNoNotNullAssersion() throws Exception {
|
||||||
runTest("idea/testData/inspectionsLocal/mapGetWithNotNullAssertionOperator/noNotNullAssersion.kt");
|
runTest("idea/testData/inspectionsLocal/mapGetWithNotNullAssertionOperator/noNotNullAssersion.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("replaceWithElvisError.kt")
|
||||||
|
public void testReplaceWithElvisError() throws Exception {
|
||||||
|
runTest("idea/testData/inspectionsLocal/mapGetWithNotNullAssertionOperator/replaceWithElvisError.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("replaceWithGetOrElse.kt")
|
||||||
|
public void testReplaceWithGetOrElse() throws Exception {
|
||||||
|
runTest("idea/testData/inspectionsLocal/mapGetWithNotNullAssertionOperator/replaceWithGetOrElse.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/inspectionsLocal/mayBeConstant")
|
@TestMetadata("idea/testData/inspectionsLocal/mayBeConstant")
|
||||||
|
|||||||
Reference in New Issue
Block a user