Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add UnnecessaryBackticks rule (#4764)
- Loading branch information
1 parent
3c9010c
commit f44947c
Showing
4 changed files
with
204 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
62 changes: 62 additions & 0 deletions
62
...les-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/UnnecessaryBackticks.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package io.gitlab.arturbosch.detekt.rules.style | ||
|
||
import io.gitlab.arturbosch.detekt.api.CodeSmell | ||
import io.gitlab.arturbosch.detekt.api.Config | ||
import io.gitlab.arturbosch.detekt.api.Debt | ||
import io.gitlab.arturbosch.detekt.api.Entity | ||
import io.gitlab.arturbosch.detekt.api.Issue | ||
import io.gitlab.arturbosch.detekt.api.Rule | ||
import io.gitlab.arturbosch.detekt.api.Severity | ||
import org.jetbrains.kotlin.com.intellij.psi.PsiElement | ||
import org.jetbrains.kotlin.lexer.KtTokens | ||
import org.jetbrains.kotlin.psi.KtElement | ||
import org.jetbrains.kotlin.psi.KtSimpleNameStringTemplateEntry | ||
import org.jetbrains.kotlin.psi.psiUtil.allChildren | ||
import org.jetbrains.kotlin.psi.psiUtil.canPlaceAfterSimpleNameEntry | ||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType | ||
import org.jetbrains.kotlin.psi.psiUtil.isIdentifier | ||
|
||
/** | ||
* This rule reports unnecessary backticks. | ||
* | ||
* <noncompliant> | ||
* class `HelloWorld` | ||
* </noncompliant> | ||
* | ||
* <compliant> | ||
* class HelloWorld | ||
* </compliant> | ||
*/ | ||
class UnnecessaryBackticks(config: Config = Config.empty) : Rule(config) { | ||
override val issue: Issue = Issue( | ||
javaClass.simpleName, | ||
Severity.Style, | ||
"Backticks are unnecessary.", | ||
Debt.FIVE_MINS | ||
) | ||
|
||
override fun visitKtElement(element: KtElement) { | ||
element.allChildren | ||
.filter { it.node.elementType == KtTokens.IDENTIFIER && it.hasUnnecessaryBackticks() } | ||
.forEach { report(CodeSmell(issue, Entity.from(it), "Backticks are unnecessary.")) } | ||
super.visitKtElement(element) | ||
} | ||
|
||
@Suppress("ReturnCount") | ||
private fun PsiElement.hasUnnecessaryBackticks(): Boolean { | ||
val text = this.text | ||
if (!text.startsWith("`") || !text.endsWith("`")) return false | ||
|
||
val unquoted = text.drop(1).dropLast(1) | ||
if (!unquoted.isIdentifier() || unquoted.isKeyword()) return false | ||
|
||
val stringTemplateEntry = getStrictParentOfType<KtSimpleNameStringTemplateEntry>() | ||
return stringTemplateEntry == null || canPlaceAfterSimpleNameEntry(stringTemplateEntry.nextSibling) | ||
} | ||
|
||
private fun String.isKeyword() = this in KEYWORDS || this.all { it == '_' } | ||
|
||
companion object { | ||
private val KEYWORDS = KtTokens.KEYWORDS.types.map { it.toString() } | ||
} | ||
} |
139 changes: 139 additions & 0 deletions
139
...style/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/style/UnnecessaryBackticksSpec.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
package io.gitlab.arturbosch.detekt.rules.style | ||
|
||
import io.gitlab.arturbosch.detekt.api.Config | ||
import io.gitlab.arturbosch.detekt.test.assertThat | ||
import io.gitlab.arturbosch.detekt.test.compileAndLint | ||
import io.gitlab.arturbosch.detekt.test.lint | ||
import org.junit.jupiter.api.Nested | ||
import org.junit.jupiter.api.Test | ||
|
||
class UnnecessaryBackticksSpec { | ||
val subject = UnnecessaryBackticks(Config.empty) | ||
|
||
@Nested | ||
inner class `Reports UnnecessaryInnerClass Rule` { | ||
@Test | ||
fun `class`() { | ||
val code = """ | ||
class `Foo` { | ||
val x: `Foo` = `Foo`() | ||
val y = ::`Foo` | ||
} | ||
""".trimIndent() | ||
assertThat(subject.compileAndLint(code)).hasSize(4) | ||
} | ||
|
||
@Test | ||
fun function() { | ||
val code = """ | ||
fun `foo`() = 1 | ||
val x = `foo`() | ||
val y = ::`foo` | ||
""".trimIndent() | ||
assertThat(subject.compileAndLint(code)).hasSize(3) | ||
} | ||
|
||
@Test | ||
fun property() { | ||
val code = """ | ||
val `foo` = "" | ||
val x = `foo` | ||
val y = ::`foo` | ||
val z = `foo`.length | ||
""".trimIndent() | ||
assertThat(subject.compileAndLint(code)).hasSize(4) | ||
} | ||
|
||
@Test | ||
fun import() { | ||
val code = """ | ||
import kotlin.`let` | ||
""".trimIndent() | ||
assertThat(subject.compileAndLint(code)).hasSize(1) | ||
} | ||
|
||
@Test | ||
fun `in string template`() { | ||
val code = """ | ||
val foo = "" | ||
val x = "${'$'}`foo`" | ||
val y = "${'$'}`foo` bar" | ||
val z = "${'$'}{`foo`}bar" | ||
""".trimIndent() | ||
assertThat(subject.compileAndLint(code)).hasSize(3) | ||
} | ||
} | ||
|
||
@Nested | ||
inner class `Does not report UnnecessaryInnerClass Rule` { | ||
@Test | ||
fun `class with spaces`() { | ||
val code = """ | ||
class `Foo Bar` | ||
val x: `Foo Bar` = `Foo Bar`() | ||
val y = ::`Foo Bar` | ||
""".trimIndent() | ||
assertThat(subject.compileAndLint(code)).hasSize(0) | ||
} | ||
|
||
@Test | ||
fun `function with spaces`() { | ||
val code = """ | ||
fun `foo bar`() = 1 | ||
val x = `foo bar`() | ||
val y = ::`foo bar` | ||
""".trimIndent() | ||
assertThat(subject.compileAndLint(code)).hasSize(0) | ||
} | ||
|
||
@Test | ||
fun `property with spaces`() { | ||
val code = """ | ||
val `foo bar` = "" | ||
val x = `foo bar` | ||
val y = ::`foo bar` | ||
val z = `foo bar`.length | ||
""".trimIndent() | ||
assertThat(subject.compileAndLint(code)).hasSize(0) | ||
} | ||
|
||
@Test | ||
fun keyword() { | ||
val code = """ | ||
val `is` = 1 | ||
val `fun` = 2 | ||
""".trimIndent() | ||
assertThat(subject.compileAndLint(code)).isEmpty() | ||
} | ||
|
||
@Test | ||
fun underscore() { | ||
val code = """ | ||
val `_` = 1 | ||
val `__` = 2 | ||
""".trimIndent() | ||
assertThat(subject.compileAndLint(code)).isEmpty() | ||
} | ||
|
||
@Test | ||
fun import() { | ||
val code = """ | ||
package test | ||
import test.`Foo Bar` | ||
class `Foo Bar` | ||
""".trimIndent() | ||
assertThat(subject.lint(code)).hasSize(0) | ||
} | ||
|
||
@Test | ||
fun `in string template`() { | ||
val code = """ | ||
val foo = "" | ||
val x = "${'$'}`foo`bar" | ||
val `bar baz` = "" | ||
val y = "${'$'}`bar baz`" | ||
""".trimIndent() | ||
assertThat(subject.compileAndLint(code)).hasSize(0) | ||
} | ||
} | ||
} |
f44947c
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
detekt – ./
detekt.vercel.app
detekt-detekt.vercel.app
detekt-git-main-detekt.vercel.app