Skip to content

Commit

Permalink
* feature/ktlint-rule-wrapper(#606)
Browse files Browse the repository at this point in the history
### What's done:
  * Refactored more classes
  * Added error message
  • Loading branch information
aktsay6 committed Feb 3, 2021
1 parent bd6e597 commit 84cf9d4
Show file tree
Hide file tree
Showing 34 changed files with 130 additions and 411 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.pinterest.ktlint.core.Rule
import org.cqfn.diktat.common.config.rules.RulesConfig
import org.cqfn.diktat.common.config.rules.isRuleEnabled
import org.cqfn.diktat.ruleset.constants.EmitType
import org.cqfn.diktat.ruleset.utils.log
import org.jetbrains.kotlin.com.intellij.lang.ASTNode

typealias DiktatConfigRule = org.cqfn.diktat.common.config.rules.Rule
Expand All @@ -21,7 +22,7 @@ abstract class DiktatRule(id: String, val configRules: List<RulesConfig>, val ru
try {
logic(node)
} catch (e: Exception) {
// TODO: Specify message
log.error("Internal error has occurred in $id. Please make an issue on this bug at https://github.com/cqfn/diKTat/.\n Error: ${e.message}")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package org.cqfn.diktat.ruleset.rules.chapter4

import org.cqfn.diktat.common.config.rules.RulesConfig
import org.cqfn.diktat.ruleset.constants.EmitType
import org.cqfn.diktat.ruleset.constants.Warnings.SAY_NO_TO_VAR
import org.cqfn.diktat.ruleset.utils.search.findAllVariablesWithAssignments
import org.cqfn.diktat.ruleset.utils.search.findAllVariablesWithUsages

import com.pinterest.ktlint.core.Rule
import com.pinterest.ktlint.core.ast.ElementType
import org.cqfn.diktat.ruleset.rules.DiktatRule
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
import org.jetbrains.kotlin.psi.KtBlockExpression
import org.jetbrains.kotlin.psi.KtLambdaExpression
Expand All @@ -20,16 +19,8 @@ import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
* because `var` variables can be reassigned several times in the business logic. Of course, in some scenarios with loops or accumulators only `var`s can be used and are allowed.
* FixMe: here we should also raise warnings for a reassignment of a var (if var has no assignments except in declaration - it can be final)
*/
class ImmutableValNoVarRule(private val configRules: List<RulesConfig>) : Rule("no-var-rule") {
private var isFixMode: Boolean = false
private lateinit var emitWarn: EmitType

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

class ImmutableValNoVarRule(configRules: List<RulesConfig>) : DiktatRule("no-var-rule", configRules, listOf(SAY_NO_TO_VAR)) {
override fun logic(node: ASTNode) {
if (node.elementType == ElementType.FILE) {
// we will raise warning for cases when var property has no assignments
val varNoAssignments = node
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package org.cqfn.diktat.ruleset.rules.chapter4

import org.cqfn.diktat.common.config.rules.RulesConfig
import org.cqfn.diktat.ruleset.constants.EmitType
import org.cqfn.diktat.ruleset.constants.Warnings.AVOID_NULL_CHECKS
import org.cqfn.diktat.ruleset.rules.DiktatRule
import org.cqfn.diktat.ruleset.utils.*

import com.pinterest.ktlint.core.Rule
import com.pinterest.ktlint.core.ast.ElementType
import com.pinterest.ktlint.core.ast.ElementType.BINARY_EXPRESSION
import com.pinterest.ktlint.core.ast.ElementType.CONDITION
Expand All @@ -27,16 +26,8 @@ import org.jetbrains.kotlin.psi.KtIfExpression
* This rule check and fixes explicit null checks (explicit comparison with `null`)
* There are several code-structures that can be used in Kotlin to avoid null-checks. For example: `?:`, `.let {}`, `.also {}`, e.t.c
*/
class NullChecksRule(private val configRules: List<RulesConfig>) : Rule("null-checks") {
private var isFixMode: Boolean = false
private lateinit var emitWarn: EmitType

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

class NullChecksRule(configRules: List<RulesConfig>) : DiktatRule("null-checks", configRules, listOf(AVOID_NULL_CHECKS)) {
override fun logic(node: ASTNode) {
if (node.elementType == CONDITION) {
node.parent(IF)?.let {
// excluding complex cases with else-if statements, because they look better with explicit null-check
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package org.cqfn.diktat.ruleset.rules.chapter4

import org.cqfn.diktat.common.config.rules.RulesConfig
import org.cqfn.diktat.ruleset.constants.EmitType
import org.cqfn.diktat.ruleset.constants.Warnings.SMART_CAST_NEEDED
import org.cqfn.diktat.ruleset.rules.DiktatRule
import org.cqfn.diktat.ruleset.utils.KotlinParser
import org.cqfn.diktat.ruleset.utils.findAllNodesWithSpecificType
import org.cqfn.diktat.ruleset.utils.findParentNodeWithSpecificType
Expand All @@ -12,7 +12,6 @@ import org.cqfn.diktat.ruleset.utils.hasChildOfType
import org.cqfn.diktat.ruleset.utils.hasParent
import org.cqfn.diktat.ruleset.utils.search.findAllVariablesWithUsages

import com.pinterest.ktlint.core.Rule
import com.pinterest.ktlint.core.ast.ElementType.BINARY_WITH_TYPE
import com.pinterest.ktlint.core.ast.ElementType.BLOCK
import com.pinterest.ktlint.core.ast.ElementType.DOT_QUALIFIED_EXPRESSION
Expand Down Expand Up @@ -40,16 +39,8 @@ import org.jetbrains.kotlin.psi.psiUtil.parents
/**
* Rule that detects redundant explicit casts
*/
class SmartCastRule(private val configRules: List<RulesConfig>) : Rule("smart-cast-rule") {
private var isFixMode: Boolean = false
private lateinit var emitWarn: EmitType

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

class SmartCastRule(configRules: List<RulesConfig>) : DiktatRule("smart-cast-rule", configRules, listOf(SMART_CAST_NEEDED)) {
override fun logic(node: ASTNode) {
if (node.elementType == FILE) {
val usages = collectLocalPropertiesWithUsages(node)
val properMap = collectReferenceList(usages)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@ package org.cqfn.diktat.ruleset.rules.chapter4
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.EmitType
import org.cqfn.diktat.ruleset.constants.Warnings.TYPE_ALIAS
import org.cqfn.diktat.ruleset.rules.DiktatRule
import org.cqfn.diktat.ruleset.utils.*

import com.pinterest.ktlint.core.Rule
import com.pinterest.ktlint.core.ast.ElementType.LT
import com.pinterest.ktlint.core.ast.ElementType.SUPER_TYPE_LIST
import com.pinterest.ktlint.core.ast.ElementType.TYPEALIAS
Expand All @@ -20,16 +19,8 @@ import org.jetbrains.kotlin.psi.psiUtil.parents
* 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") {
private var isFixMode: Boolean = false
private lateinit var emitWarn: EmitType

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

class TypeAliasRule(configRules: List<RulesConfig>) : DiktatRule("type-alias", configRules, listOf(TYPE_ALIAS)) {
override fun logic(node: ASTNode) {
if (node.elementType == TYPE_REFERENCE && node
.parents()
.map { it.elementType }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package org.cqfn.diktat.ruleset.rules.chapter4

import org.cqfn.diktat.common.config.rules.RulesConfig
import org.cqfn.diktat.ruleset.constants.EmitType
import org.cqfn.diktat.ruleset.constants.Warnings
import org.cqfn.diktat.ruleset.constants.Warnings.GENERIC_VARIABLE_WRONG_DECLARATION
import org.cqfn.diktat.ruleset.rules.DiktatRule
import org.cqfn.diktat.ruleset.utils.getAllChildrenWithType

import com.pinterest.ktlint.core.Rule
import com.pinterest.ktlint.core.ast.ElementType.CALL_EXPRESSION
import com.pinterest.ktlint.core.ast.ElementType.DOT_QUALIFIED_EXPRESSION
import com.pinterest.ktlint.core.ast.ElementType.PROPERTY
Expand All @@ -22,16 +21,9 @@ import org.jetbrains.kotlin.psi.KtProperty
* Recommended: val myVariable: Map<Int, String> = emptyMap()
*/
// FIXME: we now don't have access to return types, so we can perform this check only if explicit type is present, but should be able also if it's not.
class VariableGenericTypeDeclarationRule(private val configRules: List<RulesConfig>) : Rule("variable-generic-type") {
private var isFixMode: Boolean = false
private lateinit var emitWarn: EmitType

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

class VariableGenericTypeDeclarationRule(configRules: List<RulesConfig>) : DiktatRule("variable-generic-type", configRules,
listOf(GENERIC_VARIABLE_WRONG_DECLARATION)) {
override fun logic(node: ASTNode) {
when (node.elementType) {
PROPERTY, VALUE_PARAMETER -> handleProperty(node)
else -> {
Expand Down Expand Up @@ -63,14 +55,14 @@ class VariableGenericTypeDeclarationRule(private val configRules: List<RulesConf
if ((rightSide != null && leftSide != null) &&
rightSide.size == leftSide.size &&
rightSide.zip(leftSide).all { (first, second) -> first.text == second.text }) {
Warnings.GENERIC_VARIABLE_WRONG_DECLARATION.warnAndFix(configRules, emitWarn, isFixMode,
GENERIC_VARIABLE_WRONG_DECLARATION.warnAndFix(configRules, emitWarn, isFixMode,
"type arguments are unnecessary in ${callExpr.text}", node.startOffset, node) {
callExpr.removeChild(callExpr.findChildByType(TYPE_ARGUMENT_LIST)!!)
}
}

if (leftSide == null && rightSide != null) {
Warnings.GENERIC_VARIABLE_WRONG_DECLARATION.warn(configRules, emitWarn, isFixMode, node.text, node.startOffset, node)
GENERIC_VARIABLE_WRONG_DECLARATION.warn(configRules, emitWarn, isFixMode, node.text, node.startOffset, node)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package org.cqfn.diktat.ruleset.rules.chapter4.calculations

import org.cqfn.diktat.common.config.rules.RulesConfig
import org.cqfn.diktat.ruleset.constants.EmitType
import org.cqfn.diktat.ruleset.constants.Warnings.FLOAT_IN_ACCURATE_CALCULATIONS
import org.cqfn.diktat.ruleset.rules.DiktatRule
import org.cqfn.diktat.ruleset.utils.findLocalDeclaration
import org.cqfn.diktat.ruleset.utils.getFunctionName

import com.pinterest.ktlint.core.Rule
import com.pinterest.ktlint.core.ast.ElementType
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
import org.jetbrains.kotlin.com.intellij.psi.PsiElement
Expand All @@ -25,10 +24,7 @@ import org.jetbrains.kotlin.psi.psiUtil.startOffset
* Exception: allows arithmetic operations only when absolute value of result is immediately used in comparison
* Fixme: detect variables by type, not only floating-point literals
*/
class AccurateCalculationsRule(private val configRules: List<RulesConfig>) : Rule("accurate-calculations") {
private var isFixMode: Boolean = false
private lateinit var emitWarn: EmitType

class AccurateCalculationsRule(configRules: List<RulesConfig>) : DiktatRule("accurate-calculations", configRules, listOf(FLOAT_IN_ACCURATE_CALCULATIONS)) {
private fun KtCallExpression?.isAbsOfFloat() = this
?.run {
(calleeExpression as? KtNameReferenceExpression)
Expand Down Expand Up @@ -114,12 +110,7 @@ class AccurateCalculationsRule(private val configRules: List<RulesConfig>) : Rul
* @param autoCorrect
* @param emit
*/
override fun visit(node: ASTNode,
autoCorrect: Boolean,
emit: EmitType) {
emitWarn = emit
isFixMode = autoCorrect

override fun logic(node: ASTNode) {
when (val psi = node.psi) {
is KtBinaryExpression -> handleBinaryExpression(psi)
is KtDotQualifiedExpression -> handleFunction(psi)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package org.cqfn.diktat.ruleset.rules.chapter5

import org.cqfn.diktat.common.config.rules.RulesConfig
import org.cqfn.diktat.ruleset.constants.EmitType
import org.cqfn.diktat.ruleset.constants.Warnings.RUN_BLOCKING_INSIDE_ASYNC
import org.cqfn.diktat.ruleset.rules.DiktatRule
import org.cqfn.diktat.ruleset.utils.hasChildOfType

import com.pinterest.ktlint.core.Rule
import com.pinterest.ktlint.core.ast.ElementType.CALL_EXPRESSION
import com.pinterest.ktlint.core.ast.ElementType.FUN
import com.pinterest.ktlint.core.ast.ElementType.LAMBDA_ARGUMENT
Expand All @@ -18,17 +17,10 @@ import org.jetbrains.kotlin.psi.psiUtil.hasSuspendModifier
/**
* This rule finds if using runBlocking in asynchronous code
*/
class AsyncAndSyncRule(private val configRules: List<RulesConfig>) : Rule("sync-in-async") {
class AsyncAndSyncRule(configRules: List<RulesConfig>) : DiktatRule("sync-in-async", configRules, listOf(RUN_BLOCKING_INSIDE_ASYNC)) {
private val asyncList = listOf("async", "launch")
private var isFixMode: Boolean = false
private lateinit var emitWarn: EmitType

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

override fun logic(node: ASTNode) {
if (node.isRunBlocking()) {
checkRunBlocking(node)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package org.cqfn.diktat.ruleset.rules.chapter5

import org.cqfn.diktat.common.config.rules.RulesConfig
import org.cqfn.diktat.ruleset.constants.EmitType
import org.cqfn.diktat.ruleset.constants.Warnings.AVOID_NESTED_FUNCTIONS
import org.cqfn.diktat.ruleset.rules.DiktatRule
import org.cqfn.diktat.ruleset.utils.findAllNodesWithSpecificType
import org.cqfn.diktat.ruleset.utils.getFirstChildWithType
import org.cqfn.diktat.ruleset.utils.hasChildOfType
import org.cqfn.diktat.ruleset.utils.hasParent

import com.pinterest.ktlint.core.Rule
import com.pinterest.ktlint.core.ast.ElementType.CLASS_BODY
import com.pinterest.ktlint.core.ast.ElementType.FUN
import com.pinterest.ktlint.core.ast.ElementType.IDENTIFIER
Expand All @@ -25,16 +24,8 @@ import org.jetbrains.kotlin.psi.psiUtil.parents
/**
* This rule checks for nested functions and warns if it finds any.
*/
class AvoidNestedFunctionsRule(private val configRules: List<RulesConfig>) : Rule("avoid-nested-functions") {
private var isFixMode: Boolean = false
private lateinit var emitWarn: EmitType

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

class AvoidNestedFunctionsRule(configRules: List<RulesConfig>) : DiktatRule("avoid-nested-functions", configRules, listOf(AVOID_NESTED_FUNCTIONS)) {
override fun logic(node: ASTNode) {
if (node.elementType == FUN) {
handleNestedFunctions(node)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package org.cqfn.diktat.ruleset.rules.chapter5

import org.cqfn.diktat.common.config.rules.RulesConfig
import org.cqfn.diktat.ruleset.constants.EmitType
import org.cqfn.diktat.ruleset.constants.Warnings.INVERSE_FUNCTION_PREFERRED
import org.cqfn.diktat.ruleset.rules.DiktatRule

import com.pinterest.ktlint.core.Rule
import com.pinterest.ktlint.core.ast.ElementType.BLOCK_COMMENT
import com.pinterest.ktlint.core.ast.ElementType.CALL_EXPRESSION
import com.pinterest.ktlint.core.ast.ElementType.IDENTIFIER
Expand All @@ -23,16 +22,8 @@ import org.jetbrains.kotlin.psi.psiUtil.siblings
* This rule checks if inverse method can be used.
* For example if there is !isEmpty() on collection call that it changes it to isNotEmpty()
*/
class CheckInverseMethodRule(private val configRules: List<RulesConfig>) : Rule("inverse-method") {
private var isFixMode: Boolean = false
private lateinit var emitWarn: EmitType

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

class CheckInverseMethodRule(configRules: List<RulesConfig>) : DiktatRule("inverse-method", configRules, listOf(INVERSE_FUNCTION_PREFERRED)) {
override fun logic(node: ASTNode) {
if (node.elementType == CALL_EXPRESSION && node.text in methodMap.keys) {
checkCallExpressionName(node)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package org.cqfn.diktat.ruleset.rules.chapter5

import org.cqfn.diktat.common.config.rules.RulesConfig
import org.cqfn.diktat.ruleset.constants.EmitType
import org.cqfn.diktat.ruleset.constants.Warnings.CUSTOM_LABEL
import org.cqfn.diktat.ruleset.rules.DiktatRule
import org.cqfn.diktat.ruleset.utils.loopType

import com.pinterest.ktlint.core.Rule
import com.pinterest.ktlint.core.ast.ElementType.BREAK
import com.pinterest.ktlint.core.ast.ElementType.CALL_EXPRESSION
import com.pinterest.ktlint.core.ast.ElementType.CONTINUE
Expand All @@ -18,19 +17,12 @@ import org.jetbrains.kotlin.psi.psiUtil.parents
/**
* Rule that checks using custom label
*/
class CustomLabel(private val configRules: List<RulesConfig>) : Rule("custom-label") {
private var isFixMode: Boolean = false
class CustomLabel(configRules: List<RulesConfig>) : DiktatRule("custom-label", configRules, listOf(CUSTOM_LABEL)) {
private val forEachReference = listOf("forEach", "forEachIndexed")
private val labels = listOf("@loop", "@forEach", "@forEachIndexed")
private val stopWords = listOf(RETURN, BREAK, CONTINUE)
private lateinit var emitWarn: EmitType

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

override fun logic(node: ASTNode) {
if (node.elementType == LABEL_QUALIFIER && node.text !in labels && node.treeParent.elementType in stopWords) {
val nestedCount = node.parents().count {
it.elementType in loopType ||
Expand Down
Loading

0 comments on commit 84cf9d4

Please sign in to comment.