Comments (4)
Looking at the exact offset (3:46
), it is the elvis operator (or more precise the code leaf after the annotated expression) which is to be pushed to the next line. So the expected format is:
private fun getErrorMessage(value: String): String =
@Suppress("DEPRECATION")
customMessage.takeUnless { it.isEmpty() }
?: String.format(DEFAULT_ERROR_MESSAGE_WITH_NO_REASON, value)
When analyzing with the PsiViewer plugin in IntelliJ, it is clear that the ANNOTATED_EXPRESSION is following only:
@Suppress("DEPRECATION")
customMessage.takeUnless { it.isEmpty() }
The reasoning that default IntelliJ formatter accepts this format is less relevant as the format provided by Ktlint is also accepted by IntelliJ formatter. If the Ktlint format would not be accepted by IntelliJ formatter then the argument would be valid.
I am not sure whether this is an unintended side effect or intended behavior but I tend to the latter.
from ktlint.
Would the same be true without the annotation present? i.e. the elvis should be on a new line. What really confused me is the "new line expected" from the "annotation" rule, when the annotation looked ok.
İs there any way to report the message or location in this case? Or maybe just add this example to the docs, because we checked it and it wasn't clear from the examples what is wrong with the code.
from ktlint.
I had another look and discovered a problem. This may or may not be the same problem that you encountered but the original issue does not contain enough information to check that.
In the end, it really depends on the code style what is actually happening.
When code style is not set, or when set explicitly to ktlint_official
, official
or intellij_idea
the violation is what I reported before:
With .editorconfig
:
[{*.kt,*.kts}]
ktlint_standard=enabled
ktlint_experimental=enabled
the command ktlint --relative
results in
17:37:42.462 [main] INFO com.pinterest.ktlint.cli.internal.KtlintCommandLine - Enable default patterns [**/*.kt, **/*.kts]
src/main/kotlin/Foo.kt:3:46: Expected newline (standard:annotation)
Summary error count (descending) by rule:
standard:annotation: 1
The violation message and the offset are in sync and it should be clear how the code is to be fixed. With ktlint-0.49.1 --relative -F
the code is formatted as:
private fun getErrorMessage(value: String): String =
@Suppress("DEPRECATION")
customMessage.takeUnless { it.isEmpty() }
?: String.format(DEFAULT_ERROR_MESSAGE_WITH_NO_REASON, value)
When code style is set to android
or android_studio
there are more violations reported:
With .editorconfig
:
[{*.kt,*.kts}]
ktlint_code_style = android
ktlint_standard=enabled
ktlint_experimental=enabled
the command ktlint --relative
results in
17:41:39.417 [main] INFO com.pinterest.ktlint.cli.internal.KtlintCommandLine - Enable default patterns [**/*.kt, **/*.kts]
x.kts:6:97: Unnecessary trailing comma before ")" (standard:trailing-comma-on-call-site)
src/main/kotlin/Foo.kt:1:53: First line of body expression fits on same line as function signature (standard:function-signature)
src/main/kotlin/Foo.kt:3:1: Exceeded max line length (100) (standard:max-line-length)
src/main/kotlin/Foo.kt:3:31: Missing newline after "{" (standard:wrapping)
src/main/kotlin/Foo.kt:3:46: Expected newline (standard:annotation)
src/main/kotlin/Foo.kt:3:64: Argument should be on a separate line (unless all arguments can fit a single line) (standard:argument-list-wrapping)
src/main/kotlin/Foo.kt:3:102: Argument should be on a separate line (unless all arguments can fit a single line) (standard:argument-list-wrapping)
src/main/kotlin/Foo.kt:3:107: Missing newline before ")" (standard:argument-list-wrapping)
Summary error count (descending) by rule:
standard:argument-list-wrapping: 3
standard:annotation: 1
standard:function-signature: 1
standard:max-line-length: 1
standard:trailing-comma-on-call-site: 1
standard:wrapping: 1
When running format
the output changes to:
17:44:18.369 [main] INFO com.pinterest.ktlint.cli.internal.KtlintCommandLine - Enable default patterns [**/*.kt, **/*.kts]
src/main/kotlin/Foo.kt:1:53: Expected newline before annotation (standard:annotation)
Summary error count (descending) by rule:
standard:annotation: 1
This log message is rather confusing when you compare it with the original code sample. However, it should not be compared with the original but with the modified code to make sense.
and the file is formatted as:
private fun getErrorMessage(value: String): String = @Suppress("DEPRECATION")
customMessage.takeUnless { it.isEmpty() }
?: String.format(DEFAULT_ERROR_MESSAGE_WITH_NO_REASON, value)
What happened is following:
- The android code style has a default max-line-length (100)
- The first line of the body expression has been merged with the function signature as the total length of the merged line is less than the max-line-length. But in this case the body expression should not have been merged as it conflicts with another rule. I have to check whether this can be resolved.
- Once the formatting is done, KtlintRuleEngine executes a linting step. Normally this should only reveal lint errors which can not be automatically corrected. However, in this case it reveals that autocorrect has introduced a new problem. The user can however not fix this problem by manually inserting the newline before the annotated expression.
This problem can also be reproduced with other code styles by setting.editorconfig
properties that set the max line length and/or function signature rules.
Would the same be true without the annotation present? i.e. the elvis should be on a new line
Without the annotation the elvis operator is not pushed down. If pushing down would be needed in that scenario, it should be done by another rule but no such rule is in place. I know of at least one other situation (a chained method call) in which the elvis is also pushed down.
The annotation-rule pushes the elvis down to make more clear what the scope is of the annotation.
İs there any way to report the message or location in this case?
When calling the lint
or format
function on the KtlintRuleEngine
any LintError
is reported via a callback. This LintError
contains the offset (line and position) on which the error was found. Ktlint CLI uses exact this same mechanism to produce the output shown above.
Or maybe just add this example to the docs, because we checked it and it wasn't clear from the examples what is wrong with the code.
I don't think that adding this example to the docs would be helpful as the same could be said for all unit tests which are not explicitly described in the docs.
from ktlint.
Nice investigation! Thanks for the replies, all makes sense. I have two small clarification to make:
This may or may not be the same problem that you encountered but the original issue does not contain enough information to check that.
The issue is from the detekt project's CI on a PR (running ktlint via detekt's wrapper), so I think what you're looking for is:
https://github.com/detekt/detekt/blob/main/.editorconfig
Is there any way to report the message or location in this case?
This LintError contains the offset (line and position) on which the error was found.
In the screenshot you showed there's a range of characters highlighted in PSIViewer (the ANNOTATED_EXPRESSION
node), same as in GitHub which is Sarif uploaded from detekt's execution. The fact that you said "This LintError contains the offset (line and position)" made me realize that it's not ktlint highlighting that full node (which made this confusing), but detekt's wrapper.
Looking at pure ktlint output, it's actually very clear where the problem is (│
):
private fun getErrorMessage(value: String): String =
@Suppress("DEPRECATION")
customMessage.takeUnless { it.isEmpty() }│ ?: String.format(DEFAULT_ERROR_MESSAGE_WITH_NO_REASON, value)
and "Expected newline" makes perfect sense.
But detekt re-maps this single-location finding to the node that was being visited while it was emitted
(notice how the offset (_
) parameter is ignored):
https://github.com/detekt/detekt/blob/948276a8db4578b962bf24c63eee3b8548bac627/detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/FormattingRule.kt#L97
Based on:
- "Looking at the exact offset (3:46), it is the elvis operator which is to be pushed to the next line."
- "The annotation-rule pushes the elvis down to make more clear what the scope is of the annotation."
I think this issue is resolved by explanation, not a false positive, nothing to do from our report.
Based on:
- "This LintError contains the offset (line and position)"
- "detekt re-maps this single-location finding to the node that was being visited"
- "the offset parameter is ignored"
I think this explains the confusion about the message vs. location -> detekt/detekt#6105
So you can either close this, or keep it open for your other found issue.
from ktlint.
Related Issues (20)
- Suport partial formatting of code
- long type parameter cause `Expected a single space` HOT 1
- Do not report PascalCase top-level constants in property-naming rule HOT 3
- Separate constant naming rule from property-naming HOT 1
- Suggest IntelliJ config of wildcard import HOT 1
- Split `multiline-if-else` into two rules HOT 2
- Prevent possible conflict between `multiline-expression-wrapping` and `function-signature` body wrapping
- Binary operators in `!(...)` not checked for missing horizontal whitespace
- disabling rule 'no-empty-first-line-in-method-block' does not work HOT 1
- standard:kdoc - A KDoc is not allowed inside 'value_argument_list' HOT 2
- Add support for formatting a specific violation in a piece of code containing multiple violations
- Bug in Intellij IDEA plugin, multiple messages at once HOT 2
- Indentation of inheritance with parameters HOT 7
- Names for call arguments for Java classes should be in same line HOT 1
- Rule to disable usage of any class from specified package.... Example disable java.time.* in order to use kotlinx.datetime instead. HOT 2
- Can't disable value-argument/parameter-comment HOT 2
- Ignore comments in imports when formatting HOT 8
- Promote experimental rules
- operator get with lambda: incorrect error
- ktlint_function_signature_body_expression_wrapping configuration doesn't work via .editorconfig HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ktlint.