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

Refactor life cycle hooks on Rule #1547

Merged
merged 58 commits into from Jul 17, 2022

Conversation

paul-dingemans
Copy link
Collaborator

Description

Up until ktlint 0.46 the Rule class provided only one life cycle hook. This "visit" hook was called in a depth-first-approach on all nodes in the file. A rule like the IndentationRule used the RunOnRootOnly visitor modifier to call this lifecycle hook for the root node only in combination with an alternative way of traversing the ASTNodes. Downside of this approach was that suppression of the rule on blocks inside a file was not possible (#631). More generically, this applied to all rules, applying alternative traversals of the AST.

The Rule class now offers new life cycle hooks:

  • beforeFirstNode: This method is called once before the first node is visited. It can be used to initialize the state of the rule before processing of nodes starts. The ".editorconfig" properties (including overrides) are provided as parameter.
  • beforeVisitChildNodes: This method is called on a node in AST before visiting its child nodes. This is repeated recursively for the child nodes resulting in a depth first traversal of the AST. This method is the equivalent of the "visit" life cycle hooks. However, note that in KtLint 0.48, the UserData of the rootnode no longer provides access to the ".editorconfig" properties. This method can be used to emit Lint Violations and to autocorrect if applicable.
  • afterVisitChildNodes: This method is called on a node in AST after all its child nodes have been visited. This method can be used to emit Lint Violations and to autocorrect if applicable.
  • afterLastNode: This method is called once after the last node in the AST is visited. It can be used for teardown of the state of the rule.

The "visit" life cycle hook will be removed in Ktlint 0.48. In KtLint 0.47 the "visit" life cycle hook will be called only when hook "beforeVisitChildNodes" is not overridden. It is recommended to migrate to the new lifecycle hooks in KtLint 0.47. Please create an issue, in case you need additional assistence to implement the new life cycle hooks in your rules.

Closes #631

Checklist

  • PR description added
  • tests are added
  • CHANGELOG.md is updated

In case of adding a new rule:

  • README.md is updated
  • Rule has been applied on Ktlint itself and violations are fixed

Despite the name, the concurrent visitor is not faster than the sequential visitor as each file is processed on a single thread. There seem to be no other benefits for having two different visitor providers.
This eliminates some inconsistencies and improves readability.
…from VisitorProvider to Ktlint

The visitor provider is only responsible for running the relevant rules in the correct order. On which node is to be executed is not relevant.
…y default, the root node (e.g. the node with ElementType FILE) can not be suppressed. A '@file:Suppress' annotation on top of the file is already contained in a non-root node.
…isitChildNodes and afterLastNode and deprecating visit.

Rules no longer should implement their custom AST traversal in case processing is required after child nodes have been processed.
…Rule as this is the responsibility of the IndentationRule
…gRule as this is the responsibility of the IndentationRule
Replace generic visit method from "package.kt" with private as the visit should not be used in rules as it breaks the possibility to suppress rules on certain location. But this visit method does not have this side effect when used in the SuppressionLocator itself.
This visitor modifier was typically used to run a custom node visit algorithm using the root node
and the generic "package.visit" methods. The "package.visit" method however did not support
rule suppression. With the new lifecycle hooks on the Rule class the visit modifier has become
obsolete.
Prepare to remove ".editorconfig" properties from the UserData in ktlint 0.48. Those properties are only required on the root node but the "getUserData" method can be called on any node. The new Rule lifecycle hooks "beforeFirstNode" provides the ".editorconfig" properties directly to the rule. This contract is cleaner and more explicit.
…perties.getEditorConfigValue" by using the Rule "beforeFirstNode" lifecycle hook
Despite the name, the concurrent visitor is not faster than the sequential visitor as each file is processed on a single thread. There seem to be no other benefits for having two different visitor providers.
This eliminates some inconsistencies and improves readability.
…from VisitorProvider to Ktlint

The visitor provider is only responsible for running the relevant rules in the correct order. On which node is to be executed is not relevant.
…y default, the root node (e.g. the node with ElementType FILE) can not be suppressed. A '@file:Suppress' annotation on top of the file is already contained in a non-root node.
…isitChildNodes and afterLastNode and deprecating visit.

Rules no longer should implement their custom AST traversal in case processing is required after child nodes have been processed.
…Rule as this is the responsibility of the IndentationRule
…gRule as this is the responsibility of the IndentationRule
Replace generic visit method from "package.kt" with private as the visit should not be used in rules as it breaks the possibility to suppress rules on certain location. But this visit method does not have this side effect when used in the SuppressionLocator itself.
This visitor modifier was typically used to run a custom node visit algorithm using the root node
and the generic "package.visit" methods. The "package.visit" method however did not support
rule suppression. With the new lifecycle hooks on the Rule class the visit modifier has become
obsolete.
Prepare to remove ".editorconfig" properties from the UserData in ktlint 0.48. Those properties are only required on the root node but the "getUserData" method can be called on any node. The new Rule lifecycle hooks "beforeFirstNode" provides the ".editorconfig" properties directly to the rule. This contract is cleaner and more explicit.
…perties.getEditorConfigValue" by using the Rule "beforeFirstNode" lifecycle hook
…rovider

# Conflicts:
#	ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/KtLint.kt
#	ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/KtLintTest.kt
@paul-dingemans paul-dingemans merged commit df43622 into pinterest:master Jul 17, 2022
@paul-dingemans paul-dingemans deleted the visitor-provider branch July 17, 2022 19:55
@paul-dingemans paul-dingemans added this to the 0.47.0 milestone Jul 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Indent rule cannot be suppressed via ktlint-disable directives in the middle of a file.
1 participant