fix(gradle): resolve generated classes under AGP built-in Kotlin#9403
fix(gradle): resolve generated classes under AGP built-in Kotlin#9403michnovka wants to merge 1 commit into
Conversation
|
The tests are in |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #9403 +/- ##
============================================
- Coverage 84.72% 84.72% -0.01%
- Complexity 4486 4492 +6
============================================
Files 571 571
Lines 12423 12407 -16
Branches 2767 2767
============================================
- Hits 10526 10512 -14
+ Misses 696 694 -2
Partials 1201 1201 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Thanks to track and fix this! Does this also work for ViewBinding? For context: I wrote some tests too for similar cases (you can read context at #9331). No need to use those tests, I'm just linking for context. |
|
Yep, ViewBinding works too. Its generated class ends up on the classpath the same way BuildConfig/R do. It's actually already covered: the existing Thanks for the #9331 pointer, I'll have a look. |
|
@BraisGabin had a look at #9331, thanks for the pointer. They line up pretty nicely. This PR puts the generated classes on the analysis classpath, so it covers the AGP generated sources (BuildConfig, R, ViewBinding). #9331 runs the compiler plugins during analysis, which is what Parcelize and serialization need, and which this approach can't really do anyway since the source declaration shadows the compiled binary. So the BuildConfig and ViewBinding cases in your CompilerPluginsTests should already pass with this PR. You could probably drop those two from #9331 and just keep the Parcelize one. One heads up: we both touch Detekt, DetektCreateBaselineTask and SharedTasks, so whichever lands first the other is a quick rebase. |
|
Is there no way to achieve this without adding new parameters to the Detekt task? We shouldn't need any parameters to configure the detekt compilation task that doesn't exist on the Kotlin compilation task. |
Under AGP built-in Kotlin, detekt's type-resolution tasks (detektMain/detektDebug and the matching detektBaseline* tasks) run with an incomplete classpath: the variant's compiled generated classes (BuildConfig and other javac-compiled generated Java such as view binding) are not on the analysis classpath. detekt cannot resolve references to those generated types, logs "compiler errors found during analysis", and emits false positives from type-resolution rules such as UnusedPrivateFunction and RedundantSuspendModifier. This has been the case since built-in Kotlin support landed in detekt#9100. Put each Android variant's compiled classes onto the detekt and baseline task classpaths via Artifacts.forScope(PROJECT).use(task).toGet(ScopedArtifact.CLASSES, ...), folded into the existing classpath. AGP only exposes the compiled generated classes through ScopedArtifact.CLASSES, and its toGet requires ListProperty sinks on the consuming task, so the two sinks (generatedClassesJars/generatedClassesDirs) are kept internal. This also establishes the compile dependency so the generated classes exist when detekt runs. JVM and KMP compilations are unaffected. Add functional tests asserting detektMain and detektBaselineMain resolve generated BuildConfig, and strengthen the existing built-in-Kotlin "javac intermediates" (view binding) test, which previously only asserted doesNotContain("UnreachableCode"), a check that passes even when types are unresolved.
7c86847 to
c74d382
Compare
|
Yeah, I tried but couldn't get around it. AGP only exposes the compiled generated classes through I've made both props |
Thanks, I'd prefer that for now. |
Fixes #9402
Problem
Under AGP built-in Kotlin, the type-resolution tasks (
detektMain/detektDebugand the matchingdetektBaseline*tasks) run with an incomplete classpath: the variant's compiled generated classes (BuildConfig, and other javac-compiled generated Java like view binding) are not on the analysis classpath. So detekt can't resolve references to those generated types, logscompiler errors found during analysis, and emits false positives from type-resolution rules such asUnusedPrivateFunctionandRedundantSuspendModifier. This has been the case since built-in Kotlin support landed in #9100.The only workaround is keeping the legacy
kotlin-androidplugin plusandroid.builtInKotlin=false/android.newDsl=false, all of which are removed in AGP 10.Fix
Put each Android variant's compiled classes onto the detekt and baseline task classpaths via
Artifacts.forScope(PROJECT).use(task).toGet(ScopedArtifact.CLASSES, ...), folded into the existingclasspath. AGP only exposes the compiled generated classes throughScopedArtifact.CLASSES, and itstoGetrequiresListPropertysinks on the consuming task, so the two sinks (generatedClassesJars/generatedClassesDirs) are keptinternal. This also establishes the compile dependency so the generated classes exist when detekt runs. JVM and KMP compilations are unaffected.Tests
detektMainanddetektBaselineMainresolve generatedBuildConfig.doesNotContain("UnreachableCode"), a check that passes even when types are unresolved.Related