Versions
- SonarScanner for Gradle: 7.3.1.8318
- SonarQube: Community Build 26.6.0.123539 (reproduced locally)
- Android Gradle Plugin: 9.2.1
- Gradle: 9.5.1
- Kotlin: 2.3.0
- Module type: Kotlin Multiplatform (
org.jetbrains.kotlin.multiplatform) with anandroidTarget()producing an AAR via the Android Library plugin (com.android.library) +org.jetbrains.compose. Source sets:commonMain,androidMain,androidUnitTest(plusjvmMain/iosMain/wasmJsMain).
Summary
For KMP modules that have an Android target, the scanner registers each Android-specific source set into sonar.sources/sonar.tests twice, once via the Kotlin source set and once via the Android variant’s source provider. The duplicate directory aborts analysis with:
File <module>/src/androidUnitTest/kotlin/.../SomeTest.kt can't be indexed twice.
Please check that inclusion/exclusion patterns produce disjoint sets for main and test files
The scanner’s own per-module output shows the duplicate directly:
Indexing files of module 'neem'
Base dir: .../design-system/neem
Source paths: src/androidMain/kotlin, src/commonMain/kotlin, src/iosMain/...
Test paths: src/androidUnitTest/kotlin, src/androidUnitTest/kotlin <- same dir listed twice
androidMain is likewise duplicated in Source paths, producing the same error for main source files (e.g. androidMain/.../PlatformNativeToast.android.kt), not just tests.
Steps to reproduce
- A multi-module Gradle build with at least one KMP module applying
org.jetbrains.kotlin.multiplatformwithandroidTarget()+com.android.library(AGP 9.2.1), containing files under bothsrc/androidMain/kotlinandsrc/androidUnitTest/kotlin. - Apply
org.sonarqube7.3.1.8318 on the root project. - Run
./gradlew assembleDebugthen./gradlew sonar. :sonarfails at the indexing phase with “can’t be indexed twice” for anandroidUnitTest(orandroidMain) file.
This appears to be scanner-side, not user misconfiguration — no sonar.sources/sonar.tests is set manually; the duplicate entries are produced entirely by the plugin’s own source-set computation.
Workarounds tried
Re-setting sonar.sources/sonar.testsper module to a de-duplicated explicit list — the value is appended, not replaced, so the directory still appears twice (the Android variant provider re-adds it).
-Dsonar.gradle.scanAll=true— no effect; the duplicate lives in the Gradle-computed source sets, whichscanAlldon’t dedupe. Analysis fails identically.
Only working workaround: per-module sonar.exclusions+sonar.test.exclusionsof**/src/androidMain/**,**/src/androidUnitTest/**,**/src/test/**. This dropsandroidMainproduction code from analysis — a real coverage loss (~5k lines of Android UI code in one module, in our case).
Expected behavior
The scanner should register each KMP Android source-set directory once in sonar.sources/sonar.tests (de-duplicate the Kotlin-source-set vs Android-variant-provider contributions). So, KMP Android modules are analysed without excluding androidMain.