diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/IdentifierNaming.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/IdentifierNaming.kt index efaa07aa12..aa1c669d34 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/IdentifierNaming.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/IdentifierNaming.kt @@ -37,6 +37,7 @@ import org.cqfn.diktat.ruleset.utils.isPascalCase import org.cqfn.diktat.ruleset.utils.isTextLengthInRange import org.cqfn.diktat.ruleset.utils.isUpperSnakeCase import org.cqfn.diktat.ruleset.utils.removePrefix +import org.cqfn.diktat.ruleset.utils.search.findAllVariablesWithUsages import org.cqfn.diktat.ruleset.utils.toLowerCamelCase import org.cqfn.diktat.ruleset.utils.toPascalCase import org.cqfn.diktat.ruleset.utils.toUpperSnakeCase @@ -47,16 +48,21 @@ import com.pinterest.ktlint.core.ast.ElementType.CATCH import com.pinterest.ktlint.core.ast.ElementType.CATCH_KEYWORD import com.pinterest.ktlint.core.ast.ElementType.DESTRUCTURING_DECLARATION import com.pinterest.ktlint.core.ast.ElementType.DESTRUCTURING_DECLARATION_ENTRY +import com.pinterest.ktlint.core.ast.ElementType.FILE import com.pinterest.ktlint.core.ast.ElementType.FUNCTION_TYPE +import com.pinterest.ktlint.core.ast.ElementType.PROPERTY import com.pinterest.ktlint.core.ast.ElementType.REFERENCE_EXPRESSION import com.pinterest.ktlint.core.ast.ElementType.TYPE_PARAMETER import com.pinterest.ktlint.core.ast.ElementType.TYPE_REFERENCE import com.pinterest.ktlint.core.ast.ElementType.VALUE_PARAMETER_LIST +import com.pinterest.ktlint.core.ast.parent import com.pinterest.ktlint.core.ast.prevCodeSibling import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.com.intellij.lang.ASTNode import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement import org.jetbrains.kotlin.com.intellij.psi.tree.TokenSet +import org.jetbrains.kotlin.psi.KtProperty +import org.jetbrains.kotlin.psi.psiUtil.isPrivate import org.jetbrains.kotlin.psi.psiUtil.parents /** @@ -134,10 +140,13 @@ class IdentifierNaming(private val configRules: List) : Rule("ident /** * all checks for case and naming for vals/vars/constants */ - @Suppress("SAY_NO_TO_VAR") + @Suppress("SAY_NO_TO_VAR", "TOO_LONG_FUNCTION", "ComplexMethod") private fun checkVariableName(node: ASTNode): List { // special case for Destructuring declarations that can be treated as parameters in lambda: var namesOfVariables = extractVariableIdentifiers(node) + // Only local private properties will be autofix in order not to break code if there are usages in other files. + // Destructuring declarations are only allowed for local variables/values, so we don't need to calculate `isFix` for every node in `namesOfVariables` + val isFix = isFixMode && if (node.elementType == PROPERTY) (node.psi as KtProperty).run { isLocal || isPrivate() } else true namesOfVariables .forEach { variableName -> // variable should not contain only one letter in it's name. This is a bad example: b512 @@ -154,15 +163,21 @@ class IdentifierNaming(private val configRules: List) : Rule("ident // it should be in UPPER_CASE, no need to raise this warning if it is one-letter variable if (node.isConstant()) { if (!variableName.text.isUpperSnakeCase() && variableName.text.length > 1) { - CONSTANT_UPPERCASE.warnAndFix(configRules, emitWarn, isFixMode, variableName.text, variableName.startOffset, node) { + CONSTANT_UPPERCASE.warnAndFix(configRules, emitWarn, isFix, variableName.text, variableName.startOffset, node) { (variableName as LeafPsiElement).replaceWithText(variableName.text.toUpperSnakeCase()) } } } else if (variableName.text != "_" && !variableName.text.isLowerCamelCase()) { // variable name should be in camel case. The only exception is a list of industry standard variables like i, j, k. - VARIABLE_NAME_INCORRECT_FORMAT.warnAndFix(configRules, emitWarn, isFixMode, variableName.text, variableName.startOffset, node) { + VARIABLE_NAME_INCORRECT_FORMAT.warnAndFix(configRules, emitWarn, isFix, variableName.text, variableName.startOffset, node) { // FixMe: cover fixes with tests - (variableName as LeafPsiElement).replaceWithText(variableName.text.toLowerCamelCase()) + val correctVariableName = variableName.text.toLowerCamelCase() + variableName + .parent({it.elementType == FILE}) + ?.findAllVariablesWithUsages { it.name == variableName.text } + ?.flatMap { it.value.toList() } + ?.forEach { (it.node.firstChildNode as LeafPsiElement).replaceWithText(correctVariableName)} + (variableName as LeafPsiElement).replaceWithText(correctVariableName) } } } diff --git a/diktat-rules/src/test/resources/test/paragraph1/naming/identifiers/VariableNamingExpected.kt b/diktat-rules/src/test/resources/test/paragraph1/naming/identifiers/VariableNamingExpected.kt index 336cb28db3..a3f5eae19d 100644 --- a/diktat-rules/src/test/resources/test/paragraph1/naming/identifiers/VariableNamingExpected.kt +++ b/diktat-rules/src/test/resources/test/paragraph1/naming/identifiers/VariableNamingExpected.kt @@ -10,3 +10,39 @@ private val loWerValue = "" private val lower = "" private val valNX256 = "" private val voiceIpPort = "" + +class A { + private val voiceIpPort = "" + public val valN_x2567 = "" + + fun foo() { + val voiceIpPorts = "" + val upperSnakers = voiceIpPort + qww(voiceIpPorts) + } + + fun goo() { + val qwe = lowerSnake + val pre = valNX256 + } +} + +class B { + companion object { + val QQ = 1 + private val qwe = 11 + } + + fun foo() { + var qq = 20 + while (qq < 20) { + qq = 10 + } + } + + class Ba { + fun goo() { + val qwe = QQ + } + } +} \ No newline at end of file diff --git a/diktat-rules/src/test/resources/test/paragraph1/naming/identifiers/VariableNamingTest.kt b/diktat-rules/src/test/resources/test/paragraph1/naming/identifiers/VariableNamingTest.kt index 8d04545cf5..10bfbdc829 100644 --- a/diktat-rules/src/test/resources/test/paragraph1/naming/identifiers/VariableNamingTest.kt +++ b/diktat-rules/src/test/resources/test/paragraph1/naming/identifiers/VariableNamingTest.kt @@ -10,3 +10,39 @@ private val loWer_VAlue = "" private val lower = "" private val ValN_x256 = "" private val VoiceIP_port = "" + +class A { + private val VoiceIP_port = "" + public val valN_x2567 = "" + + fun foo() { + val VoiceIP_ports = "" + val UPPER_SNAKERS = VoiceIP_port + qww(VoiceIP_ports) + } + + fun goo() { + val qwe = lower_snake + val pre = ValN_x256 + } +} + +class B { + companion object { + val QQ = 1 + private val QWE = 11 + } + + fun foo() { + var QQ = 20 + while (QQ < 20) { + QQ = 10 + } + } + + class BA { + fun goo() { + val qwe = QQ + } + } +}