Skip to content

Commit

Permalink
feature/inline-classes(#698)
Browse files Browse the repository at this point in the history
### What's done:
  * Fixed bugs
  • Loading branch information
aktsay6 committed Jan 19, 2021
1 parent bf7133e commit 0db1a08
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import org.cqfn.diktat.ruleset.rules.calculations.AccurateCalculationsRule
import org.cqfn.diktat.ruleset.rules.classes.AbstractClassesRule
import org.cqfn.diktat.ruleset.rules.classes.CompactInitialization
import org.cqfn.diktat.ruleset.rules.classes.DataClassesRule
import org.cqfn.diktat.ruleset.rules.classes.InlineClassesRule
import org.cqfn.diktat.ruleset.rules.classes.SingleConstructorRule
import org.cqfn.diktat.ruleset.rules.classes.SingleInitRule
import org.cqfn.diktat.ruleset.rules.classes.StatelessClassesRule
Expand All @@ -27,7 +28,6 @@ import org.cqfn.diktat.ruleset.rules.kdoc.KdocMethods

import com.pinterest.ktlint.core.RuleSet
import com.pinterest.ktlint.core.RuleSetProvider
import org.cqfn.diktat.ruleset.rules.classes.InlineClassesRule
import org.jetbrains.kotlin.org.jline.utils.Levenshtein
import org.slf4j.LoggerFactory

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,37 +13,51 @@ import com.pinterest.ktlint.core.ast.ElementType.MODIFIER_LIST
import com.pinterest.ktlint.core.ast.ElementType.PRIVATE_KEYWORD
import com.pinterest.ktlint.core.ast.ElementType.PROTECTED_KEYWORD
import com.pinterest.ktlint.core.ast.ElementType.PUBLIC_KEYWORD
import com.pinterest.ktlint.core.ast.ElementType.SUPER_TYPE_LIST
import com.pinterest.ktlint.core.ast.ElementType.VAR_KEYWORD
import org.cqfn.diktat.ruleset.utils.hasChildOfType
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
import org.jetbrains.kotlin.psi.KtClass

/**
* This rule checks if inline class can be used.
*/
class InlineClassesRule(private val configRule: List<RulesConfig>) : Rule("inline-classes") {
private var isFixMode: Boolean = false
private lateinit var emitWarn: EmitType

override fun visit(
node: ASTNode,
autoCorrect: Boolean,
emit: EmitType
node: ASTNode,
autoCorrect: Boolean,
emit: EmitType
) {
emitWarn = emit
isFixMode = autoCorrect

if (node.elementType == CLASS) {
handleClasses(node)
handleClasses(node.psi as KtClass)
}
}

private fun handleClasses(node: ASTNode) {
if ((node.psi as KtClass).getProperties().size == 1 && !(node.psi as KtClass).hasExplicitPrimaryConstructor()) {
val modList = node.getFirstChildWithType(MODIFIER_LIST)
if (modList == null || modList.getChildren(null).all { it.elementType in goodModifiers }) {
INLINE_CLASS_CAN_BE_USED.warnAndFix(configRule, emitWarn, isFixMode, "class ${(node.psi as KtClass).name}", node.startOffset, node) {
// Fixme: since it's an experimental feature we shouldn't do fixer
}
private fun handleClasses(classPsi: KtClass) {
if (hasValidProperties(classPsi)
&& !classPsi.node.hasChildOfType(SUPER_TYPE_LIST) // Fixme: for now we can't understand whether it extends class or interface
&& classPsi.node.getFirstChildWithType(MODIFIER_LIST)?.getChildren(null)?.all { it.elementType in goodModifiers } != false) {
INLINE_CLASS_CAN_BE_USED.warnAndFix(configRule, emitWarn, isFixMode, "class ${classPsi.name}", classPsi.node.startOffset, classPsi.node) {
// Fixme: since it's an experimental feature we shouldn't do fixer
}
}
}

private fun hasValidProperties(classPsi: KtClass) : Boolean {
if (classPsi.getProperties().size == 1 && !classPsi.hasExplicitPrimaryConstructor()) {
return !classPsi.getProperties().first().isVar
} else if (classPsi.getProperties().isEmpty() && classPsi.hasExplicitPrimaryConstructor()) {
return classPsi.primaryConstructorParameters.size == 1 && !classPsi.primaryConstructorParameters.first().node.hasChildOfType(VAR_KEYWORD)
}
return false
}

companion object {
val goodModifiers = listOf(PUBLIC_KEYWORD, PRIVATE_KEYWORD, FINAL_KEYWORD, PROTECTED_KEYWORD, INTERNAL_KEYWORD)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import org.cqfn.diktat.util.LintTestBase

import com.pinterest.ktlint.core.LintError
import generated.WarningNames
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Tag
import org.junit.jupiter.api.Test

Expand Down Expand Up @@ -61,4 +62,54 @@ class InlineClassesWarnTest : LintTestBase(::InlineClassesRule) {
""".trimMargin()
)
}

@Test
@Tag(WarningNames.INLINE_CLASS_CAN_BE_USED)
fun `should trigger on class with val prop in constructor`() {
lintMethod(
"""
|class Some(val anything: Int) {
|
|}
""".trimMargin(),
LintError(1, 1, ruleId, "${INLINE_CLASS_CAN_BE_USED.warnText()} class Some", true)
)
}

@Test
@Tag(WarningNames.INLINE_CLASS_CAN_BE_USED)
fun `should not trigger on class with var prop #1`() {
lintMethod(
"""
|class Some(var anything: Int) {
|
|}
""".trimMargin()
)
}

@Test
@Tag(WarningNames.INLINE_CLASS_CAN_BE_USED)
fun `should not trigger on class with var prop #2`() {
lintMethod(
"""
|class Some {
| var some = 3
|}
""".trimMargin()
)
}

@Disabled
@Test
@Tag(WarningNames.INLINE_CLASS_CAN_BE_USED)
fun `should not trigger on class that extends class or interface`() {
lintMethod(
"""
|class Some : Any {
| val some = 3
|}
""".trimMargin()
)
}
}

0 comments on commit 0db1a08

Please sign in to comment.