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

Added validation of constructors to LongParameterList #2410

Merged
merged 1 commit into from
Mar 23, 2020

Conversation

r4zzz4k
Copy link
Contributor

@r4zzz4k r4zzz4k commented Mar 5, 2020

I've looked through existing rules, seems that nothing covers number of parameters in contructors. LongParameterList is the nearest thing, but it covers only methods.

Does this sound like a useful rule? In discussions over the Internet on argument count limit I mostly see costructors included. Checkstyle, for example, covers both methods and parameters, PMD seems to agree on that.

After adding this plugin ./gradlew detekt starts failing on the project, as some classes (e.g. CorrectableCodeSmell, see below) have 6 or more parameters in constructors.

https://github.com/arturbosch/detekt/blob/521e96856d841ec8c115a12f2db8230ce01eda86/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/CodeSmell.kt#L44-L51

I'll try to collect proper report, as right now I'm having troubles with it (#2411).

Copy link
Member

@schalkms schalkms left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for contributing to detekt. This is a good idea.
I'd put this in a separate rule, since users may want to have different configuration settings for the max parameter number.

@r4zzz4k
Copy link
Contributor Author

r4zzz4k commented Mar 5, 2020 via email

@r4zzz4k r4zzz4k force-pushed the long-param-list-ctors branch from 96183ff to 28726f9 Compare March 6, 2020 13:54
@r4zzz4k
Copy link
Contributor Author

r4zzz4k commented Mar 6, 2020

I'm playing with it for some time and don't like both abstract parent for two rules (pushed above) and code duplication without it.

Does adding new configuration parameter like constructorThreshold to existing rule sound viable? With default value like -1 or 255 meaning "don't validate constructors".

I'm open to any other suggestions, of course.

@schalkms
Copy link
Member

schalkms commented Mar 6, 2020

For me this PR looks good. Please fix the issues detected issues and regenerate the documentation for detekt's homepage. Then we'll proceed with merging this PR.

@arturbosch
Copy link
Member

Both approaches have advantages:

  1. own rule:
  • clear separation of concerns
  • does not interfere with current config properties of LongParameterList
  1. extending LongParameterList
  • pmd and checkstyle have just one rule for both cases
  • co-location of properties (constructorThreshold, functionThreshold, threshold)
  • two similar rule names: LongParameterList and LongConstructorParameterList; I would prefer deprecating LongParameterList then and build extra logic for a LongFunctionParameterList.

I'm OK with both approaches but would prefer a property constructorThreshold for LPL with a default -1 value.

@BraisGabin
Copy link
Member

Why the -1 as default? It doesn't seem like a good default value. If the reason is to avoid "BC" I consider this a bug fix more than a new feature.

If we go to LongParameterList we should deprecate threshold and add constructorThreshold and functionThreshold. I did this before to have a reference: #2132

@r4zzz4k
Copy link
Contributor Author

r4zzz4k commented Mar 10, 2020

Thanks for the reference! Proper deprecation and splitting property into two seems much nicer than -1.
I'll try that one out, as I'm also leaning to single rule instead of two different, but very similar ones.

Hoping to get back to that in the nearest future.

@schalkms
Copy link
Member

schalkms commented Mar 10, 2020

I don’t think it’s wise to use -1 as a default value.

@r4zzz4k r4zzz4k force-pushed the long-param-list-ctors branch from 28726f9 to 9c69ab9 Compare March 22, 2020 14:21
@r4zzz4k r4zzz4k requested a review from schalkms March 22, 2020 14:21
@r4zzz4k
Copy link
Contributor Author

r4zzz4k commented Mar 22, 2020

I've went with splitting configuration option in two as this was the most discussed option here. I've also added option to ignore data classes as these value bags are a kinda separate thing in my opinion. So one may want to both validate and not validate them to their liking.

I guess CONTRIBUTING.md should note that update of both both documentation and default-detekt-config.yml can be done via generateDocumentation Gradle task as this is not quite obvious. But of course build covers that, so I'm not sure if this is actually important for contributors.

Looking forward to your opinions on the PR.

Copy link
Member

@schalkms schalkms left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! That PR looks awesome!
I have two found one minor improvement regarding the documentation.

Concerning the Contributing guide, if you find something missing we would be really grateful for a PR that improves the docs. For experienced contributors it's hard to always know which documentation 1st time contributors need.

import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtParameterList
import org.jetbrains.kotlin.psi.KtPrimaryConstructor
import org.jetbrains.kotlin.psi.KtSecondaryConstructor

/**
* Reports functions which have more parameters than a certain threshold (default: 6).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Reports functions which have more parameters than a certain threshold (default: 6).
* Reports functions and constructors which have more parameters than a certain threshold.

validateConstructor(constructor)
}

private fun <T : KtConstructor<T>> validateConstructor(constructor: KtConstructor<T>) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry, I don't understand why this function needs generics.
Does the following function declaration also suffice?

Suggested change
private fun <T : KtConstructor<T>> validateConstructor(constructor: KtConstructor<T>) {
private fun validateConstructor(constructor: KtFunction) {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've just taken least common denominator of two types, which happens to have generic parameter. More generic KtFunction should work, will check.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.getContainingClassOrObject() is a method of KtConstructor, so it's not available on KtFunction, but if star-projected type is okay, that's more than enough for this.

}

it("does not report short parameter list for secondary constructors") {
val code = "class LongCtor() { constructor(a: Int, b: Int, c: Int, d: Int, e: Int, f: Int) }"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

@arturbosch arturbosch added this to the 1.8.0 milestone Mar 22, 2020
@schalkms
Copy link
Member

@r4zzz4k your implemented rule already found a code smell in detekt itself 😉
The rest builds fine. Thank you. Good job! 💪

Ruleset: complexity - 20min debt
4443	LongParameterList - 7/7 - [DslGradleRunner] at /home/travis/build/arturbosch/detekt/detekt-gradle-plugin/src/test/kotlin/io/gitlab/arturbosch/detekt/DslGradleRunner.kt:8:22

@r4zzz4k
Copy link
Contributor Author

r4zzz4k commented Mar 22, 2020

I'm not hundred percent sure about defaults, so it may need some tuning in future. Hoping we would be able to gather some valuable feedback on this in future.

Anyway, great that my contribution is useful to someone besides me. Thank you :) And thanks for your hard work on the project, it really changes the way one works on their codebase in a very positive way!

@arturbosch
Copy link
Member

Please suppress the issue for now so we can move merging this awesome PR :)

* Validated parameter count of primary and secondary constructors
* Added flag to ignore data classes as parameter count of these
  arguably doesn't highlight violation of SRP
* Deprecated threshold in favor of functionThreshold and constructorThreshold
* Suppressed found issue in existing code
@r4zzz4k r4zzz4k force-pushed the long-param-list-ctors branch from 1f296f3 to e9f90f7 Compare March 22, 2020 20:56
@codecov-io
Copy link

codecov-io commented Mar 22, 2020

Codecov Report

Merging #2410 into master will decrease coverage by 0.00%.
The diff coverage is 85.71%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master    #2410      +/-   ##
============================================
- Coverage     83.26%   83.26%   -0.01%     
- Complexity     2198     2204       +6     
============================================
  Files           360      360              
  Lines          6240     6250      +10     
  Branches       1144     1146       +2     
============================================
+ Hits           5196     5204       +8     
  Misses          466      466              
- Partials        578      580       +2     
Impacted Files Coverage Δ Complexity Δ
...bosch/detekt/rules/complexity/LongParameterList.kt 83.33% <84.61%> (-2.39%) 15.00 <7.00> (+6.00) ⬇️
...ch/detekt/api/internal/ValidatableConfiguration.kt 100.00% <100.00%> (ø) 0.00 <0.00> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update fbfcabf...e9f90f7. Read the comment docs.

@r4zzz4k
Copy link
Contributor Author

r4zzz4k commented Mar 22, 2020

Should I roll back rebasing or this is okay?

@schalkms
Copy link
Member

@r4zzz4k this is okay. The failing AppVeyor build is not related to your change. Everything's fine.

@arturbosch arturbosch merged commit 184eaa8 into detekt:master Mar 23, 2020
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.

5 participants