dependency-analysis-gradle-plugin
dependency-analysis-gradle-plugin copied to clipboard
Incorrect advice given if a type is used as type parameter of a generic type in specific scenarios
Plugin version
2.17.0
Gradle version
8.12
JDK version
21
Kotlin and Kotlin Gradle Plugin (KGP) version
2.1.20
reason output for bugs relating to incorrect advice
------------------------------------------------------------
You asked about the dependency ':moduleA'.
You have been advised to change this dependency to 'implementation' from 'api'.
------------------------------------------------------------
Shortest path from :moduleB to :moduleA for compileClasspath:
:moduleB
\--- :moduleA
Shortest path from :moduleB to :moduleA for runtimeClasspath:
:moduleB
\--- :moduleA
Shortest path from :moduleB to :moduleA for testCompileClasspath:
:moduleB
\--- :moduleA
Shortest path from :moduleB to :moduleA for testRuntimeClasspath:
:moduleB
\--- :moduleA
Source: main
------------
* Imports 1 class: de.exaring.a.Ui (implies implementation).
Source: test
------------
(no usages)
Describe the bug
We have a module that defines a Ui type:
interface Ui
And another module exposes that type by using it as a generic type parameter on a public return type, like that:
interface UiModule {
fun bindUiMap(): Map<Class<out Any>, Ui>
}
The plugin doesn't recognize Ui as being part of the public API and gives the (incorrect) advice to change the dependency from api to implementation:
Existing dependencies which should be modified to be as indicated:
implementation(project(":ui:api")) (was api)
Now the interesting part. I've investigated this further and found out that the wrong advice is only given in a very specific scenario:
- The generic type has multiple type parameters (like
MaporPairorTriple) - There is another type parameter which is itself a generic type
- That other type parameter is listed before our type in question
This is best demonstrated with a few examples:
interface UiModule {
// These trigger an incorrect advice:
fun example1(): Map<List<String>, Ui>
fun example2(): Pair<List<String>, Ui>
fun example3(): Triple<List<String>, String, Ui>
fun example4(): Triple<List<String>, List<String>, Ui>
fun example5(): Triple<List<String>, Ui, String>
fun example6(): Triple<String, List<String>, Ui>
// These don't trigger an incorrect advice:
fun example7(): Map<Ui, List<String>>
fun example8(): Map<List<String>, List<Ui>>
fun example9(): Map<String, Ui>
fun example10(): Triple<Ui, List<String>, String>
fun example11(): Triple<Ui, List<String>, Ui>
}
To Reproduce Steps to reproduce the behavior:
Here is a simple reproducer project: dagp-generics-repro.zip
Running buildHealth on this project will produce the incorrect advice with the reason output given above.
Expected behavior
The plugin should not give any advice to change the dependency to implementation, since the type is exposed in the public API via the generic type parameter.
Thank you for the report and the preliminary debugging!