Fix 2325 - CoreResolution with Child Scopes / ViewModelScope#2340
Fix 2325 - CoreResolution with Child Scopes / ViewModelScope#2340arnaudgiuliani merged 5 commits into4.2.0from
Conversation
…+ Need for ViewModel to be declared ViewModelScope for VM scope constructor injection.
…adjustment required.
There was a problem hiding this comment.
Pull request overview
This PR fixes a scope resolution leak where ViewModels declared at root scope could incorrectly access dependencies defined in viewModelScope { }. The fix introduces stricter scope resolution logic and adds proper annotations and documentation to guide developers toward the correct usage pattern.
Changes:
- Refactored
CoreResolverV2into clearly separated resolution methods for better maintainability - Added
@KoinViewModelScopeApiopt-in annotation with WARNING level to enforce correct usage patterns - Improved error messages to include scope information for easier debugging
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| projects/gradle.properties | Version bump to 4.2.0-beta3-rc6 |
| projects/core/koin-core/src/commonTest/kotlin/org/koin/core/ScopeTest.kt | Added @BeforeTest cleanup to prevent test pollution |
| projects/core/koin-core/src/commonTest/kotlin/org/koin/core/ScopeInfoTest.kt | Fixed parameter resolution to use explicit injected parameter context |
| projects/core/koin-core/src/commonTest/kotlin/org/koin/core/ScopeExampleTest.kt | Added comprehensive test case for issue #2325 demonstrating scope resolution |
| projects/core/koin-core/src/commonMain/kotlin/org/koin/core/resolution/CoreResolverV2.kt | Refactored resolver into separate methods and improved error messages with scope info |
| projects/core/koin-core/src/commonMain/kotlin/org/koin/core/option/KoinOption.kt | Annotated viewModelScopeFactory with @KoinViewModelScopeApi and improved documentation |
| projects/core/koin-core/src/commonMain/kotlin/org/koin/core/annotation/KoinAnnotations.kt | Added new @KoinViewModelScopeApi annotation for guarding experimental ViewModel scope API |
| projects/core/koin-core-viewmodel/src/commonMain/kotlin/org/koin/viewmodel/scope/ViewModelScopeArchetypeDSL.kt | Enhanced documentation with usage examples and added opt-in annotation |
| projects/core/koin-annotations/api/koin-annotations.api | Added public API definition for annotations module |
| projects/android/koin-android/src/test/java/org/koin/test/android/scope/ViewModelScopeArchetypeTest.kt | Updated test to follow correct pattern with ViewModel declared inside viewModelScope block |
| examples/gradle/versions.gradle | Updated Kotlin and Koin versions |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @OptIn(KoinExperimentalAPI::class) | ||
| class ViewModelScopeArchetypeTest { |
There was a problem hiding this comment.
Missing @OptIn(KoinViewModelScopeApi::class) annotation. The viewModelScope function is annotated with @KoinViewModelScopeApi, which requires opt-in. The class-level @OptIn(KoinExperimentalAPI::class) doesn't cover this requirement.
| @Test | ||
| fun test_issue_2325() { |
There was a problem hiding this comment.
Missing test cleanup. The test uses startKoin but doesn't have an @AfterTest to call stopKoin(). This could cause state pollution between tests. Add an @AfterTest method to clean up Koin state, similar to other test classes like ObjectScopeTest and ScopeTest.
| val foundScope = resolvedScope ?: return null | ||
| if (factory == null) return null |
There was a problem hiding this comment.
The null check for factory is redundant. If factory is null, then resolvedScope will also be null (since resolvedScope is only assigned when definition is not null). The check on line 93 already handles this case by returning null when foundScope is null.
| koin.createScope("id", named("name")) | ||
|
|
||
| val ucOnScoped = koin.get<UseCaseOnScopedRepo>() | ||
| assertEquals("single",ucOnScoped.scopedRepo.singleApi.client.name) |
There was a problem hiding this comment.
Missing space after comma in assertEquals. Should be assertEquals("single", ucOnScoped.scopedRepo.singleApi.client.name) for consistency with Kotlin style conventions.
|
|
||
| val ucOnScoped = koin.get<UseCaseOnScopedRepo>() | ||
| assertEquals("single",ucOnScoped.scopedRepo.singleApi.client.name) | ||
| assertEquals("scoped",ucOnScoped.scopedRepo.scopedApi.client.name) |
There was a problem hiding this comment.
Missing space after comma in assertEquals. Should be assertEquals("scoped", ucOnScoped.scopedRepo.scopedApi.client.name) for consistency with Kotlin style conventions.
| assertEquals("scoped",ucOnScoped.scopedRepo.scopedApi.client.name) | ||
|
|
||
| val ucOnSingle = koin.get<UseCaseOnSingleRepo>() | ||
| assertEquals("single",ucOnSingle.singleRepo.singleApi.client.name) |
There was a problem hiding this comment.
Missing space after comma in assertEquals. Should be assertEquals("single", ucOnSingle.singleRepo.singleApi.client.name) for consistency with Kotlin style conventions.
Fix #2325 - Scope Resolution + ViewModelScope Scope Leak Fix
Summary
Fixes scope resolution leak where ViewModels at root scope could incorrectly access viewModelScope { } dependencies. CoreResolverV2 is now stricter. Also impacting previously other scope access.
Breaking Change (Experimental API)
Changes
Files Changed
Impact