Skip to content

Commit 1ab8542

Browse files
committed
Don't call a dependency overshot if it's already declared in that source set
1 parent 85de3cb commit 1ab8542

File tree

4 files changed

+134
-21
lines changed

4 files changed

+134
-21
lines changed

modulecheck-core/src/main/kotlin/modulecheck/core/context/OverShotDependencies.kt

+14-4
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ import modulecheck.parsing.gradle.ConfigurationName
2121
import modulecheck.project.ConfiguredProjectDependency
2222
import modulecheck.project.McProject
2323
import modulecheck.project.ProjectContext
24+
import modulecheck.project.toSourceSetDependency
2425
import modulecheck.utils.SafeCache
26+
import modulecheck.utils.mapToSet
27+
import modulecheck.utils.unsafeLazy
2528

2629
data class OverShotDependencies(
2730
private val delegate: SafeCache<ConfigurationName, List<OverShotDependencyFinding>>,
@@ -39,12 +42,19 @@ data class OverShotDependencies(
3942
.flatMap { unused ->
4043

4144
val unusedCpd = unused.cpd()
45+
val unusedSsd =
46+
unusedCpd.toSourceSetDependency(unused.configurationName.toSourceSetName())
4247
val unusedSourceSetName = unused.configurationName.toSourceSetName()
4348

4449
val allUsedByConfigName = unusedSourceSetName
4550
.withDownStream(project)
4651
.mapNotNull { sourceSetName ->
4752

53+
val existingDependencies by unsafeLazy {
54+
project.projectDependencies[sourceSetName]
55+
.mapToSet { it.toSourceSetDependency(sourceSetName) }
56+
}
57+
4858
val configName = sourceSetName.implementationConfig()
4959

5060
val seed = when {
@@ -69,10 +79,10 @@ data class OverShotDependencies(
6979
)
7080
}
7181
.filterNot {
72-
it.isTestFixture == unused.cpd().isTestFixture &&
73-
it.configurationName.toSourceSetName() == unused.cpd()
74-
.configurationName
75-
.toSourceSetName()
82+
83+
val asSsd = it.toSourceSetDependency(sourceSetName)
84+
85+
asSsd == unusedSsd || existingDependencies.contains(asSsd)
7686
}
7787
.firstNotNullOfOrNull { cpd ->
7888

modulecheck-core/src/main/kotlin/modulecheck/core/rule/InheritedDependencyRule.kt

+2-17
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,13 @@ import modulecheck.api.settings.ChecksSettings
2222
import modulecheck.core.InheritedDependencyFinding
2323
import modulecheck.core.context.asApiOrImplementation
2424
import modulecheck.core.internal.uses
25-
import modulecheck.parsing.gradle.ProjectPath.StringProjectPath
2625
import modulecheck.parsing.gradle.SourceSetName
2726
import modulecheck.parsing.gradle.sortedByInheritance
2827
import modulecheck.project.ConfiguredProjectDependency
2928
import modulecheck.project.McProject
29+
import modulecheck.project.SourceSetDependency
3030
import modulecheck.project.TransitiveProjectDependency
31+
import modulecheck.project.toSourceSetDependency
3132
import modulecheck.utils.flatMapToSet
3233
import modulecheck.utils.mapAsync
3334

@@ -39,22 +40,6 @@ class InheritedDependencyRule : ModuleCheckRule<InheritedDependencyFinding> {
3940

4041
override suspend fun check(project: McProject): List<InheritedDependencyFinding> {
4142

42-
data class SourceSetDependency(
43-
val sourceSetName: SourceSetName,
44-
val path: StringProjectPath,
45-
val isTestFixture: Boolean
46-
)
47-
48-
fun ConfiguredProjectDependency.toSourceSetDependency(
49-
sourceSetName: SourceSetName = configurationName.toSourceSetName(),
50-
path: StringProjectPath = this@toSourceSetDependency.path,
51-
isTestFixture: Boolean = this@toSourceSetDependency.isTestFixture
52-
) = SourceSetDependency(
53-
sourceSetName = sourceSetName,
54-
path = path,
55-
isTestFixture = isTestFixture
56-
)
57-
5843
// For each source set, the set of all module paths and whether they're test fixtures
5944
val dependencyPathCache = mutableMapOf<SourceSetName, Set<SourceSetDependency>>()
6045

modulecheck-core/src/test/kotlin/modulecheck/core/OverShotDependenciesTest.kt

+101
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,107 @@ class OverShotDependenciesTest : RunnerTest() {
815815
)
816816
}
817817

818+
// https://github.com/RBusarow/ModuleCheck/issues/520
819+
@Test
820+
fun `overshot as debugApi from invisible dependency with a visible unrelated debugApi project dependency`() {
821+
822+
val lib1 = kotlinProject(":lib1") {
823+
addKotlinSource(
824+
"""
825+
package com.modulecheck.lib1
826+
827+
open class Lib1Class
828+
""".trimIndent()
829+
)
830+
}
831+
832+
val lib2 = androidLibrary(":lib2", "com.modulecheck.lib2") {
833+
// lib1 is added as a dependency, but it's not in the build file.
834+
// This is intentional, because it mimics the behavior of a convention plugin
835+
// which adds a dependency without any visible declaration in the build file
836+
addDependency(ConfigurationName.api, lib1)
837+
838+
buildFile {
839+
"""
840+
plugins {
841+
kotlin("jvm")
842+
}
843+
844+
dependencies {
845+
debugApi(project(path = ":lib4"))
846+
}
847+
"""
848+
}
849+
addKotlinSource(
850+
"""
851+
package com.modulecheck.lib2
852+
853+
import com.modulecheck.lib1.Lib1Class
854+
855+
val clazz = Lib1Class()
856+
""".trimIndent(),
857+
SourceSetName.DEBUG
858+
)
859+
}
860+
861+
run().isSuccess shouldBe false
862+
863+
lib2.buildFile shouldHaveText """
864+
plugins {
865+
kotlin("jvm")
866+
}
867+
868+
dependencies {
869+
debugApi(project(path = ":lib1"))
870+
debugApi(project(path = ":lib4"))
871+
}
872+
"""
873+
874+
logger.parsedReport() shouldBe listOf(
875+
":lib2" to listOf(
876+
overshot(
877+
fixed = true,
878+
configuration = "debugApi",
879+
dependency = ":lib1",
880+
position = null
881+
),
882+
unusedDependency(
883+
fixed = false,
884+
configuration = "api",
885+
dependency = ":lib1",
886+
position = null
887+
)
888+
)
889+
)
890+
891+
logger.clear()
892+
893+
// this second run should not have an overshot finding, and shouldn't modify the build file
894+
run().isSuccess shouldBe false
895+
896+
lib2.buildFile shouldHaveText """
897+
plugins {
898+
kotlin("jvm")
899+
}
900+
901+
dependencies {
902+
debugApi(project(path = ":lib1"))
903+
debugApi(project(path = ":lib4"))
904+
}
905+
"""
906+
907+
logger.parsedReport() shouldBe listOf(
908+
":lib2" to listOf(
909+
unusedDependency(
910+
fixed = false,
911+
configuration = "api",
912+
dependency = ":lib1",
913+
position = null
914+
)
915+
)
916+
)
917+
}
918+
818919
@Test
819920
fun `overshot as testImplementation from invisible dependency with a visible unrelated implementation project dependency`() {
820921

modulecheck-project/api/src/main/kotlin/modulecheck/project/ConfiguredProjectDependency.kt

+17
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package modulecheck.project
1717

1818
import modulecheck.parsing.gradle.ConfigurationName
19+
import modulecheck.parsing.gradle.ProjectPath.StringProjectPath
1920
import modulecheck.parsing.gradle.SourceSetName
2021

2122
data class ConfiguredProjectDependency(
@@ -77,3 +78,19 @@ data class DownstreamDependency(
7778
val dependentProject: McProject,
7879
val configuredProjectDependency: ConfiguredProjectDependency
7980
)
81+
82+
data class SourceSetDependency(
83+
val sourceSetName: SourceSetName,
84+
val path: StringProjectPath,
85+
val isTestFixture: Boolean
86+
)
87+
88+
fun ConfiguredProjectDependency.toSourceSetDependency(
89+
sourceSetName: SourceSetName = configurationName.toSourceSetName(),
90+
path: StringProjectPath = this@toSourceSetDependency.path,
91+
isTestFixture: Boolean = this@toSourceSetDependency.isTestFixture
92+
) = SourceSetDependency(
93+
sourceSetName = sourceSetName,
94+
path = path,
95+
isTestFixture = isTestFixture
96+
)

0 commit comments

Comments
 (0)