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
AnnotationSuppressor now resolves Full Qualified Annotation Names without type solving #4570
Conversation
detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/AnnotationExcluder.kt
Show resolved
Hide resolved
c42310a
to
fcb3f23
Compare
fcb3f23
to
1db1b8e
Compare
1db1b8e
to
320a26e
Compare
Codecov Report
@@ Coverage Diff @@
## main #4570 +/- ##
===========================================
+ Coverage 0 84.56% +84.56%
- Complexity 0 3340 +3340
===========================================
Files 0 481 +481
Lines 0 11186 +11186
Branches 0 2038 +2038
===========================================
+ Hits 0 9459 +9459
- Misses 0 697 +697
- Partials 0 1030 +1030
Continue to review full report at Codecov.
|
detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/AnnotationExcluder.kt
Show resolved
Hide resolved
detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/AnnotationExcluder.kt
Outdated
Show resolved
Hide resolved
I went through them and I lack the relevant context as I haven't really touched this part of the codebase in a while. The code looks good and well tested. Generally, I think we're good to go with the heuristic you suggested. |
detekt-psi-utils/src/test/kotlin/io/github/detekt/psi/internal/FullQualifiedNameGuesserSpec.kt
Outdated
Show resolved
Hide resolved
@@ -39,13 +39,16 @@ class FullQualifiedNameGuesser internal constructor( | |||
if (packageName != null) { | |||
add("$packageName.$name") | |||
} | |||
if (name.first().isLowerCase()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the reason for this check?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For that reason we use a heuristic here: If the first character is lower case we assume it's a package name. Therefore I think this is to handle cases like dagger\..*
. First uppercase indicates a class name and Component\..*
would not be a valid case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry @schalkms, I didn't see this comment before.
Yes the reason was that heuristic... but now that I think about that I'm not sure if this class needs to know about this. We could assume that any string that we can't match with an import could be a FullQualifiedName. But I don't know if that's better or worse... That's the issue with this mixed behaviour. The "general use cases" are easy to manage but all this edge cases are really difficult to manage because we can't know for sure.
The drawback of having this mixed implementation for enabled and disabled type resolution is the complexity of the code. However, for now, I don't know a better solution. |
Agree. This approach will lead to significant maintenance if for every rule or feature that's improved by using type resolution we have to also support users who choose not to use type resolution. Is the real issue that type resolution is too difficult to use correctly? What can we do here to avoid introducing this complexity to our code? |
As far as I know the main issue is the performance. We should rework our gradle plugin to make it type solve first. |
This ☝️ . We have users running detekt on pre-commit hooks. Enabling TR for them is a no-go as they'll end up impacting the development loop for a lot of engineers. I think we should keep the current feature set for non-TR enabled project and add new features that are working with TR only. The problem in this PR/Linked issues was that, by implementing a more advanced annotation suppressor, we actually broke the experience for users on non-TR project. |
Anything missing from this PR? I'd like to kickoff a RC1 as soon as this is merged 👍 |
This is ready to merge for me. But, is this a notable change or just a bug fix? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm! Thank you for adding those test cases and that really helped me to understand
detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/AnnotationExcluder.kt
Show resolved
Hide resolved
@@ -39,13 +39,16 @@ class FullQualifiedNameGuesser internal constructor( | |||
if (packageName != null) { | |||
add("$packageName.$name") | |||
} | |||
if (name.first().isLowerCase()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For that reason we use a heuristic here: If the first character is lower case we assume it's a package name. Therefore I think this is to handle cases like dagger\..*
. First uppercase indicates a class name and Component\..*
would not be a valid case.
detekt-api/src/test/kotlin/io/gitlab/arturbosch/detekt/api/AnnotationExcluderSpec.kt
Show resolved
Hide resolved
…/FullQualifiedNameGuesserSpec.kt Co-authored-by: M Schalk <30376729+schalkms@users.noreply.github.com>
9638d52
to
30ce1c7
Compare
It's a notable change that we fixed a regression in the latest stable (imho this would have been point-release worthy, we skipped that so let's at least mention this on top of the release notes). |
This was way more difficult than I expected. Please, review this PR commit by commit.
The more complex type of annotations are like this
@com.dagger.Component.Factory
. We have a part that is package and another part that are class names. But it's not clear when one ends and one the other ends. This is importan because when we find for matches for this type of annotations we should allow:@com.dagger.Component.Factory
@Component.Factory
ifimport com.dagger.Component is present
@Factory
ifimport com.dagger.Component.Factory is present
But we should not allow
@dagger.Component.Factory
, because that's another annotation different. It can't be@com.dagger.Component.Factory
. All this cases is what makes this code complex and that force me to have all those tests.fixes #4355
fixes #4356