autonomousapps / autonomousapps/dependency-analysis-gradle-plugin

Incorrect advice to change dependency from implementation to api

Open
#1,118 7 comments 0 reactions 0 assignees View on GitHub
bug help wanted toolchain:android toolchain:kotlin
Dominant language
Kotlin
Stars
2.2k
Forks
158
Avg merge
16h 25m
Merged PRs (30d)
46

Description

**Plugin version**
"1.29.0"

**Gradle version**
Gradle-8.2

**JDK version**
openjdk version "17" 2021-09-14
OpenJDK Runtime Environment (build 17+35-2724)
OpenJDK 64-Bit Server VM (build 17+35-2724, mixed mode, sharing)

**(Optional) Kotlin and Kotlin Gradle Plugin (KGP) version**
"1.9.0"

**(Optional) Android Gradle Plugin (AGP) version**
8.2.0

**(Optional) `reason` output for bugs relating to incorrect advice**
```
> Task :feature:reason

----------------------------------------
You asked about the dependency 'androidx.compose.foundation:foundation-layout-android:1.6.0'.
You have been advised to change this dependency to 'api' from 'implementation'.
----------------------------------------

Shortest path from :feature to androidx.compose.foundation:foundation-layout-android:1.6.0 for debugCompileClasspath:
:feature
\--- androidx.compose.foundation:foundation-layout-android:1.6.0

Source: debug, main
-------------------
* Exposes 1 class: androidx.compose.foundation.layout.BoxScope (implies api).
```

**Describe the bug**
As per this article: https://dev.to/autonomousapps/dependency-analysis-gradle-plugin-what-s-an-abi-3l2h this plugin uses application binary interface as a source of advices. Unfortunately, compiler can add some optimizations, such as cache for lambdas:
```
@Lkotlin/Metadata;
public final class com/github/dependency/analysis/feature/ComposableSingletons$FeatureElementKt {
public static final field INSTANCE Lcom/github/dependency/analysis/feature/ComposableSingletons$FeatureElementKt;
public static field lambda-1 Lkotlin/jvm/functions/Function3;
public fun ()V
public final fun getLambda-1$feature_debug ()Lkotlin/jvm/functions/Function3;
}
```
And due to these transformations it is possible, that some classes will be treated as exposed (`BoxScope` from steps to reproduce section), but in fact they are not a part of actual public module API.

**To Reproduce**
Steps to reproduce the behavior:
1) Create library module, for example `uikit` with compose elements for android development.
```
@Composable
fun BaseFooter(subContent: @Composable BoxScope.() -> Unit) {
Box(modifier = Modifier.fillMaxSize()) {
subContent()
}
Text(text = "footer")
}
```
It exposes `BoxScope`, hence has `api("androidx.compose.foundation:foundation-layout-android")`
2) Create `feature` module and use `uikit` as a dependency:
```
@Composable
fun FeatureElement(text: String) {
Text(text = text)
// It triggers incorrect api suggestion due to cached lambda
BaseFooter {}
// This variant pass without any advice
// val someString = remember { "text" }
// BaseFooter { println(someString) }
}
```
This module doesn't expose BoxScope directly, just uses it internally, but plugin treats it as public usage.

**Expected behavior**
Plugin shouldn't advice to change from `implementation("androidx.compose.foundation:foundation-layout-android")` to `api("androidx.compose.foundation:foundation-layout-android")` for `feature` module.

**Additional context**
Test project: [DependencyAnalysisTest.zip](https://github.com/autonomousapps/dependency-analysis-gradle-plugin/files/14112408/DependencyAnalysisTest.zip) (don't forget to add `local.properties` with `sdk.dir=YOUR_PATH`)

Launch the `projectHealth` task for `feature` module
```
./gradlew :feature:projectHealth --no-configuration-cache
```
and check reason:
```
./gradlew :feature:reason --no-configuration-cache --id androidx.compose.foundation:foundation-layout-android
```

Contributor guide

Open the contributing guide

Research direction

Start with the attached DependencyAnalysisTest.zip and run :feature:projectHealth, followed by :feature:reason --no-configuration-cache --id androidx.compose.foundation:foundation-layout-android. Compare the reason output for the BaseFooter and FeatureElement reproduction with the expected dependency advice; done when the feature module is no longer advised to change implementation to api.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, kotlin
Domain
build-system, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.