Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recommendation 4.2.2 type alias #288

Merged
merged 9 commits into from
Sep 17, 2020
Merged
7 changes: 6 additions & 1 deletion diktat-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -230,4 +230,9 @@
configuration: {}
- name: LOCAL_VARIABLE_EARLY_DECLARATION
enabled: true
configuration: {}
configuration: {}
# Type aliases provide alternative names for existing types when type's reference text is longer 25 chars
- name: TYPE_ALIAS
enabled: true
configuration:
typeReferenceLength: '25' # max length of type reference
2 changes: 2 additions & 0 deletions diktat-rules/src/main/kotlin/generated/WarningNames.kt
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,6 @@ object WarningNames {
const val WRONG_MULTIPLE_MODIFIERS_ORDER: String = "WRONG_MULTIPLE_MODIFIERS_ORDER"

const val LOCAL_VARIABLE_EARLY_DECLARATION: String = "LOCAL_VARIABLE_EARLY_DECLARATION"

const val TYPE_ALIAS: String = "TYPE_ALIAS"
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ enum class Warnings(private val canBeAutoCorrected: Boolean, private val warn: S
WRONG_DECLARATIONS_ORDER(true, "declarations of constants and enum members should be sorted alphabetically"),
WRONG_MULTIPLE_MODIFIERS_ORDER(true, "sequence of modifiers is incorrect"),
LOCAL_VARIABLE_EARLY_DECLARATION(false, "local variables should be declared close to the line where they are first used"),
TYPE_ALIAS(false, "variable's type is too complex and should be replaced with typealias"),
;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class DiktatRuleSetProvider(private val diktatConfigFile: String = "diktat-analy
::SortRule,
::StringConcatenationRule,
::LineLength,
::TypeAliasRule,
::BlankLinesRule,
::WhiteSpaceRule,
::WhenMustHaveElseRule,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package org.cqfn.diktat.ruleset.rules

import com.pinterest.ktlint.core.Rule
import com.pinterest.ktlint.core.ast.ElementType.LT
import com.pinterest.ktlint.core.ast.ElementType.TYPE_REFERENCE
import com.pinterest.ktlint.core.ast.ElementType.VALUE_PARAMETER
import org.cqfn.diktat.common.config.rules.RuleConfiguration
import org.cqfn.diktat.common.config.rules.RulesConfig
import org.cqfn.diktat.common.config.rules.getRuleConfig
import org.cqfn.diktat.ruleset.constants.Warnings.TYPE_ALIAS
import org.cqfn.diktat.ruleset.utils.*
import org.jetbrains.kotlin.com.intellij.lang.ASTNode

/**
* This rule checks if variable has long type reference and two or more nested generics.
* Length type reference can be configured
*/
class TypeAliasRule(private val configRules: List<RulesConfig>) : Rule("type-alias") {
kentr0w marked this conversation as resolved.
Show resolved Hide resolved

companion object {
const val TYPE_REFERENCE_MAX_LENGTH = 25
}

private lateinit var emitWarn: ((offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit)
private var isFixMode: Boolean = false

override fun visit(node: ASTNode,
autoCorrect: Boolean,
emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit) {
emitWarn = emit
isFixMode = autoCorrect

if (node.elementType == TYPE_REFERENCE) {
checkTypeReference(node, TypeAliasConfiguration(configRules.getRuleConfig(TYPE_ALIAS)?.configuration ?: mapOf()))
}
}

/**
* Check properties for nested generics. Count LT for generic types and VALUE_PARAMETER for functional types
*/
private fun checkTypeReference(node: ASTNode, config: TypeAliasConfiguration) {
if (node.textLength > config.typeReferenceLength)
if (node.findAllNodesWithSpecificType(LT).size > 1 || node.findAllNodesWithSpecificType(VALUE_PARAMETER).size > 1)
kentr0w marked this conversation as resolved.
Show resolved Hide resolved
TYPE_ALIAS.warn(configRules, emitWarn, isFixMode, "too long type reference", node.startOffset, node)
}

class TypeAliasConfiguration(config: Map<String, String>) : RuleConfiguration(config) {
val typeReferenceLength = config["typeReferenceLength"]?.toIntOrNull() ?: TYPE_REFERENCE_MAX_LENGTH
}
}
7 changes: 6 additions & 1 deletion diktat-rules/src/main/resources/diktat-analysis-huawei.yml
Original file line number Diff line number Diff line change
Expand Up @@ -230,4 +230,9 @@
configuration: {}
- name: LOCAL_VARIABLE_EARLY_DECLARATION
enabled: true
configuration: {}
configuration: {}
# Type aliases provide alternative names for existing types when type's reference text is longer 25 chars
- name: TYPE_ALIAS
enabled: true
configuration:
typeReferenceLength: '25' # max length of type reference
7 changes: 6 additions & 1 deletion diktat-rules/src/main/resources/diktat-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -234,4 +234,9 @@
# Inspection that checks if local variables are declared close to the first usage site
- name: LOCAL_VARIABLE_EARLY_DECLARATION
enabled: true
configuration: {}
configuration: {}
# Type aliases provide alternative names for existing types when type's reference text is longer 25 chars
- name: TYPE_ALIAS
kentr0w marked this conversation as resolved.
Show resolved Hide resolved
enabled: true
configuration:
typeReferenceLength: '25' # max length of type reference
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package org.cqfn.diktat.ruleset.chapter3

import com.pinterest.ktlint.core.LintError
import generated.WarningNames
import org.cqfn.diktat.common.config.rules.RulesConfig
import org.cqfn.diktat.ruleset.constants.Warnings.TYPE_ALIAS
import org.cqfn.diktat.ruleset.rules.DIKTAT_RULE_SET_ID
import org.cqfn.diktat.ruleset.rules.TypeAliasRule
import org.cqfn.diktat.util.LintTestBase
import org.junit.jupiter.api.Tag
import org.junit.jupiter.api.Test

class TypeAliasRuleWarnTest : LintTestBase(::TypeAliasRule) {

private val ruleId = "$DIKTAT_RULE_SET_ID:type-alias"

private val rulesConfigListShortType: List<RulesConfig> = listOf(
RulesConfig(TYPE_ALIAS.name, true,
mapOf("typeReferenceLength" to "4"))
)

@Test
@Tag(WarningNames.TYPE_ALIAS)
fun `string concatenation - only strings`() {
lintMethod(
"""
| val b: MutableMap<String, MutableList<String>>
| val b = listof<Int>()
""".trimMargin(),
LintError(1,9, ruleId, "${TYPE_ALIAS.warnText()} too long type reference", false)
)
}

@Test
@Tag(WarningNames.TYPE_ALIAS)
fun `check long lambda property`() {
lintMethod(
"""
| var emitWarn: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit
| var emitWarn: (offset: Int, (T) -> Boolean) -> Unit
""".trimMargin(),
LintError(1,16, ruleId, "${TYPE_ALIAS.warnText()} too long type reference", false),
LintError(2,16, ruleId, "${TYPE_ALIAS.warnText()} too long type reference", false)
)
}

@Test
@Tag(WarningNames.TYPE_ALIAS)
fun `correct type length`() {
lintMethod(
"""
| var emitWarn: Int
| val b = mutableMapOf<String, MutableList<String>>()
|
| fun foo(): MutableMap<String, MutableList<String>> {
| }
|
""".trimMargin(),
LintError(4,13, ruleId, "${TYPE_ALIAS.warnText()} too long type reference", false)
)
}

@Test
@Tag(WarningNames.TYPE_ALIAS)
fun `correct type length but with configuration`() {
lintMethod(
"""
| var emitWarn: Int
| val flag: (T) -> Boolean
| val list: List<List<Int>>
|
""".trimMargin(),
LintError(3,12, ruleId, "${TYPE_ALIAS.warnText()} too long type reference", false),
rulesConfigList = rulesConfigListShortType
)
}
}
1 change: 1 addition & 0 deletions info/available-rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,4 @@
| 3 | 3.2 | WRONG_DECLARATIONS_ORDER | Check: if order of enum values or constant property inside companion isn't correct | yes | - | - |
| 3 | 3.11 | ANNOTATION_NEW_LINE | Check: warns if annotation not on a new single line | yes | - | - |
| 3 | 3.2 | WRONG_MULTIPLE_MODIFIERS_ORDER | Check: if multiple modifiers sequence is in the wrong order | yes | - | - |
| 4 | 4.2.2| TYPE_ALIAS | Check: if type reference of property is longer than expected | yes | typeReferenceLength | -|