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

Add support for fallback property #3675

Merged
merged 9 commits into from
May 7, 2021

Conversation

marschwar
Copy link
Contributor

@marschwar marschwar commented Apr 11, 2021

This PR relates to #3670 and adds support for annotated properties that have been renamed. Example:

without annotation

    private val functionThreshold: Int =
        valueOrDefault(FUNCTION_THRESHOLD, valueOrDefault(THRESHOLD, DEFAULT_FUNCTION_THRESHOLD))

with annotation

    private val functionThreshold: Int  by fallbackConfig(
        fallbackProperty = "threshold", 
        defaultValue = DEFAULT_FUNCTION_THRESHOLD
    )

@marschwar marschwar force-pushed the fallback-config-property branch from 6255a2a to 7526a32 Compare April 11, 2021 18:14
@codecov
Copy link

codecov bot commented Apr 11, 2021

Codecov Report

Merging #3675 (d3395c3) into main (50b453b) will increase coverage by 0.01%.
The diff coverage is 74.41%.

❗ Current head d3395c3 differs from pull request most recent head d6fef86. Consider uploading reports for the commit d6fef86 to get more accurate results
Impacted file tree graph

@@             Coverage Diff              @@
##               main    #3675      +/-   ##
============================================
+ Coverage     78.04%   78.05%   +0.01%     
- Complexity     2883     2891       +8     
============================================
  Files           473      473              
  Lines          9300     9329      +29     
  Branches       1767     1785      +18     
============================================
+ Hits           7258     7282      +24     
+ Misses         1078     1076       -2     
- Partials        964      971       +7     
Impacted Files Coverage Δ Complexity Δ
...ekt/generator/collection/ConfigurationCollector.kt 73.03% <70.37%> (+2.44%) 28.00 <11.00> (+8.00)
...b/arturbosch/detekt/api/internal/ConfigProperty.kt 83.33% <81.25%> (+3.33%) 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 50b453b...d6fef86. Read the comment docs.

SimpleConfigProperty(defaultValue)

fun <T : Any> fallbackConfig(fallbackProperty: String, defaultValue: T): ReadOnlyProperty<ConfigAware, T> =
Copy link
Member

Choose a reason for hiding this comment

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

A wild idea: Could we use ReadOnlyProperty<ConfigAware, T> as the type of fallbackProperty? This can help us guarantee that there is no typo to be made as String.

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 played around with this idea, but I don't see how that would be possible. The concern of having a typo is very valid IMO so I added a check in the config collector.

@marschwar marschwar force-pushed the fallback-config-property branch from 233fc73 to 7eee539 Compare May 1, 2021 13:21
@cortinico
Copy link
Member

    private val functionThreshold: Int  by fallbackConfig(
        fallbackProperty = "threshold", 
        defaultValue = DEFAULT_FUNCTION_THRESHOLD
    )

I came a bit late to the party but I have a couple of (maybe dumb) questions here:

  1. Could we implement this as an property for config with default value (either null or ""):
fun config(fallback: String = "", defaultValue: String): ReadOnlyProperty<ConfigAware, String> = simpleConfig(fallback, defaultValue)
  1. If 1. is not an option, could we call the delegate function configWithFallback? I think it's going to be more discoverable (especially for autocompletion and similar) and it brings more context on what the delegate is actually doing.

@marschwar
Copy link
Contributor Author

I like the suggestion from @chao2zhang to give the each config delegate its own name so we don't just have the same function overloaded multiple times.

When it comes to naming I am open for anything. I understand the reasoning and like your suggestion. What would you call the delegate that expects a List to be configured?

config            -> config
fallbackConfig    -> configWithFallback
listConfig        -> ??? configOfList ???

@cortinico
Copy link
Member

What would you call the delegate that expects a List to be configured?

How about configList?

return checkNotNull(defaultArgument.getArgumentExpression())
}

private object ConfigWithFallbackSupport {
Copy link
Member

Choose a reason for hiding this comment

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

Today I learned: We can define a non-companion object inside a class.

@BraisGabin
Copy link
Member

Why do we need configList? Isn't enought to use config? And, if we need configWithFallback don't we need configListWithFallback too? I'd vote for an unified delegate config.

@marschwar
Copy link
Contributor Author

I agree that the differenciation between config and configList is a bit awkward. Let me see if there is something that can be done.

@marschwar
Copy link
Contributor Author

If this is something we can agree on, I would clean up and add more tests.

is Boolean,
is Int,
is Long -> configAware.valueOrDefault(propertyName, defaultValue)
else -> error("${defaultValue.javaClass} is not supported as ")
Copy link
Member

Choose a reason for hiding this comment

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

Maybe using the code from here: #3676 (comment) we could make this more type safe.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The problem here is, that fun <T : Any> config(defaultValue: T): ReadOnlyProperty<ConfigAware, T> removes most of the type safety since a rule author could write val prop: Regex by config(Regex("aaa")) which would compile but fail at runtime. With the code from this PR it is more explicit and we can provide a specific error message if the provided type is not supported.

Copy link
Member

@BraisGabin BraisGabin May 3, 2021

Choose a reason for hiding this comment

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

If we want that type of security (I agree with it). We could add a config file for each type. This way we ensure even more the type safety.

@BraisGabin
Copy link
Member

If this is something we can agree on, I would clean up and add more tests.

I think that the API looks nice :)

@BraisGabin
Copy link
Member

This looks fine now. We can iterate later if we want.

@marschwar
Copy link
Contributor Author

Is there anything I can do to help getting this merged?

@BraisGabin BraisGabin merged commit 7cc0c9d into detekt:main May 7, 2021
@marschwar marschwar deleted the fallback-config-property branch May 8, 2021 16:19
@cortinico cortinico added this to the 1.17.0 milestone May 12, 2021
chao2zhang pushed a commit to chao2zhang/detekt that referenced this pull request May 13, 2021
* Add support for fallback property

* Introduce listConfig and fallbackConfig

* Verify that the configured fallback property exists

* replace config with listConfig where appropriate

* rename fallbackConfig -> configWithFallback

* rename parameter fallbackProperty -> fallbackPropertyName

* Integrate configList into SimpleConfigProperty and FallbackConfigProperty

* Improve error handling and add tests

* Inline values to pass custom checks

Co-authored-by: Markus Schwarz <post@markus-schwarz.net>
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.

4 participants