Skip to content

Commit

Permalink
Merge branch 'master' into 'feature/underscores'
Browse files Browse the repository at this point in the history
# Conflicts:
#   diktat-huawei-rules/src/main/kotlin/com/huawei/rri/fixbot/ruleset/huawei/constants/Warnings.kt
  • Loading branch information
petertrr committed Jun 15, 2020
2 parents dc9db5e + 4bf6535 commit 185a253
Show file tree
Hide file tree
Showing 11 changed files with 246 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,10 @@ enum class Warnings(private val id: Int, private val canBeAutoCorrected: Boolean
KDOC_WITHOUT_PARAM_TAG(22, true, "all methods which take arguments should have @param tags in KDoc, the following parameters are missing"),
KDOC_WITHOUT_RETURN_TAG(23, true, "all methods which return values should have @return tag in KDoc"),
KDOC_WITHOUT_THROWS_TAG(24, true, "all methods which throw exceptions should have @throws tag in KDoc"),

BLANK_LINE_AFTER_KDOC(25, true, "there should be no empty line between Kdoc and code it is describing"),

// ====== incorrect place and warn number ====
INCORRECT_PACKAGE_SEPARATOR(25, true, "package name parts should be separated only by dots - there should be no other symbols like underscores (_)")
INCORRECT_PACKAGE_SEPARATOR(26, true, "package name parts should be separated only by dots - there should be no other symbols like underscores (_)")
;

override fun ruleName(): String = this.name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class HuaweiRuleSetProvider : RuleSetProvider {
"huawei-codestyle",
KdocComments(),
KdocMethods(),
KdocFormatting(),
FileNaming(),
PackageNaming(),
IdentifierNaming()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class KdocComments : Rule("kdoc-comments") {
val classBody = node.getFirstChildWithType(CLASS_BODY)

// if parent class is public or internal than we can check it's internal code elements
if (classBody != null && isAccessibleOutside(modifier)) {
if (classBody != null && modifier.isAccessibleOutside()) {
(classBody.getAllChildrenWithType(CLASS) + classBody.getAllChildrenWithType(FUN) + classBody.getAllChildrenWithType(PROPERTY))
.forEach { checkDoc(it, MISSING_KDOC_CLASS_ELEMENTS) }
}
Expand All @@ -71,7 +71,7 @@ class KdocComments : Rule("kdoc-comments") {
val modifier = node.getFirstChildWithType(MODIFIER_LIST)
val name = node.getIdentifierName()

if (isAccessibleOutside(modifier) && kDoc == null) {
if (modifier.isAccessibleOutside() && kDoc == null) {
warning.warn(confiRules, emitWarn, isFixMode, name!!.text, node.startOffset)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.huawei.rri.fixbot.ruleset.huawei.rules

import com.huawei.rri.fixbot.ruleset.huawei.constants.Warnings.BLANK_LINE_AFTER_KDOC
import com.huawei.rri.fixbot.ruleset.huawei.utils.countSubStringOccurrences
import com.huawei.rri.fixbot.ruleset.huawei.utils.getFirstChildWithType
import com.huawei.rri.fixbot.ruleset.huawei.utils.leaveOnlyOneNewLine
import com.pinterest.ktlint.core.KtLint
import com.pinterest.ktlint.core.Rule
import com.pinterest.ktlint.core.ast.ElementType
import com.pinterest.ktlint.core.ast.ElementType.CLASS
import com.pinterest.ktlint.core.ast.ElementType.FUN
import com.pinterest.ktlint.core.ast.ElementType.PROPERTY
import config.rules.RulesConfig
import org.jetbrains.kotlin.com.intellij.lang.ASTNode

/**
* Formatting visitor for Kdoc:
* 1) removing all blank lines between Kdoc and the code it's declaring
*/
class KdocFormatting : Rule("kdoc-formatting") {

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

override fun visit(node: ASTNode,
autoCorrect: Boolean,
params: KtLint.Params,
emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit) {

confiRules = params.rulesConfigList!!
isFixMode = autoCorrect
emitWarn = emit

val declarationTypes = setOf(CLASS, FUN, PROPERTY)

if (declarationTypes.contains(node.elementType)) {
val kdoc = node.getFirstChildWithType(ElementType.KDOC)
val nodeAfterKdoc = kdoc?.treeNext
val name = node.getFirstChildWithType(ElementType.IDENTIFIER)
if (nodeAfterKdoc?.elementType == ElementType.WHITE_SPACE && nodeAfterKdoc.text.countSubStringOccurrences("\n") > 1) {
BLANK_LINE_AFTER_KDOC.warnAndFix(confiRules, emitWarn, isFixMode, name!!.text, nodeAfterKdoc.startOffset) {
nodeAfterKdoc.leaveOnlyOneNewLine()
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class KdocMethods : Rule("kdoc-methods") {
isFixMode = autoCorrect
emitWarn = emit

if (node.elementType == FUN && isAccessibleOutside(node.getFirstChildWithType(MODIFIER_LIST))) {
if (node.elementType == FUN && node.getFirstChildWithType(MODIFIER_LIST).isAccessibleOutside()) {
checkSignatureDescription(node)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ package com.huawei.rri.fixbot.ruleset.huawei.utils
import com.pinterest.ktlint.core.ast.ElementType
import com.pinterest.ktlint.core.ast.ElementType.CONST_KEYWORD
import com.pinterest.ktlint.core.ast.ElementType.FILE
import com.pinterest.ktlint.core.ast.ElementType.INTERNAL_KEYWORD
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.WHITE_SPACE
import com.pinterest.ktlint.core.ast.isLeaf
import org.jetbrains.kotlin.com.google.common.base.Preconditions
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
Expand Down Expand Up @@ -52,6 +58,9 @@ fun ASTNode.getFirstChildWithType(elementType: IElementType): ASTNode? =
fun ASTNode.hasChildOfType(elementType: IElementType): Boolean =
this.getFirstChildWithType(elementType) != null

fun ASTNode.hasAnyChildOfTypes(vararg elementType: IElementType): Boolean =
elementType.any { this.hasChildOfType(it) }

/**
*
*/
Expand Down Expand Up @@ -103,7 +112,9 @@ fun ASTNode.isVarProperty() =
this.getChildren(null)
.any { it.elementType == ElementType.VAR_KEYWORD }

fun ASTNode.toLower() { (this as LeafPsiElement).replaceWithText(this.text.toLowerCase()) }
fun ASTNode.toLower() {
(this as LeafPsiElement).replaceWithText(this.text.toLowerCase())
}

/**
* This util method does tree traversal and stores to the result all tree leaf node of particular type (elementType).
Expand Down Expand Up @@ -154,14 +165,19 @@ fun ASTNode.prettyPrint(level: Int = 0, maxLevel: Int = -1): String {
* Checks if this modifier list corresponds to accessible outside entity
* @param modifierList ASTNode with ElementType.MODIFIER_LIST, can be null if entity has no modifier list
*/
fun isAccessibleOutside(modifierList: ASTNode?): Boolean {
Preconditions.checkArgument(modifierList == null || modifierList.elementType == ElementType.MODIFIER_LIST,
"The parameter should be ASTNode with ElementType.MODIFIER_LIST")
return modifierList == null ||
modifierList.hasChildOfType(ElementType.PUBLIC_KEYWORD) ||
modifierList.hasChildOfType(ElementType.INTERNAL_KEYWORD) ||
modifierList.hasChildOfType(ElementType.PROTECTED_KEYWORD) ||
// default == public modifier
(!modifierList.hasChildOfType(ElementType.PUBLIC_KEYWORD) && !modifierList.hasChildOfType(ElementType.INTERNAL_KEYWORD) &&
!modifierList.hasChildOfType(ElementType.PROTECTED_KEYWORD) && !modifierList.hasChildOfType(ElementType.PRIVATE_KEYWORD))
fun ASTNode?.isAccessibleOutside(): Boolean =
if (this != null) {
assert(this.elementType == MODIFIER_LIST)
this.hasAnyChildOfTypes(PUBLIC_KEYWORD, PROTECTED_KEYWORD, INTERNAL_KEYWORD) ||
!this.hasAnyChildOfTypes(PUBLIC_KEYWORD, INTERNAL_KEYWORD, PROTECTED_KEYWORD, PRIVATE_KEYWORD)
} else {
true
}

/**
* removing all newlines in WHITE_SPACE node and replacing it to a one newline saving the initial indenting format
*/
fun ASTNode.leaveOnlyOneNewLine() {
assert(this.elementType == WHITE_SPACE)
(this as LeafPsiElement).replaceWithText("\n${this.text.replace("\n", "")}")
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ fun String.containsOneLetterOrZero(): Boolean {
return count == 1 || count == 0
}

fun String.countSubStringOccurrences(sub: String) = this.split(sub).size - 1

fun String.splitPathToDirs(): List<String> =
this.replace("\\", "/")
.replace("//", "/")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.huawei.rri.fixbot.ruleset.huawei.chapter2

import com.huawei.rri.fixbot.ruleset.huawei.constants.Warnings
import com.huawei.rri.fixbot.ruleset.huawei.rules.KdocComments
import com.huawei.rri.fixbot.ruleset.huawei.rules.KdocFormatting
import com.huawei.rri.fixbot.ruleset.huawei.rules.PackageNaming
import com.pinterest.ktlint.core.KtLint
import com.pinterest.ktlint.core.LintError
import com.pinterest.ktlint.core.Rule
import com.pinterest.ktlint.core.RuleSet
import com.pinterest.ktlint.test.lint
import org.assertj.core.api.Assertions
import org.junit.Test
import test_framework.processing.TestComparatorUnit

class KdocFormattingFixTest {

val testComparatorUnit = TestComparatorUnit("test/paragraph2/kdoc/", ::format)


@Test
fun `there should be no blank line between kdoc and it's declaration code`() {
Assertions.assertThat(
testComparatorUnit
.compareFilesFromResources("KdocEmptyLineExpected.kt", "KdocEmptyLineTest.kt")
).isEqualTo(true)
}

private fun format(text: String, fileName: String): String = KdocFormatting().format(text, fileName)

private fun Rule.format(text: String, fileName: String): String {
return KtLint.format(
KtLint.Params(
text = text,
ruleSets = listOf(RuleSet("huawei-codestyle", this@format)),
fileName = fileName,
cb = { _, _ -> }
)
)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.huawei.rri.fixbot.ruleset.huawei.chapter2

import com.huawei.rri.fixbot.ruleset.huawei.constants.Warnings
import com.huawei.rri.fixbot.ruleset.huawei.rules.KdocFormatting
import com.pinterest.ktlint.core.LintError
import com.pinterest.ktlint.test.lint
import org.assertj.core.api.Assertions
import org.junit.Test

class KdocFormattingTest {
@Test
fun `there should be no blank line between kdoc and it's declaration code`() {
Assertions.assertThat(
KdocFormatting().lint(
"""
package com.huawei.test.resources.test.paragraph2.kdoc
/**
* declaration for some constant
*/
const val SUPER_CONSTANT = 46
/**
* Kdoc docummentation
*/
class SomeName {
/**
* another Kdoc
*/
val variable = "string"
/**
* another Kdoc
*/
fun somePublicFunction() {}
}
/**
* another Kdoc
*/
fun someFunction() {}
""".trimIndent()
)
).containsExactly(
LintError(5, 4, "kdoc-formatting", "${Warnings.BLANK_LINE_AFTER_KDOC.warnText()} SUPER_CONSTANT"),
LintError(11, 4, "kdoc-formatting", "${Warnings.BLANK_LINE_AFTER_KDOC.warnText()} SomeName"),
LintError(16, 8, "kdoc-formatting", "${Warnings.BLANK_LINE_AFTER_KDOC.warnText()} variable"),
LintError(22, 8, "kdoc-formatting", "${Warnings.BLANK_LINE_AFTER_KDOC.warnText()} somePublicFunction"),
LintError(31, 4, "kdoc-formatting", "${Warnings.BLANK_LINE_AFTER_KDOC.warnText()} someFunction")
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.huawei.test.resources.test.paragraph2.kdoc

/**
* declaration for some constant
*/
const val SUPER_CONSTANT = 46

/**
* Kdoc docummentation
*/
class SomeName {
/**
* another Kdoc
*/
val a = "string"

/**
* another Kdoc
*/
fun somePublicFunction() {}

}


/**
* another Kdoc
*/
fun someFunction() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.huawei.test.resources.test.paragraph2.kdoc

/**
* declaration for some constant
*/

const val SUPER_CONSTANT = 46

/**
* Kdoc docummentation
*/

class SomeName {
/**
* another Kdoc
*/

val a = "string"

/**
* another Kdoc
*/

fun somePublicFunction() {}

}


/**
* another Kdoc
*/

fun someFunction() {}

0 comments on commit 185a253

Please sign in to comment.