Remove redundant backticks: do not report if variable inside the string and isn't followed by space

#KT-35051 Fixed
This commit is contained in:
Toshiaki Kameyama
2019-11-23 14:33:49 +09:00
committed by Yan Zhulanow
parent ad3ea9a36a
commit 74ee68e57b
7 changed files with 47 additions and 7 deletions
@@ -19,6 +19,7 @@ import com.intellij.codeInspection.LocalQuickFix
import com.intellij.codeInspection.ProblemDescriptor 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.lang.ASTNode
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementVisitor import com.intellij.psi.PsiElementVisitor
@@ -26,9 +27,9 @@ import com.intellij.psi.impl.source.tree.SharedImplUtil
import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.core.unquote import org.jetbrains.kotlin.idea.core.unquote
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.KtPsiFactory import org.jetbrains.kotlin.psi.psiUtil.canPlaceAfterSimpleNameEntry
import org.jetbrains.kotlin.psi.KtVisitorVoid import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.isIdentifier import org.jetbrains.kotlin.psi.psiUtil.isIdentifier
class RemoveRedundantBackticksInspection : AbstractKotlinInspection() { class RemoveRedundantBackticksInspection : AbstractKotlinInspection() {
@@ -37,7 +38,7 @@ class RemoveRedundantBackticksInspection : AbstractKotlinInspection() {
override fun visitKtElement(element: KtElement) { override fun visitKtElement(element: KtElement) {
super.visitKtElement(element) super.visitKtElement(element)
SharedImplUtil.getChildrenOfType(element.node, KtTokens.IDENTIFIER).forEach { SharedImplUtil.getChildrenOfType(element.node, KtTokens.IDENTIFIER).forEach {
if (isRedundantBackticks(it.text)) { if (isRedundantBackticks(it)) {
registerProblem(holder, it.psi) registerProblem(holder, it.psi)
} }
} }
@@ -61,7 +62,7 @@ class RemoveRedundantBackticksQuickFix : LocalQuickFix {
override fun applyFix(project: Project, descriptor: ProblemDescriptor) { override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val element = descriptor.psiElement val element = descriptor.psiElement
if (!isRedundantBackticks(element.text)) return if (!isRedundantBackticks(element.node)) return
val factory = KtPsiFactory(project) val factory = KtPsiFactory(project)
element.replace(factory.createIdentifier(element.text.unquote())) element.replace(factory.createIdentifier(element.text.unquote()))
} }
@@ -70,8 +71,11 @@ class RemoveRedundantBackticksQuickFix : LocalQuickFix {
private fun isKeyword(text: String): Boolean = private fun isKeyword(text: String): Boolean =
text == "yield" || text.all { it == '_' } || (KtTokens.KEYWORDS.types + KtTokens.SOFT_KEYWORDS.types).any { it.toString() == text } text == "yield" || text.all { it == '_' } || (KtTokens.KEYWORDS.types + KtTokens.SOFT_KEYWORDS.types).any { it.toString() == text }
private fun isRedundantBackticks(identifier: String): Boolean { private fun isRedundantBackticks(node: ASTNode): Boolean {
val identifier = node.text
if (!(identifier.startsWith("`") && identifier.endsWith("`"))) return false if (!(identifier.startsWith("`") && identifier.endsWith("`"))) return false
val unquotedText = identifier.unquote() val unquotedText = identifier.unquote()
return unquotedText.isIdentifier() && !isKeyword(unquotedText) if (!unquotedText.isIdentifier() || isKeyword(unquotedText)) return false
val simpleNameStringTemplateEntry = node.psi.getStrictParentOfType<KtSimpleNameStringTemplateEntry>()
return simpleNameStringTemplateEntry == null || canPlaceAfterSimpleNameEntry(simpleNameStringTemplateEntry.nextSibling)
} }
@@ -0,0 +1,5 @@
// PROBLEM: none
fun main() {
val name = "Kotlin"
val test = "$<caret>`name`test"
}
@@ -0,0 +1,4 @@
fun main() {
val name = "Kotlin"
val test = "$<caret>`name` test"
}
@@ -0,0 +1,4 @@
fun main() {
val name = "Kotlin"
val test = "$name test"
}
@@ -0,0 +1,4 @@
fun main() {
val name = "Kotlin"
val test = "${<caret>`name`}test"
}
@@ -0,0 +1,4 @@
fun main() {
val name = "Kotlin"
val test = "${name}test"
}
@@ -9545,6 +9545,21 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
runTest("idea/testData/inspectionsLocal/removeRedundantBackticks/identifierContainingSpaces.kt"); runTest("idea/testData/inspectionsLocal/removeRedundantBackticks/identifierContainingSpaces.kt");
} }
@TestMetadata("inStringTemplate.kt")
public void testInStringTemplate() throws Exception {
runTest("idea/testData/inspectionsLocal/removeRedundantBackticks/inStringTemplate.kt");
}
@TestMetadata("inStringTemplate2.kt")
public void testInStringTemplate2() throws Exception {
runTest("idea/testData/inspectionsLocal/removeRedundantBackticks/inStringTemplate2.kt");
}
@TestMetadata("inStringTemplate3.kt")
public void testInStringTemplate3() throws Exception {
runTest("idea/testData/inspectionsLocal/removeRedundantBackticks/inStringTemplate3.kt");
}
@TestMetadata("keyword.kt") @TestMetadata("keyword.kt")
public void testKeyword() throws Exception { public void testKeyword() throws Exception {
runTest("idea/testData/inspectionsLocal/removeRedundantBackticks/keyword.kt"); runTest("idea/testData/inspectionsLocal/removeRedundantBackticks/keyword.kt");