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

Run rules during unit tests in correct order #1470

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/Rule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import org.jetbrains.kotlin.com.intellij.lang.ASTNode
* Implementation **doesn't** have to be thread-safe or stateless
* (provided [RuleSetProvider] creates a new instance on each `get()` call).
*
* @param id must be unique within the ruleset
* @param id: For non-standard rules, it is expected that this id consist of the ruleSetId and ruleId, e.g. "some-rule-set-id:some-rule-id"
* @param visitorModifiers: set of modifiers of the visitor. Preferably a rule has no modifiers at all, meaning that it
* is completely independent of all other rules.
*
Expand All @@ -20,7 +20,7 @@ abstract class Rule(
public val visitorModifiers: Set<VisitorModifier> = emptySet()
) {
init {
IdNamingPolicy.enforceNaming(id)
IdNamingPolicy.enforceRuleIdNaming(id)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ open class RuleSet(
) : Iterable<Rule> {

init {
IdNamingPolicy.enforceNaming(id)
IdNamingPolicy.enforceRuleSetIdNaming(id)
require(rules.isNotEmpty()) { "At least one rule must be provided" }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ import org.jetbrains.kotlin.com.intellij.lang.ASTNode

public class VisitorProvider(
ruleSets: Iterable<RuleSet>,
private val debug: Boolean,
isUnitTestContext: Boolean = false
private val debug: Boolean
) {
private val ruleReferences: List<RuleReference> =
VisitorProviderInitializer(ruleSets, debug, isUnitTestContext).getRulePreferences()
VisitorProviderInitializer(ruleSets, debug).getRulePreferences()

internal fun visitor(
ruleSets: Iterable<RuleSet>,
Expand All @@ -27,7 +26,7 @@ public class VisitorProvider(
.rules
.filter { rule -> toQualifiedRuleId(ruleSet.id, rule.id) in enabledQualifiedRuleIds }
.filter { rule -> isNotDisabled(rootNode, toQualifiedRuleId(ruleSet.id, rule.id)) }
.map { rule -> "${ruleSet.id}:${rule.id}" to rule }
.map { rule -> "${toQualifiedRuleId(ruleSet.id, rule.id)}" to rule }
}.toMap()
if (debug && enabledRules.isEmpty()) {
println(
Expand Down Expand Up @@ -130,7 +129,11 @@ private fun toQualifiedRuleId(
ruleSetId: String,
ruleId: String
) =
"$ruleSetId:$ruleId"
if (ruleId.startsWith("$ruleSetId:")) {
ruleId
} else {
"$ruleSetId:$ruleId"
}

private fun String.toQualifiedRuleId() =
if (contains(":")) {
Expand All @@ -141,8 +144,7 @@ private fun String.toQualifiedRuleId() =

private class VisitorProviderInitializer(
val ruleSets: Iterable<RuleSet>,
val debug: Boolean,
val isUnitTestContext: Boolean = false
val debug: Boolean
) {
fun getRulePreferences(): List<RuleReference> {
return ruleSets
Expand Down Expand Up @@ -275,13 +277,7 @@ private class VisitorProviderInitializer(
while (ruleReferencesIterator.hasNext()) {
val ruleReference = ruleReferencesIterator.next()

if (ruleReference.runAfterRule != null && isUnitTestContext) {
// When running unit tests,the RunAfterRule annotation is ignored. The code provided in the unit should
// be formatted as if the rule on which it depends was already applied. In this way the unit test can be
// restricted to one single rule instead of having to take into account all other rules on which it
// might depend.
newRuleReferences.add(ruleReference.copy(runAfterRule = null))
} else if (ruleReference.runAfterRule != null && newRuleReferences.none { rule -> rule.runsAfter(ruleReference) }) {
if (ruleReference.runAfterRule != null && newRuleReferences.none { rule -> rule.runsAfter(ruleReference) }) {
// The RunAfterRule refers to a rule which is not yet added to the new list of rule references.
if (this.none { it.runsAfter(ruleReference) }) {
// The RunAfterRule refers to a rule which is not loaded at all.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,23 @@ package com.pinterest.ktlint.core.internal
* Provides policy to have consistent and restricted `id` field naming style.
*/
internal object IdNamingPolicy {
private const val ID_REGEX = "[a-z]+([-][a-z]+)*"
private val idRegex = ID_REGEX.toRegex()
private const val SIMPLE_ID_REGEX = "[a-z]+([-][a-z]+)*"
private val ruleIdRegex = "($SIMPLE_ID_REGEX:)?($SIMPLE_ID_REGEX)".toRegex()
private val ruleSetIdRegex = "($SIMPLE_ID_REGEX)".toRegex()

/**
* Checks provided [id] is valid.
* Checks provided [ruleId] is valid.
*
* Will throw [IllegalArgumentException] on invalid [id] name.
* Will throw [IllegalArgumentException] on invalid [ruleId] name.
*/
internal fun enforceNaming(id: String) =
require(id.matches(idRegex)) { "id $id must match $ID_REGEX" }
internal fun enforceRuleIdNaming(ruleId: String) =
require(ruleId.matches(ruleIdRegex)) { "Rule id '$ruleId' must match '${ruleIdRegex.pattern}'" }

/**
* Checks provided [ruleSetId] is valid.
*
* Will throw [IllegalArgumentException] on invalid [ruleSetId] name.
*/
internal fun enforceRuleSetIdNaming(ruleSetId: String) =
require(ruleSetId.matches(ruleSetIdRegex)) { "RuleSet id '$ruleSetId' must match '${ruleSetIdRegex.pattern}'" }
}
Original file line number Diff line number Diff line change
Expand Up @@ -580,10 +580,7 @@ class VisitorProviderTest {
return VisitorProvider(
ruleSets = ruleSetList,
// Enable debug mode as it is helpful when a test fails
debug = true,
// Although this is a unit test, the isUnitTestContext is disabled by default so that rules marked with
// RunAfterRule can be tested as well.
isUnitTestContext = isUnitTestContext ?: false
debug = true
).run {
var visits: MutableList<Visit>? = null
visitor(ruleSetList, SOME_ROOT_AST_NODE, concurrent ?: false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import org.jetbrains.kotlin.psi.psiUtil.nextLeaf
*
* @see [AnnotationSpacingRule] for white space rules. Moved since
*/
class AnnotationRule : Rule("annotation") {
class AnnotationRule : Rule("$experimentalRulesetId:annotation") {

companion object {
const val multipleAnnotationsOnSameLineAsAnnotatedConstructErrorMessage =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import org.jetbrains.kotlin.psi.psiUtil.leaves
*
* https://kotlinlang.org/docs/reference/coding-conventions.html#annotation-formatting
*/
class AnnotationSpacingRule : Rule("annotation-spacing") {
class AnnotationSpacingRule : Rule("$experimentalRulesetId:annotation-spacing") {

companion object {
const val ERROR_MESSAGE = "Annotations should occur immediately before the annotated construct"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
*/
@OptIn(FeatureInAlphaState::class)
class ArgumentListWrappingRule :
Rule("argument-list-wrapping"),
Rule("$experimentalRulesetId:argument-list-wrapping"),
UsesEditorConfigProperties {
private var editorConfigIndent = IndentConfig.DEFAULT_INDENT_CONFIG
private var maxLineLength = -1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafElement
*/
class BlockCommentInitialStarAlignmentRule :
Rule(
"block-comment-initial-star-alignment",
"$experimentalRulesetId:block-comment-initial-star-alignment",
visitorModifiers = setOf(
// The block comment is a node which can contain multiple lines. The indent of the second and later line
// should be determined based on the indent of the block comment node. This indent is determined by the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiCommentImpl
*/
@OptIn(FeatureInAlphaState::class)
public class CommentWrappingRule :
Rule("comment-wrapping"),
Rule("$experimentalRulesetId:comment-wrapping"),
UsesEditorConfigProperties {
override val editorConfigProperties: List<UsesEditorConfigProperties.EditorConfigProperty<*>> =
listOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import org.jetbrains.kotlin.com.intellij.lang.ASTNode
* foo(t: T) = "some-result"
* ```
*/
public class DiscouragedCommentLocationRule : Rule("discouraged-comment-location") {
public class DiscouragedCommentLocationRule : Rule("$experimentalRulesetId:discouraged-comment-location") {
override fun visit(
node: ASTNode,
autoCorrect: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import org.jetbrains.kotlin.com.intellij.lang.ASTNode
import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.CompositeElement
import org.jetbrains.kotlin.psi.KtEnumEntry

public class EnumEntryNameCaseRule : Rule("enum-entry-name-case") {

public class EnumEntryNameCaseRule : Rule("$experimentalRulesetId:enum-entry-name-case") {
internal companion object {
val regex = Regex("[A-Z]([A-Za-z\\d]*|[A-Z_\\d]*)")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import com.pinterest.ktlint.core.RuleSet
import com.pinterest.ktlint.core.RuleSetProvider
import com.pinterest.ktlint.ruleset.experimental.trailingcomma.TrailingCommaRule

public class ExperimentalRuleSetProvider : RuleSetProvider {
public const val experimentalRulesetId = "experimental"

public class ExperimentalRuleSetProvider : RuleSetProvider {
override fun get(): RuleSet = RuleSet(
"experimental",
experimentalRulesetId,
AnnotationRule(),
ArgumentListWrappingRule(),
MultiLineIfElseRule(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement
/**
* Lints and formats the spacing after the fun keyword
*/
public class FunKeywordSpacingRule : Rule("fun-keyword-spacing") {
public class FunKeywordSpacingRule : Rule("$experimentalRulesetId:fun-keyword-spacing") {
override fun visit(
node: ASTNode,
autoCorrect: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import com.pinterest.ktlint.core.ast.upsertWhitespaceAfterMe
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafElement

public class FunctionReturnTypeSpacingRule : Rule("function-return-type-spacing") {
public class FunctionReturnTypeSpacingRule : Rule("$experimentalRulesetId:function-return-type-spacing") {
override fun visit(
node: ASTNode,
autoCorrect: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement
/**
* Lints and formats the spacing after the fun keyword
*/
public class FunctionStartOfBodySpacingRule : Rule("function-start-of-body-spacing") {
public class FunctionStartOfBodySpacingRule : Rule("$experimentalRulesetId:function-start-of-body-spacing") {
override fun visit(
node: ASTNode,
autoCorrect: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import com.pinterest.ktlint.core.ast.ElementType.WHITE_SPACE
import com.pinterest.ktlint.core.ast.nextSibling
import org.jetbrains.kotlin.com.intellij.lang.ASTNode

public class FunctionTypeReferenceSpacingRule : Rule("function-type-reference-spacing") {
public class FunctionTypeReferenceSpacingRule : Rule("$experimentalRulesetId:function-type-reference-spacing") {
override fun visit(
node: ASTNode,
autoCorrect: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement
*/
@OptIn(FeatureInAlphaState::class)
public class KdocWrappingRule :
Rule("kdoc-wrapping"),
Rule("$experimentalRulesetId:kdoc-wrapping"),
UsesEditorConfigProperties {
override val editorConfigProperties: List<UsesEditorConfigProperties.EditorConfigProperty<*>> =
listOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement
/**
* Lint and format the spacing between the modifiers in and after the last modifier in a modifier list.
*/
public class ModifierListSpacingRule : Rule("modifier-list-spacing") {
public class ModifierListSpacingRule : Rule("$experimentalRulesetId:modifier-list-spacing") {
override fun visit(
node: ASTNode,
autoCorrect: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import org.jetbrains.kotlin.psi.psiUtil.leaves
*
* TODO: if, for, when branch, do, while
*/
class MultiLineIfElseRule : Rule("multiline-if-else") {
class MultiLineIfElseRule : Rule("$experimentalRulesetId:multiline-if-else") {

override fun visit(
node: ASTNode,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ import org.jetbrains.kotlin.com.intellij.lang.ASTNode
import org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace
import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement

class NoEmptyFirstLineInMethodBlockRule : Rule("no-empty-first-line-in-method-block") {

class NoEmptyFirstLineInMethodBlockRule : Rule("$experimentalRulesetId:no-empty-first-line-in-method-block") {
override fun visit(
node: ASTNode,
autoCorrect: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import com.pinterest.ktlint.core.ast.prevLeaf
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement

public class NullableTypeSpacingRule : Rule("nullable-type-spacing") {
public class NullableTypeSpacingRule : Rule("$experimentalRulesetId:nullable-type-spacing") {
override fun visit(
node: ASTNode,
autoCorrect: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import com.pinterest.ktlint.core.ast.ElementType.PACKAGE_DIRECTIVE
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
import org.jetbrains.kotlin.psi.KtPackageDirective

class PackageNameRule : Rule("package-name") {

class PackageNameRule : Rule("$experimentalRulesetId:package-name") {
override fun visit(
node: ASTNode,
autoCorrect: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement
* comma's and colons. However, it does have a more complete view on the higher concept of the parameter-list without
* interfering of the parameter-list-wrapping rule.
*/
public class ParameterListSpacingRule : Rule("parameter-list-spacing") {
public class ParameterListSpacingRule : Rule("$experimentalRulesetId:parameter-list-spacing") {
override fun visit(
node: ASTNode,
autoCorrect: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import com.pinterest.ktlint.core.ast.prevLeaf
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafElement

class SpacingAroundAngleBracketsRule : Rule("spacing-around-angle-brackets") {
class SpacingAroundAngleBracketsRule : Rule("$experimentalRulesetId:spacing-around-angle-brackets") {
private fun String.trimBeforeLastLine() = this.substring(this.lastIndexOf('\n'))

override fun visit(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ import org.jetbrains.kotlin.com.intellij.lang.ASTNode
import org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace
import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement

class SpacingAroundDoubleColonRule : Rule("double-colon-spacing") {

class SpacingAroundDoubleColonRule : Rule("$experimentalRulesetId:double-colon-spacing") {
override fun visit(
node: ASTNode,
autoCorrect: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ import org.jetbrains.kotlin.com.intellij.lang.ASTNode
*
* @see [Kotlin Style Guide](https://kotlinlang.org/docs/reference/coding-conventions.html#horizontal-whitespace)
*/
class SpacingAroundUnaryOperatorRule : Rule("unary-op-spacing") {

class SpacingAroundUnaryOperatorRule : Rule("$experimentalRulesetId:unary-op-spacing") {
override fun visit(
node: ASTNode,
autoCorrect: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ import org.jetbrains.kotlin.psi.psiUtil.prevLeafs
/**
* @see https://youtrack.jetbrains.com/issue/KT-35106
*/
class SpacingBetweenDeclarationsWithAnnotationsRule : Rule("spacing-between-declarations-with-annotations") {

class SpacingBetweenDeclarationsWithAnnotationsRule : Rule("$experimentalRulesetId:spacing-between-declarations-with-annotations") {
override fun visit(
node: ASTNode,
autoCorrect: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ import org.jetbrains.kotlin.psi.psiUtil.startOffset
/**
* @see https://youtrack.jetbrains.com/issue/KT-35088
*/
class SpacingBetweenDeclarationsWithCommentsRule : Rule("spacing-between-declarations-with-comments") {

class SpacingBetweenDeclarationsWithCommentsRule : Rule("$experimentalRulesetId:spacing-between-declarations-with-comments") {
override fun visit(
node: ASTNode,
autoCorrect: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import com.pinterest.ktlint.core.ast.ElementType.WHITE_SPACE
import com.pinterest.ktlint.core.ast.nextSibling
import org.jetbrains.kotlin.com.intellij.lang.ASTNode

public class SpacingBetweenFunctionNameAndOpeningParenthesisRule : Rule("spacing-between-function-name-and-opening-parenthesis") {
public class SpacingBetweenFunctionNameAndOpeningParenthesisRule : Rule("$experimentalRulesetId:spacing-between-function-name-and-opening-parenthesis") {
override fun visit(
node: ASTNode,
autoCorrect: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import org.jetbrains.kotlin.com.intellij.lang.ASTNode
/**
* Lints and formats the spacing before and after the angle brackets of a type argument list.
*/
public class TypeArgumentListSpacingRule : Rule("type-argument-list-spacing") {
public class TypeArgumentListSpacingRule : Rule("$experimentalRulesetId:type-argument-list-spacing") {
override fun visit(
node: ASTNode,
autoCorrect: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement
/**
* Lints and formats the spacing before and after the angle brackets of a type parameter list.
*/
public class TypeParameterListSpacingRule : Rule("type-parameter-list-spacing") {
public class TypeParameterListSpacingRule : Rule("$experimentalRulesetId:type-parameter-list-spacing") {
override fun visit(
node: ASTNode,
autoCorrect: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import org.jetbrains.kotlin.com.intellij.lang.ASTNode
/**
* Ensures there are no unnecessary parentheses before a trailing lambda.
*/
class UnnecessaryParenthesesBeforeTrailingLambdaRule : Rule("unnecessary-parentheses-before-trailing-lambda") {
class UnnecessaryParenthesesBeforeTrailingLambdaRule : Rule("$experimentalRulesetId:unnecessary-parentheses-before-trailing-lambda") {
override fun visit(
node: ASTNode,
autoCorrect: Boolean,
Expand Down
Loading