diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f192d2e5..6e59b00a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,58 +18,46 @@ concurrency: jobs: build: - runs-on: macOS-latest - env: - api-level: "18" + runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v1 - - - name: Gradle Wrapper Validation - uses: gradle/wrapper-validation-action@v1 + uses: actions/checkout@v6 - name: Install JDK - uses: actions/setup-java@v2 + uses: actions/setup-java@v5 with: distribution: 'zulu' - java-version: '17' + java-version: '21' - - name: Gradle cache - uses: gradle/gradle-build-action@v2 + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v6 # TODO split test and instrumentation into parallel builds - name: Build and run unit tests - id: gradle - uses: gradle/gradle-build-action@v2 - with: - arguments: check + run: ./gradlew check - - name: AVD cache - uses: actions/cache@v3 - id: avd-cache - with: - path: | - ~/.android/avd/* - ~/.android/adb* - key: avd-${{ env.api-level }} + - name: Enable KVM group perms + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm - - name: Create AVD and generate snapshot for caching - if: steps.avd-cache.outputs.cache-hit != 'true' - uses: reactivecircus/android-emulator-runner@v2 - with: - api-level: ${{ env.api-level }} - force-avd-creation: false - emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none - disable-animations: false - script: echo "Generated AVD snapshot for caching." + - name: Free up disk space for the emulator + run: | + # Remove Haskell stuff to free up space for the emulator + sudo rm -rf /usr/local/.ghcup + # Remove dotnet stuff as well + sudo rm -rf /usr/share/dotnet + df -h - name: Run instrumentation tests uses: reactivecircus/android-emulator-runner@v2 with: - api-level: ${{ env.api-level }} - force-avd-creation: false - emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + api-level: 35 + arch: x86_64 disable-animations: true + disk-size: 6000M + heap-size: 600M script: ./gradlew connectedCheck - name: (Fail-only) Upload build reports diff --git a/CHANGELOG.md b/CHANGELOG.md index d7818bc8..650623d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,18 @@ Changelog ========= +Unreleased +---------- + +- **Fix**: Handle empty lambdas in lint checks. +- **Fix**: Use `javax.inject.Inject` for newer versions of ErrorProne. +- **Fix**: Properly propagate nullabiltiy in type params (i.e., `T extends @NonNull Object` vs `@NonNull T`). +- Raise lint target Kotlin language version to `2.0`. +- Update to RxJava `3.1.12`. +- Update minSdk to `23` to match upstream AndroidX deps. +- Update to Lint `32.2.1`. +- Update to ErrorProne `2.49.0`. + Version 2.2.1 ------------- diff --git a/android/autodispose-androidx-lifecycle/src/main/java/autodispose2/androidx/lifecycle/KotlinExtensions.kt b/android/autodispose-androidx-lifecycle/src/main/java/autodispose2/androidx/lifecycle/KotlinExtensions.kt index 28f8fe17..b3e2a63a 100644 --- a/android/autodispose-androidx-lifecycle/src/main/java/autodispose2/androidx/lifecycle/KotlinExtensions.kt +++ b/android/autodispose-androidx-lifecycle/src/main/java/autodispose2/androidx/lifecycle/KotlinExtensions.kt @@ -93,7 +93,7 @@ public inline fun Lifecycle.scope( @CheckReturnValue public inline fun Flowable.autoDispose( lifecycleOwner: LifecycleOwner, - untilEvent: Event? = null + untilEvent: Event? = null, ): FlowableSubscribeProxy { return if (untilEvent == null) { this.to(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(lifecycleOwner))) @@ -114,7 +114,7 @@ public inline fun Flowable.autoDispose( @CheckReturnValue public inline fun Observable.autoDispose( lifecycleOwner: LifecycleOwner, - untilEvent: Event? = null + untilEvent: Event? = null, ): ObservableSubscribeProxy { return if (untilEvent == null) { this.to(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(lifecycleOwner))) @@ -135,7 +135,7 @@ public inline fun Observable.autoDispose( @CheckReturnValue public inline fun Single.autoDispose( lifecycleOwner: LifecycleOwner, - untilEvent: Event? = null + untilEvent: Event? = null, ): SingleSubscribeProxy { return if (untilEvent == null) { this.to(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(lifecycleOwner))) @@ -156,7 +156,7 @@ public inline fun Single.autoDispose( @CheckReturnValue public inline fun Maybe.autoDispose( lifecycleOwner: LifecycleOwner, - untilEvent: Event? = null + untilEvent: Event? = null, ): MaybeSubscribeProxy { return if (untilEvent == null) { this.to(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(lifecycleOwner))) @@ -177,7 +177,7 @@ public inline fun Maybe.autoDispose( @CheckReturnValue public inline fun Completable.autoDispose( lifecycleOwner: LifecycleOwner, - untilEvent: Event? = null + untilEvent: Event? = null, ): CompletableSubscribeProxy { return if (untilEvent == null) { this.to(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(lifecycleOwner))) @@ -200,7 +200,7 @@ public inline fun Completable.autoDispose( @CheckReturnValue public inline fun ParallelFlowable.autoDispose( lifecycleOwner: LifecycleOwner, - untilEvent: Event? = null + untilEvent: Event? = null, ): ParallelFlowableSubscribeProxy { return if (untilEvent == null) { this.to(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(lifecycleOwner))) diff --git a/autodispose-interop/coroutines/src/main/kotlin/autodispose2/interop/coroutines/AutoDisposeCoroutinesInterop.kt b/autodispose-interop/coroutines/src/main/kotlin/autodispose2/interop/coroutines/AutoDisposeCoroutinesInterop.kt index c1f58980..6c05f9c1 100644 --- a/autodispose-interop/coroutines/src/main/kotlin/autodispose2/interop/coroutines/AutoDisposeCoroutinesInterop.kt +++ b/autodispose-interop/coroutines/src/main/kotlin/autodispose2/interop/coroutines/AutoDisposeCoroutinesInterop.kt @@ -89,14 +89,13 @@ private fun CoroutineScope.asUndeferredCompletable(): Completable { ?: error( "Scope cannot be created because it does not have a job: ${this@asUndeferredCompletable}" ) - val handle = - job.invokeOnCompletion { - when (it) { - null, - is CancellationException -> emitter.onComplete() - else -> emitter.onError(it) - } + val handle = job.invokeOnCompletion { + when (it) { + null, + is CancellationException -> emitter.onComplete() + else -> emitter.onError(it) } + } emitter.setCancellable(handle::dispose) } } diff --git a/autodispose-lifecycle/src/main/java/autodispose2/lifecycle/CorrespondingEventsFunction.java b/autodispose-lifecycle/src/main/java/autodispose2/lifecycle/CorrespondingEventsFunction.java index 5146a710..91c5a2bc 100644 --- a/autodispose-lifecycle/src/main/java/autodispose2/lifecycle/CorrespondingEventsFunction.java +++ b/autodispose-lifecycle/src/main/java/autodispose2/lifecycle/CorrespondingEventsFunction.java @@ -25,7 +25,7 @@ * * @param the event type. */ -public interface CorrespondingEventsFunction<@NonNull E> extends Function { +public interface CorrespondingEventsFunction extends Function { /** * Given an event {@code event}, returns the next corresponding event that this lifecycle should diff --git a/autodispose-lifecycle/src/main/java/autodispose2/lifecycle/LifecycleScopeProvider.java b/autodispose-lifecycle/src/main/java/autodispose2/lifecycle/LifecycleScopeProvider.java index a40ff172..ed1bb749 100644 --- a/autodispose-lifecycle/src/main/java/autodispose2/lifecycle/LifecycleScopeProvider.java +++ b/autodispose-lifecycle/src/main/java/autodispose2/lifecycle/LifecycleScopeProvider.java @@ -35,7 +35,7 @@ * @see LifecycleScopes */ @DoNotMock(value = "Use TestLifecycleScopeProvider instead") -public interface LifecycleScopeProvider<@NonNull E> extends ScopeProvider { +public interface LifecycleScopeProvider extends ScopeProvider { /** * Returns a sequence of lifecycle events. Note that completion of this lifecycle will also diff --git a/autodispose-lifecycle/src/main/java/autodispose2/lifecycle/LifecycleScopes.java b/autodispose-lifecycle/src/main/java/autodispose2/lifecycle/LifecycleScopes.java index e4a7b2d1..27306701 100644 --- a/autodispose-lifecycle/src/main/java/autodispose2/lifecycle/LifecycleScopes.java +++ b/autodispose-lifecycle/src/main/java/autodispose2/lifecycle/LifecycleScopes.java @@ -52,7 +52,7 @@ private LifecycleScopes() { * @throws OutsideScopeException if the {@link LifecycleScopeProvider#correspondingEvents()} * throws an {@link OutsideScopeException} during resolution. */ - public static <@NonNull E> CompletableSource resolveScopeFromLifecycle( + public static CompletableSource resolveScopeFromLifecycle( final LifecycleScopeProvider provider) throws OutsideScopeException { return resolveScopeFromLifecycle(provider, true); } @@ -75,7 +75,7 @@ private LifecycleScopes() { * @throws OutsideScopeException if the {@link LifecycleScopeProvider#correspondingEvents()} * throws an {@link OutsideScopeException} during resolution. */ - public static <@NonNull E> CompletableSource resolveScopeFromLifecycle( + public static CompletableSource resolveScopeFromLifecycle( final LifecycleScopeProvider provider, final boolean checkEndBoundary) throws OutsideScopeException { E lastEvent = provider.peekLifecycle(); @@ -115,7 +115,7 @@ private LifecycleScopes() { * @param endEvent the target end event * @param the lifecycle event type */ - public static <@NonNull E> CompletableSource resolveScopeFromLifecycle( + public static CompletableSource resolveScopeFromLifecycle( Observable lifecycle, final E endEvent) { @Nullable Comparator comparator = null; if (endEvent instanceof Comparable) { @@ -134,7 +134,7 @@ private LifecycleScopes() { * @param comparator an optional comparator for checking event equality. * @param the lifecycle event type */ - public static <@NonNull E> CompletableSource resolveScopeFromLifecycle( + public static CompletableSource resolveScopeFromLifecycle( Observable lifecycle, final E endEvent, @Nullable final Comparator comparator) { Predicate equalityPredicate; if (comparator != null) { diff --git a/autodispose/src/main/java/autodispose2/AutoDispose.java b/autodispose/src/main/java/autodispose2/AutoDispose.java index 3c43fa42..e875e10c 100644 --- a/autodispose/src/main/java/autodispose2/AutoDispose.java +++ b/autodispose/src/main/java/autodispose2/AutoDispose.java @@ -78,7 +78,8 @@ public final class AutoDispose { * @return an {@link AutoDisposeConverter} to transform with operators like {@link * Observable#to(ObservableConverter)} */ - public static <@NonNull T> AutoDisposeConverter autoDisposable(final ScopeProvider provider) { + public static AutoDisposeConverter autoDisposable( + final ScopeProvider provider) { checkNotNull(provider, "provider == null"); return autoDisposable(completableOf(provider)); } @@ -99,7 +100,8 @@ public final class AutoDispose { * @return an {@link AutoDisposeConverter} to transform with operators like {@link * Observable#to(ObservableConverter)} */ - public static <@NonNull T> AutoDisposeConverter autoDisposable(final CompletableSource scope) { + public static AutoDisposeConverter autoDisposable( + final CompletableSource scope) { checkNotNull(scope, "scope == null"); return new AutoDisposeConverter() { @Override @@ -138,7 +140,7 @@ public void subscribe(CompletableObserver observer) { } @Override - public <@NonNull E extends CompletableObserver> E subscribeWith(E observer) { + public E subscribeWith(E observer) { return new AutoDisposeCompletable(upstream, scope).subscribeWith(observer); } @@ -196,7 +198,7 @@ public void subscribe(Subscriber observer) { } @Override - public <@NonNull E extends Subscriber> E subscribeWith(E observer) { + public > E subscribeWith(E observer) { return new AutoDisposeFlowable<>(upstream, scope).subscribeWith(observer); } @@ -263,7 +265,7 @@ public void subscribe(MaybeObserver observer) { } @Override - public <@NonNull E extends MaybeObserver> E subscribeWith(E observer) { + public > E subscribeWith(E observer) { return new AutoDisposeMaybe<>(upstream, scope).subscribeWith(observer); } @@ -321,7 +323,7 @@ public void subscribe(Observer observer) { } @Override - public <@NonNull E extends Observer> E subscribeWith(E observer) { + public > E subscribeWith(E observer) { return new AutoDisposeObservable<>(upstream, scope).subscribeWith(observer); } @@ -363,7 +365,7 @@ public Disposable subscribe(Consumer onSuccess) { @SuppressWarnings("NullAway") // False positive @Override public Disposable subscribe( - BiConsumer<@Nullable ? super T, @Nullable ? super Throwable> biConsumer) { + BiConsumer biConsumer) { return new AutoDisposeSingle<>(upstream, scope).subscribe(biConsumer); } @@ -379,7 +381,7 @@ public void subscribe(SingleObserver observer) { } @Override - public <@NonNull E extends SingleObserver> E subscribeWith(E observer) { + public > E subscribeWith(E observer) { return new AutoDisposeSingle<>(upstream, scope).subscribeWith(observer); } diff --git a/autodispose/src/main/java/autodispose2/AutoDisposeConverter.java b/autodispose/src/main/java/autodispose2/AutoDisposeConverter.java index 75006dfb..27b0a04c 100644 --- a/autodispose/src/main/java/autodispose2/AutoDisposeConverter.java +++ b/autodispose/src/main/java/autodispose2/AutoDisposeConverter.java @@ -29,7 +29,7 @@ * * @param the type. */ -public interface AutoDisposeConverter<@NonNull T> +public interface AutoDisposeConverter extends FlowableConverter>, ParallelFlowableConverter>, ObservableConverter>, diff --git a/autodispose/src/main/java/autodispose2/AutoDisposeFlowable.java b/autodispose/src/main/java/autodispose2/AutoDisposeFlowable.java index 768ed3e4..d4cb2da8 100644 --- a/autodispose/src/main/java/autodispose2/AutoDisposeFlowable.java +++ b/autodispose/src/main/java/autodispose2/AutoDisposeFlowable.java @@ -21,7 +21,7 @@ import org.reactivestreams.Publisher; import org.reactivestreams.Subscriber; -final class AutoDisposeFlowable<@NonNull T> extends Flowable +final class AutoDisposeFlowable extends Flowable implements FlowableSubscribeProxy { private final Publisher source; private final CompletableSource scope; diff --git a/autodispose/src/main/java/autodispose2/AutoDisposeMaybe.java b/autodispose/src/main/java/autodispose2/AutoDisposeMaybe.java index 14f24a7a..d8f8b8a6 100644 --- a/autodispose/src/main/java/autodispose2/AutoDisposeMaybe.java +++ b/autodispose/src/main/java/autodispose2/AutoDisposeMaybe.java @@ -21,7 +21,8 @@ import io.reactivex.rxjava3.core.MaybeObserver; import io.reactivex.rxjava3.core.MaybeSource; -final class AutoDisposeMaybe<@NonNull T> extends Maybe implements MaybeSubscribeProxy { +final class AutoDisposeMaybe extends Maybe + implements MaybeSubscribeProxy { private final MaybeSource source; private final CompletableSource scope; diff --git a/autodispose/src/main/java/autodispose2/AutoDisposeObservable.java b/autodispose/src/main/java/autodispose2/AutoDisposeObservable.java index 96db085a..212d3916 100644 --- a/autodispose/src/main/java/autodispose2/AutoDisposeObservable.java +++ b/autodispose/src/main/java/autodispose2/AutoDisposeObservable.java @@ -21,7 +21,7 @@ import io.reactivex.rxjava3.core.ObservableSource; import io.reactivex.rxjava3.core.Observer; -final class AutoDisposeObservable<@NonNull T> extends Observable +final class AutoDisposeObservable extends Observable implements ObservableSubscribeProxy { private final ObservableSource source; private final CompletableSource scope; diff --git a/autodispose/src/main/java/autodispose2/AutoDisposeParallelFlowable.java b/autodispose/src/main/java/autodispose2/AutoDisposeParallelFlowable.java index 1e60e43a..b6501b72 100644 --- a/autodispose/src/main/java/autodispose2/AutoDisposeParallelFlowable.java +++ b/autodispose/src/main/java/autodispose2/AutoDisposeParallelFlowable.java @@ -20,7 +20,7 @@ import io.reactivex.rxjava3.parallel.ParallelFlowable; import org.reactivestreams.Subscriber; -final class AutoDisposeParallelFlowable<@NonNull T> extends ParallelFlowable +final class AutoDisposeParallelFlowable extends ParallelFlowable implements ParallelFlowableSubscribeProxy { private final ParallelFlowable source; diff --git a/autodispose/src/main/java/autodispose2/AutoDisposeSingle.java b/autodispose/src/main/java/autodispose2/AutoDisposeSingle.java index 640c892b..6a875e39 100644 --- a/autodispose/src/main/java/autodispose2/AutoDisposeSingle.java +++ b/autodispose/src/main/java/autodispose2/AutoDisposeSingle.java @@ -21,7 +21,8 @@ import io.reactivex.rxjava3.core.SingleObserver; import io.reactivex.rxjava3.core.SingleSource; -final class AutoDisposeSingle<@NonNull T> extends Single implements SingleSubscribeProxy { +final class AutoDisposeSingle extends Single + implements SingleSubscribeProxy { private final SingleSource source; private final CompletableSource scope; diff --git a/autodispose/src/main/java/autodispose2/AutoDisposingMaybeObserverImpl.java b/autodispose/src/main/java/autodispose2/AutoDisposingMaybeObserverImpl.java index 1869dc23..55e6f9a9 100644 --- a/autodispose/src/main/java/autodispose2/AutoDisposingMaybeObserverImpl.java +++ b/autodispose/src/main/java/autodispose2/AutoDisposingMaybeObserverImpl.java @@ -23,7 +23,8 @@ import io.reactivex.rxjava3.observers.DisposableCompletableObserver; import java.util.concurrent.atomic.AtomicReference; -final class AutoDisposingMaybeObserverImpl<@NonNull T> implements AutoDisposingMaybeObserver { +final class AutoDisposingMaybeObserverImpl + implements AutoDisposingMaybeObserver { @SuppressWarnings("WeakerAccess") // Package private for synthetic accessor saving final AtomicReference mainDisposable = new AtomicReference<>(); diff --git a/autodispose/src/main/java/autodispose2/AutoDisposingObserverImpl.java b/autodispose/src/main/java/autodispose2/AutoDisposingObserverImpl.java index 7c3f4999..5792ba8d 100644 --- a/autodispose/src/main/java/autodispose2/AutoDisposingObserverImpl.java +++ b/autodispose/src/main/java/autodispose2/AutoDisposingObserverImpl.java @@ -24,7 +24,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; -final class AutoDisposingObserverImpl<@NonNull T> extends AtomicInteger +final class AutoDisposingObserverImpl extends AtomicInteger implements AutoDisposingObserver { @SuppressWarnings("WeakerAccess") // Package private for synthetic accessor saving diff --git a/autodispose/src/main/java/autodispose2/AutoDisposingSingleObserverImpl.java b/autodispose/src/main/java/autodispose2/AutoDisposingSingleObserverImpl.java index 282c8eac..19958e60 100644 --- a/autodispose/src/main/java/autodispose2/AutoDisposingSingleObserverImpl.java +++ b/autodispose/src/main/java/autodispose2/AutoDisposingSingleObserverImpl.java @@ -23,7 +23,8 @@ import io.reactivex.rxjava3.observers.DisposableCompletableObserver; import java.util.concurrent.atomic.AtomicReference; -final class AutoDisposingSingleObserverImpl<@NonNull T> implements AutoDisposingSingleObserver { +final class AutoDisposingSingleObserverImpl + implements AutoDisposingSingleObserver { @SuppressWarnings("WeakerAccess") // Package private for synthetic accessor saving final AtomicReference mainDisposable = new AtomicReference<>(); diff --git a/autodispose/src/main/java/autodispose2/AutoDisposingSubscriberImpl.java b/autodispose/src/main/java/autodispose2/AutoDisposingSubscriberImpl.java index 6f0f5e21..deb75b4c 100644 --- a/autodispose/src/main/java/autodispose2/AutoDisposingSubscriberImpl.java +++ b/autodispose/src/main/java/autodispose2/AutoDisposingSubscriberImpl.java @@ -26,7 +26,7 @@ import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; -final class AutoDisposingSubscriberImpl<@NonNull T> extends AtomicInteger +final class AutoDisposingSubscriberImpl extends AtomicInteger implements AutoDisposingSubscriber { @SuppressWarnings("WeakerAccess") // Package private for synthetic accessor saving diff --git a/autodispose/src/main/java/autodispose2/CompletableSubscribeProxy.java b/autodispose/src/main/java/autodispose2/CompletableSubscribeProxy.java index 5b144908..a7a51ad0 100644 --- a/autodispose/src/main/java/autodispose2/CompletableSubscribeProxy.java +++ b/autodispose/src/main/java/autodispose2/CompletableSubscribeProxy.java @@ -57,7 +57,7 @@ public interface CompletableSubscribeProxy { * @return a {@link CompletableObserver} */ @CheckReturnValue - <@NonNull E extends CompletableObserver> E subscribeWith(E observer); + E subscribeWith(E observer); /** * Proxy for {@link Completable#test()}. diff --git a/autodispose/src/main/java/autodispose2/FlowableSubscribeProxy.java b/autodispose/src/main/java/autodispose2/FlowableSubscribeProxy.java index 669f1a03..c2c6d8f0 100644 --- a/autodispose/src/main/java/autodispose2/FlowableSubscribeProxy.java +++ b/autodispose/src/main/java/autodispose2/FlowableSubscribeProxy.java @@ -25,7 +25,7 @@ import org.reactivestreams.Subscriber; /** Subscribe proxy that matches {@link Flowable}'s subscribe overloads. */ -public interface FlowableSubscribeProxy<@NonNull T> { +public interface FlowableSubscribeProxy { /** * Proxy for {@link Flowable#subscribe()}. @@ -65,7 +65,7 @@ Disposable subscribe( * @return an {@link Subscriber} */ @CheckReturnValue - <@NonNull E extends Subscriber> E subscribeWith(E observer); + > E subscribeWith(E observer); /** * Proxy for {@link Flowable#test()}. diff --git a/autodispose/src/main/java/autodispose2/HalfSerializer.java b/autodispose/src/main/java/autodispose2/HalfSerializer.java index bafcbafc..0ba8bd03 100644 --- a/autodispose/src/main/java/autodispose2/HalfSerializer.java +++ b/autodispose/src/main/java/autodispose2/HalfSerializer.java @@ -48,7 +48,7 @@ private HalfSerializer() { * @param error the holder of Throwables * @return true if a terminal event was emitted to {@code observer}, false if not */ - public static <@NonNull T> boolean onNext(Subscriber subscriber, + public static boolean onNext(Subscriber subscriber, T value, AtomicInteger wip, AtomicThrowable error) { @@ -117,7 +117,7 @@ public static void onComplete(Subscriber subscriber, AtomicInteger wip, Atomi * @param error the holder of Throwables * @return true if a terminal event was emitted to {@code observer}, false if not */ - public static <@NonNull T> boolean onNext(Observer observer, T value, AtomicInteger wip, AtomicThrowable error) { + public static boolean onNext(Observer observer, T value, AtomicInteger wip, AtomicThrowable error) { if (wip.get() == 0 && wip.compareAndSet(0, 1)) { observer.onNext(value); if (wip.decrementAndGet() != 0) { diff --git a/autodispose/src/main/java/autodispose2/MaybeSubscribeProxy.java b/autodispose/src/main/java/autodispose2/MaybeSubscribeProxy.java index 6b719324..cdf23e4b 100644 --- a/autodispose/src/main/java/autodispose2/MaybeSubscribeProxy.java +++ b/autodispose/src/main/java/autodispose2/MaybeSubscribeProxy.java @@ -25,7 +25,7 @@ import io.reactivex.rxjava3.observers.TestObserver; /** Subscribe proxy that matches {@link Maybe}'s subscribe overloads. */ -public interface MaybeSubscribeProxy<@NonNull T> { +public interface MaybeSubscribeProxy { /** * Proxy for {@link Maybe#subscribe()}. @@ -65,7 +65,7 @@ Disposable subscribe( * @return a {@link MaybeObserver} */ @CheckReturnValue - <@NonNull E extends MaybeObserver> E subscribeWith(E observer); + > E subscribeWith(E observer); /** * Proxy for {@link Maybe#test()}. diff --git a/autodispose/src/main/java/autodispose2/ObservableSubscribeProxy.java b/autodispose/src/main/java/autodispose2/ObservableSubscribeProxy.java index 274563f5..f729b177 100644 --- a/autodispose/src/main/java/autodispose2/ObservableSubscribeProxy.java +++ b/autodispose/src/main/java/autodispose2/ObservableSubscribeProxy.java @@ -25,7 +25,7 @@ import io.reactivex.rxjava3.observers.TestObserver; /** Subscribe proxy that matches {@link Observable}'s subscribe overloads. */ -public interface ObservableSubscribeProxy<@NonNull T> { +public interface ObservableSubscribeProxy { /** * Proxy for {@link Observable#subscribe()}. @@ -65,7 +65,7 @@ Disposable subscribe( * @return an {@link Observer} */ @CheckReturnValue - <@NonNull E extends Observer> E subscribeWith(E observer); + > E subscribeWith(E observer); /** * Proxy for {@link Observable#test()}. diff --git a/autodispose/src/main/java/autodispose2/ParallelFlowableSubscribeProxy.java b/autodispose/src/main/java/autodispose2/ParallelFlowableSubscribeProxy.java index 0b69e7cb..225f27b4 100644 --- a/autodispose/src/main/java/autodispose2/ParallelFlowableSubscribeProxy.java +++ b/autodispose/src/main/java/autodispose2/ParallelFlowableSubscribeProxy.java @@ -20,7 +20,7 @@ import org.reactivestreams.Subscriber; /** Subscribe proxy that matches {@link ParallelFlowable}'s subscribe overloads. */ -public interface ParallelFlowableSubscribeProxy<@NonNull T> { +public interface ParallelFlowableSubscribeProxy { /** Proxy for {@link ParallelFlowable#subscribe(Subscriber[])}. */ void subscribe(Subscriber[] subscribers); diff --git a/autodispose/src/main/java/autodispose2/SingleSubscribeProxy.java b/autodispose/src/main/java/autodispose2/SingleSubscribeProxy.java index e4b047b4..fdbae69d 100644 --- a/autodispose/src/main/java/autodispose2/SingleSubscribeProxy.java +++ b/autodispose/src/main/java/autodispose2/SingleSubscribeProxy.java @@ -26,7 +26,7 @@ import io.reactivex.rxjava3.observers.TestObserver; /** Subscribe proxy that matches {@link Single}'s subscribe overloads. */ -public interface SingleSubscribeProxy<@NonNull T> { +public interface SingleSubscribeProxy { /** * Proxy for {@link Single#subscribe()}. @@ -47,7 +47,7 @@ public interface SingleSubscribeProxy<@NonNull T> { * * @return a {@link Disposable} */ - Disposable subscribe(BiConsumer<@Nullable ? super T, @Nullable ? super Throwable> biConsumer); + Disposable subscribe(BiConsumer biConsumer); /** * Proxy for {@link Single#subscribe(Consumer, Consumer)}. @@ -65,7 +65,7 @@ public interface SingleSubscribeProxy<@NonNull T> { * @return a {@link SingleObserver} */ @CheckReturnValue - <@NonNull E extends SingleObserver> E subscribeWith(E observer); + > E subscribeWith(E observer); /** * Proxy for {@link Single#test()}. diff --git a/autodispose/src/main/java/autodispose2/observers/AutoDisposingMaybeObserver.java b/autodispose/src/main/java/autodispose2/observers/AutoDisposingMaybeObserver.java index fe9af691..de5a431f 100644 --- a/autodispose/src/main/java/autodispose2/observers/AutoDisposingMaybeObserver.java +++ b/autodispose/src/main/java/autodispose2/observers/AutoDisposingMaybeObserver.java @@ -23,7 +23,8 @@ * A {@link Disposable} {@link MaybeObserver} that can automatically dispose itself. Interface here * for type safety but enforcement is left to the implementation. */ -public interface AutoDisposingMaybeObserver<@NonNull T> extends MaybeObserver, Disposable { +public interface AutoDisposingMaybeObserver + extends MaybeObserver, Disposable { /** * Returns the delegate {@link MaybeObserver} that is used under the hood for introspection diff --git a/autodispose/src/main/java/autodispose2/observers/AutoDisposingObserver.java b/autodispose/src/main/java/autodispose2/observers/AutoDisposingObserver.java index c1d98597..750c0a48 100644 --- a/autodispose/src/main/java/autodispose2/observers/AutoDisposingObserver.java +++ b/autodispose/src/main/java/autodispose2/observers/AutoDisposingObserver.java @@ -23,7 +23,7 @@ * A {@link Disposable} {@link Observer} that can automatically dispose itself. Interface here for * type safety but enforcement is left to the implementation. */ -public interface AutoDisposingObserver<@NonNull T> extends Observer, Disposable { +public interface AutoDisposingObserver extends Observer, Disposable { /** * Returns the delegate {@link Observer} that is used under the hood for introspection purposes. diff --git a/autodispose/src/main/java/autodispose2/observers/AutoDisposingSingleObserver.java b/autodispose/src/main/java/autodispose2/observers/AutoDisposingSingleObserver.java index cf3183c2..a7b0f8f2 100644 --- a/autodispose/src/main/java/autodispose2/observers/AutoDisposingSingleObserver.java +++ b/autodispose/src/main/java/autodispose2/observers/AutoDisposingSingleObserver.java @@ -23,7 +23,8 @@ * A {@link Disposable} {@link SingleObserver} that can automatically dispose itself. Interface here * for type safety but enforcement is left to the implementation. */ -public interface AutoDisposingSingleObserver<@NonNull T> extends SingleObserver, Disposable { +public interface AutoDisposingSingleObserver + extends SingleObserver, Disposable { /** * Returns the delegate {@link SingleObserver} that is used under the hood for introspection diff --git a/autodispose/src/main/java/autodispose2/observers/AutoDisposingSubscriber.java b/autodispose/src/main/java/autodispose2/observers/AutoDisposingSubscriber.java index 106d95a3..ba4b1f1a 100644 --- a/autodispose/src/main/java/autodispose2/observers/AutoDisposingSubscriber.java +++ b/autodispose/src/main/java/autodispose2/observers/AutoDisposingSubscriber.java @@ -25,7 +25,7 @@ * A {@link Disposable} {@link Subscriber} that can automatically dispose itself. Interface here for * type safety but enforcement is left to the implementation. */ -public interface AutoDisposingSubscriber<@NonNull T> +public interface AutoDisposingSubscriber extends FlowableSubscriber, Subscription, Disposable { /** diff --git a/build.gradle.kts b/build.gradle.kts index eafc55ce..3ae5791f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -22,11 +22,11 @@ import com.diffplug.gradle.spotless.SpotlessExtension import com.diffplug.gradle.spotless.SpotlessExtensionPredeclare import com.diffplug.spotless.LineEnding import com.vanniktech.maven.publish.MavenPublishBaseExtension -import java.net.URI import net.ltgt.gradle.errorprone.CheckSeverity import net.ltgt.gradle.errorprone.errorprone import net.ltgt.gradle.nullaway.nullaway -import org.jetbrains.dokka.gradle.DokkaTaskPartial +import org.jetbrains.dokka.gradle.DokkaExtension +import org.jetbrains.dokka.gradle.engine.parameters.VisibilityModifier import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptions @@ -57,7 +57,7 @@ val mixedSourcesArtifacts = "autodispose-android", "autodispose-androidx-lifecycle", "autodispose-androidx-lifecycle-test", - "autodispose-lifecycle" + "autodispose-lifecycle", ) // These are files with different copyright headers that should not be modified automatically. val copiedFiles = @@ -73,9 +73,11 @@ val copiedFiles = .map { "**/*${it}.java" } .toTypedArray() -tasks.dokkaHtmlMultiModule { - outputDirectory.set(rootDir.resolve("docs/api/2.x")) - includes.from(project.layout.projectDirectory.file("README.md")) +dokka { + dokkaPublications.html { + outputDirectory.set(rootDir.resolve("docs/api/2.x")) + includes.from(project.layout.projectDirectory.file("README.md")) + } } val ktfmtVersion = libs.versions.ktfmt.get() @@ -87,7 +89,7 @@ allprojects { format("misc") { target("**/*.md", "**/.gitignore") - indentWithSpaces(2) + leadingTabsToSpaces(2) trimTrailingWhitespace() endWithNewline() } @@ -107,7 +109,7 @@ allprojects { endWithNewline() licenseHeaderFile( rootProject.file("spotless/copyright.kt"), - "(import|plugins|buildscript|dependencies|pluginManagement|dependencyResolutionManagement)" + "(import|plugins|buildscript|dependencies|pluginManagement|dependencyResolutionManagement)", ) } @@ -192,29 +194,48 @@ subprojects { pluginManager.withPlugin("com.vanniktech.maven.publish") { project.apply(plugin = "org.jetbrains.dokka") - tasks.withType().configureEach { - outputDirectory.set(buildDir.resolve("docs/partial")) + configure { moduleName.set(project.property("POM_ARTIFACT_ID").toString()) moduleVersion.set(project.property("VERSION_NAME").toString()) + basePublicationsDirectory.set(layout.buildDirectory.dir("dokkaDir")) + dokkaPublications.configureEach { suppressInheritedMembers.set(true) } dokkaSourceSets.configureEach { - skipDeprecated.set(true) - includes.from("Module.md") - suppressGeneratedFiles.set(true) - suppressInheritedMembers.set(true) - externalDocumentationLink { - url.set(URI("https://reactivex.io/RxJava/3.x/javadoc/").toURL()) + val readMeProvider = project.layout.projectDirectory.file("README.md") + if (readMeProvider.asFile.exists()) { + includes.from(readMeProvider) } - externalDocumentationLink { - url.set(URI("https://kotlin.github.io/kotlinx.coroutines/index.html").toURL()) + suppressGeneratedFiles.set(true) + + if (name.contains("androidTest", ignoreCase = true)) { + suppress.set(true) } + skipDeprecated.set(true) + documentedVisibilities.add(VisibilityModifier.Public) + + // Skip internal packages perPackageOption { // language=RegExp matchingRegex.set(".*\\.internal\\..*") suppress.set(true) } - val moduleMd = project.layout.projectDirectory.file("Module.md") - if (moduleMd.asFile.exists()) { - includes.from(moduleMd) + // AndroidX and Android docs are automatically added by the Dokka plugin. + externalDocumentationLinks.apply { + create("RxJava").apply { url("https://reactivex.io/RxJava/3.x/javadoc/") } + create("Coroutines").apply { + url("https://kotlin.github.io/kotlinx.coroutines/index.html") + } + } + + // Add source links + sourceLink { + localDirectory.set(layout.projectDirectory.dir("src")) + val relPath = rootProject.projectDir.toPath().relativize(projectDir.toPath()) + remoteUrl( + providers.gradleProperty("POM_SCM_URL").map { scmUrl -> + "$scmUrl/tree/main/$relPath/src" + } + ) + remoteLineSuffix.set("#L") } } } @@ -226,7 +247,7 @@ subprojects { } // Common android config - val commonAndroidConfig: CommonExtension<*, *, *, *>.() -> Unit = { + val commonAndroidConfig: CommonExtension<*, *, *, *, *, *>.() -> Unit = { compileSdk = compileSdkVersionInt defaultConfig { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index de6f3254..4c8641e2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,53 +1,53 @@ [versions] -agp = "8.2.2" -androidTest = "1.6.0-alpha03" -androidxLifecycle = "2.6.1" -animalSniffer = "1.7.1" -appcompat = "1.6.1" -compileSdkVersion = "33" -constraintlayout = "2.1.4" -dokka = "1.9.10" -errorProne = "2.24.1" -errorPronePlugin = "3.1.0" -fragmentKtx = "1.6.0" -gjf = "1.19.2" -jdk = "17" +agp = "8.13.2" +androidTest = "1.7.0" +androidxLifecycle = "2.10.0" +animalSniffer = "2.0.1" +appcompat = "1.7.1" +compileSdkVersion = "36" +constraintlayout = "2.2.1" +dokka = "2.2.0" +errorProne = "2.49.0" +errorPronePlugin = "5.1.0" +fragmentKtx = "1.8.9" +gjf = "1.35.0" +jdk = "21" jvmTarget = "1.8" -kotlin = "1.9.22" -ktfmt = "0.51" -leakcanaryAndroid = "2.13" +kotlin = "2.3.21" +ktfmt = "0.62" +leakcanaryAndroid = "2.14" lifecycleExtensions = "2.2.0" -lint = "31.0.2" -lintJvmTarget = "17" -material = "1.9.0" -mavenPublish = "0.27.0" -minSdkVersion = "14" +lint = "32.2.1" +lintJvmTarget = "21" +material = "1.14.0" +mavenPublish = "0.36.0" +minSdkVersion = "23" multidex = "2.0.1" -nullawayPlugin = "1.6.0" +nullawayPlugin = "3.0.0" replayingShareKotlin = "2.2.0" rxjava3Bridge = "3.0.2" rxrelay = "2.1.1" -spotless = "6.25.0" -targetSdkVersion = "33" +spotless = "8.4.0" +targetSdkVersion = "36" [plugins] android-application = { id = "com.android.application", version.ref = "agp" } android-library = { id = "com.android.library", version.ref = "agp" } android-lint = { id = "com.android.lint", version.ref = "agp" } animalSniffer = { id = "ru.vyarus.animalsniffer", version.ref = "animalSniffer" } -binaryCompatibilityValidator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version = "0.14.0" } +binaryCompatibilityValidator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version = "0.18.1" } dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } errorProne = { id = "net.ltgt.errorprone", version.ref = "errorPronePlugin" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } -ksp = { id = "com.google.devtools.ksp", version = "1.9.23-1.0.19" } +ksp = { id = "com.google.devtools.ksp", version = "2.3.8" } mavenPublish = { id = "com.vanniktech.maven.publish", version.ref = "mavenPublish" } nullAway = { id = "net.ltgt.nullaway", version.ref = "nullawayPlugin" } spotless = { id = "com.diffplug.spotless", version.ref = "spotless" } [libraries] -androidx-activityKtx = "androidx.activity:activity-ktx:1.9.1" -androidx-annotations = "androidx.annotation:annotation:1.6.0" +androidx-activityKtx = "androidx.activity:activity-ktx:1.13.0" +androidx-annotations = "androidx.annotation:annotation:1.10.0" androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" } androidx-constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "constraintlayout" } androidx-fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref = "fragmentKtx" } @@ -59,7 +59,7 @@ androidx-lifecycle-runtimeKtx = { module = "androidx.lifecycle:lifecycle-runtime androidx-lifecycle-runtimeTest = { module = "androidx.lifecycle:lifecycle-runtime-testing", version.ref = "androidxLifecycle" } androidx-lifecycle-vmKtx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "androidxLifecycle" } autoService-annotations = "com.google.auto.service:auto-service-annotations:1.1.1" -autoService-ksp = "dev.zacsweers.autoservice:auto-service-ksp:1.1.0" +autoService-ksp = "dev.zacsweers.autoservice:auto-service-ksp:1.2.0" build-animalSniffer = "org.codehaus.mojo.signature:java17:1.0" build-errorProne = { module = "com.google.errorprone:error_prone_core", version.ref = "errorProne" } build-errorProneAnnotations = { module = "com.google.errorprone:error_prone_annotations", version.ref = "errorProne" } @@ -68,8 +68,8 @@ build-errorProneTestHelpers = { module = "com.google.errorprone:error_prone_test build-lint-api = { module = "com.android.tools.lint:lint-api", version.ref = "lint" } build-lint-core = { module = "com.android.tools.lint:lint", version.ref = "lint" } build-lint-tests = { module = "com.android.tools.lint:lint-tests", version.ref = "lint" } -build-nullAway = "com.uber.nullaway:nullaway:0.10.22" -kotlin-coroutines = "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3" +build-nullAway = "com.uber.nullaway:nullaway:0.13.4" +kotlin-coroutines = "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0" leakcanary-android = { module = "com.squareup.leakcanary:leakcanary-android", version.ref = "leakcanaryAndroid" } material = { module = "com.google.android.material:material", version.ref = "material" } multidex = { module = "com.android.support:multidex", version.ref = "multidex" } @@ -81,12 +81,12 @@ renovateTrigger-gjf = { module = "com.google.googlejavaformat:google-java-format replaying-share-kotlin = { module = "com.jakewharton.rx2:replaying-share-kotlin", version.ref = "replayingShareKotlin" } rx-android = "io.reactivex.rxjava3:rxandroid:3.0.2" -rx-java = "io.reactivex.rxjava3:rxjava:3.1.8" +rx-java = "io.reactivex.rxjava3:rxjava:3.1.12" rxjava3-bridge = { module = "com.github.akarnokd:rxjava3-bridge", version.ref = "rxjava3Bridge" } rxrelay = { module = "com.jakewharton.rxrelay2:rxrelay", version.ref = "rxrelay" } -test-androidExtJunit = "androidx.test.ext:junit:1.2.0-alpha01" -test-androidOrchestrator = { module = "androidx.test:orchestrator", version = "1.5.0-alpha01" } -test-androidRules = { module = "androidx.test:rules", version = "1.6.1" } +test-androidExtJunit = "androidx.test.ext:junit:1.3.0" +test-androidOrchestrator = { module = "androidx.test:orchestrator", version = "1.6.1" } +test-androidRules = { module = "androidx.test:rules", version = "1.7.0" } test-androidRunner = { module = "androidx.test:runner", version.ref = "androidTest" } test-junit = "junit:junit:4.13.2" -test-truth = "com.google.truth:truth:1.4.0" +test-truth = "com.google.truth:truth:1.4.5" diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 033e24c4..b1b8ef56 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9f4197d5..df6a6ad7 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,9 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip networkTimeout=10000 +retries=0 +retryBackOffMs=500 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index fcb6fca1..b9bb139f 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -83,7 +85,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -111,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -144,7 +146,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +154,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -169,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -201,16 +202,15 @@ fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 6689b85b..aa5f10b0 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -21,8 +23,8 @@ @rem @rem ########################################################################## -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @@ -43,13 +45,13 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 -goto fail +"%COMSPEC%" /c exit 1 :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% @@ -57,36 +59,24 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 -goto fail +"%COMSPEC%" /c exit 1 :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel -:omega +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/sample/build.gradle.kts b/sample/build.gradle.kts index 8ebf719a..be04f89d 100644 --- a/sample/build.gradle.kts +++ b/sample/build.gradle.kts @@ -45,7 +45,7 @@ val classesWithScope = "android.app.Fragment", "androidx.lifecycle.LifecycleOwner", "autodispose2.ScopeProvider", - "autodispose2.sample.CustomScope" + "autodispose2.sample.CustomScope", ) tasks.withType().configureEach { diff --git a/sample/src/main/kotlin/autodispose2/recipes/AutoDisposeActivityKotlin.kt b/sample/src/main/kotlin/autodispose2/recipes/AutoDisposeActivityKotlin.kt index dec138dc..876ee7d1 100644 --- a/sample/src/main/kotlin/autodispose2/recipes/AutoDisposeActivityKotlin.kt +++ b/sample/src/main/kotlin/autodispose2/recipes/AutoDisposeActivityKotlin.kt @@ -44,7 +44,7 @@ abstract class AutoDisposeActivityKotlin : Activity(), LifecycleScopeProvider { diff --git a/sample/src/main/kotlin/autodispose2/recipes/AutoDisposeFragmentKotlin.kt b/sample/src/main/kotlin/autodispose2/recipes/AutoDisposeFragmentKotlin.kt index 4199661b..4097cb08 100644 --- a/sample/src/main/kotlin/autodispose2/recipes/AutoDisposeFragmentKotlin.kt +++ b/sample/src/main/kotlin/autodispose2/recipes/AutoDisposeFragmentKotlin.kt @@ -54,7 +54,7 @@ abstract class AutoDisposeFragmentKotlin : Fragment(), LifecycleScopeProvider { diff --git a/sample/src/main/kotlin/autodispose2/recipes/AutoDisposeViewHolderKotlin.kt b/sample/src/main/kotlin/autodispose2/recipes/AutoDisposeViewHolderKotlin.kt index 0dfb845e..ebf610b9 100644 --- a/sample/src/main/kotlin/autodispose2/recipes/AutoDisposeViewHolderKotlin.kt +++ b/sample/src/main/kotlin/autodispose2/recipes/AutoDisposeViewHolderKotlin.kt @@ -38,7 +38,7 @@ abstract class AutoDisposeViewHolderKotlin(itemView: View) : enum class ViewHolderEvent { BIND, - UNBIND + UNBIND, } override fun onBind() = lifecycleEvents.onNext(BIND) diff --git a/sample/src/main/kotlin/autodispose2/recipes/AutoDisposeViewKotlin.kt b/sample/src/main/kotlin/autodispose2/recipes/AutoDisposeViewKotlin.kt index 33ff2ca3..28c93608 100644 --- a/sample/src/main/kotlin/autodispose2/recipes/AutoDisposeViewKotlin.kt +++ b/sample/src/main/kotlin/autodispose2/recipes/AutoDisposeViewKotlin.kt @@ -39,7 +39,7 @@ abstract class AutoDisposeViewKotlin : View, LifecycleScopeProvider { enum class ViewEvent { ATTACH, - DETACH + DETACH, } private val lifecycleEvents by lazy { BehaviorSubject.create() } @@ -48,7 +48,7 @@ abstract class AutoDisposeViewKotlin : View, LifecycleScopeProvider { constructor( context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = View.NO_ID + defStyleAttr: Int = View.NO_ID, ) : super(context, attrs, defStyleAttr) @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @@ -56,7 +56,7 @@ abstract class AutoDisposeViewKotlin : View, LifecycleScopeProvider { context: Context, attrs: AttributeSet, defStyleAttr: Int, - defStyleRes: Int + defStyleRes: Int, ) : super(context, attrs, defStyleAttr, defStyleRes) override fun onAttachedToWindow() { diff --git a/sample/src/main/kotlin/autodispose2/recipes/AutoDisposeViewModel.kt b/sample/src/main/kotlin/autodispose2/recipes/AutoDisposeViewModel.kt index a9ead9bc..59a3a213 100644 --- a/sample/src/main/kotlin/autodispose2/recipes/AutoDisposeViewModel.kt +++ b/sample/src/main/kotlin/autodispose2/recipes/AutoDisposeViewModel.kt @@ -38,7 +38,7 @@ abstract class AutoDisposeViewModel : ViewModel(), LifecycleScopeProvider Unit = {} fun ObservableSubscribeProxy.subscribeBy( onError: (Throwable) -> Unit = onErrorStub, onComplete: () -> Unit = onCompleteStub, - onNext: (T) -> Unit = onNextStub + onNext: (T) -> Unit = onNextStub, ): Disposable { return if (onError === onErrorStub && onComplete === onCompleteStub) { subscribe(onNext) @@ -63,7 +63,7 @@ fun ObservableSubscribeProxy.subscribeBy( fun FlowableSubscribeProxy.subscribeBy( onError: (Throwable) -> Unit = onErrorStub, onComplete: () -> Unit = onCompleteStub, - onNext: (T) -> Unit = onNextStub + onNext: (T) -> Unit = onNextStub, ): Disposable { return if (onError === onErrorStub && onComplete === onCompleteStub) { subscribe(onNext) @@ -75,7 +75,7 @@ fun FlowableSubscribeProxy.subscribeBy( /** Overloaded subscribe function that allows passing named parameters */ fun SingleSubscribeProxy.subscribeBy( onError: (Throwable) -> Unit = onErrorStub, - onSuccess: (T) -> Unit = onNextStub + onSuccess: (T) -> Unit = onNextStub, ): Disposable { return if (onError === onErrorStub) { subscribe(onSuccess) @@ -88,7 +88,7 @@ fun SingleSubscribeProxy.subscribeBy( fun MaybeSubscribeProxy.subscribeBy( onError: (Throwable) -> Unit = onErrorStub, onComplete: () -> Unit = onCompleteStub, - onSuccess: (T) -> Unit = onNextStub + onSuccess: (T) -> Unit = onNextStub, ): Disposable { return if (onError === onErrorStub && onComplete === onCompleteStub) { subscribe(onSuccess) @@ -100,7 +100,7 @@ fun MaybeSubscribeProxy.subscribeBy( /** Overloaded subscribe function that allows passing named parameters */ fun CompletableSubscribeProxy.subscribeBy( onError: (Throwable) -> Unit = onErrorStub, - onComplete: () -> Unit = onCompleteStub + onComplete: () -> Unit = onCompleteStub, ): Disposable { return if (onError === onErrorStub) { subscribe(onComplete) diff --git a/sample/src/main/kotlin/autodispose2/sample/ArchComponentViewModel.kt b/sample/src/main/kotlin/autodispose2/sample/ArchComponentViewModel.kt index eeb331f9..145d14e5 100644 --- a/sample/src/main/kotlin/autodispose2/sample/ArchComponentViewModel.kt +++ b/sample/src/main/kotlin/autodispose2/sample/ArchComponentViewModel.kt @@ -43,7 +43,8 @@ class ArchComponentViewModel(private val imageRepository: ImageRepository) : Vie class Factory(private val imageRepository: ImageRepository) : ViewModelProvider.Factory { override fun create(modelClass: Class): T { - @Suppress("UNCHECKED_CAST") return ArchComponentViewModel(imageRepository) as T + @Suppress("UNCHECKED_CAST") + return ArchComponentViewModel(imageRepository) as T } } } diff --git a/sample/src/main/kotlin/autodispose2/sample/DisposingViewModel.kt b/sample/src/main/kotlin/autodispose2/sample/DisposingViewModel.kt index 91ba7e45..6aa42d34 100644 --- a/sample/src/main/kotlin/autodispose2/sample/DisposingViewModel.kt +++ b/sample/src/main/kotlin/autodispose2/sample/DisposingViewModel.kt @@ -79,7 +79,7 @@ class DisposingViewModel(private val repository: NetworkRepository) : AutoDispos .subscribe( { progress -> viewRelay.accept(DownloadState.InProgress(progress)) }, { error -> error.printStackTrace() }, - { viewRelay.accept(DownloadState.Completed) } + { viewRelay.accept(DownloadState.Completed) }, ) } @@ -99,7 +99,8 @@ class DisposingViewModel(private val repository: NetworkRepository) : AutoDispos class Factory(private val networkRepository: NetworkRepository) : ViewModelProvider.Factory { override fun create(modelClass: Class): T { - @Suppress("UNCHECKED_CAST") return DisposingViewModel(networkRepository) as T + @Suppress("UNCHECKED_CAST") + return DisposingViewModel(networkRepository) as T } } } diff --git a/sample/src/main/kotlin/autodispose2/sample/KotlinFragment.kt b/sample/src/main/kotlin/autodispose2/sample/KotlinFragment.kt index 04299ce2..60e1d03a 100644 --- a/sample/src/main/kotlin/autodispose2/sample/KotlinFragment.kt +++ b/sample/src/main/kotlin/autodispose2/sample/KotlinFragment.kt @@ -54,7 +54,7 @@ class KotlinFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? + savedInstanceState: Bundle?, ): View? { Log.d(TAG, "onCreateView()") return inflater.inflate(R.layout.content_main, container, false) diff --git a/static-analysis/autodispose-error-prone/src/main/java/autodispose2/errorprone/AbstractReturnValueIgnored.java b/static-analysis/autodispose-error-prone/src/main/java/autodispose2/errorprone/AbstractReturnValueIgnored.java index 4d9cdbdb..f75e44e6 100644 --- a/static-analysis/autodispose-error-prone/src/main/java/autodispose2/errorprone/AbstractReturnValueIgnored.java +++ b/static-analysis/autodispose-error-prone/src/main/java/autodispose2/errorprone/AbstractReturnValueIgnored.java @@ -80,7 +80,7 @@ public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState } private Description matchMethodInvocationNew(MethodInvocationTree tree, VisitorState state) { - boolean matches = specializedMatcher().matches(tree, state); + var matches = specializedMatcher().matches(tree, state); if (!matches) { return Description.NO_MATCH; } @@ -107,7 +107,7 @@ private Description matchMethodInvocationNew(MethodInvocationTree tree, VisitorS @Override public Description matchMemberReference(MemberReferenceTree tree, VisitorState state) { - boolean matches = specializedMatcher().matches(tree, state); + var matches = specializedMatcher().matches(tree, state); if (!matches) { return Description.NO_MATCH; } @@ -169,11 +169,13 @@ private static boolean methodCallInDeclarationOfThrowingRunnable(VisitorState st out: for (Tree t : state.getPath()) { switch (t.getKind()) { - case LAMBDA_EXPRESSION: - case CLASS: + case LAMBDA_EXPRESSION, CLASS -> { tree = t; break out; - default: // fall out, to loop again + } + default -> { + // fall out, to loop again + } } } @@ -261,21 +263,21 @@ private static Matcher identifierHasName(final String name) { */ private Description describe(MethodInvocationTree methodInvocationTree, VisitorState state) { // Find the root of the field access chain, i.e. a.intern().trim() ==> a. - ExpressionTree identifierExpr = ASTHelpers.getRootAssignable(methodInvocationTree); + var identifierExpr = ASTHelpers.getRootAssignable(methodInvocationTree); String identifierStr = null; Type identifierType = null; if (identifierExpr != null) { identifierStr = state.getSourceForNode(identifierExpr); - if (identifierExpr instanceof JCIdent) { - identifierType = ((JCIdent) identifierExpr).sym.type; - } else if (identifierExpr instanceof JCFieldAccess) { - identifierType = ((JCFieldAccess) identifierExpr).sym.type; + if (identifierExpr instanceof JCIdent jcIdent) { + identifierType = jcIdent.sym.type; + } else if (identifierExpr instanceof JCFieldAccess jcFieldAccess) { + identifierType = jcFieldAccess.sym.type; } else { throw new IllegalStateException("Expected a JCIdent or a JCFieldAccess"); } } - Type returnType = getReturnType(((JCMethodInvocation) methodInvocationTree).getMethodSelect()); + var returnType = getReturnType(((JCMethodInvocation) methodInvocationTree).getMethodSelect()); Fix fix; if (identifierStr != null @@ -285,8 +287,8 @@ private Description describe(MethodInvocationTree methodInvocationTree, VisitorS // Fix by assigning the assigning the result of the call to the root receiver reference. fix = SuggestedFix.prefixWith(methodInvocationTree, identifierStr + " = "); } else { - // Unclear what the programmer intended. Delete since we don't know what else to do. - Tree parent = state.getPath().getParentPath().getLeaf(); + // Unclear what the programmer intended. Delete since we don't know what else to do. + var parent = state.getPath().getParentPath().getLeaf(); fix = SuggestedFix.delete(parent); } return describeMatch(methodInvocationTree, fix); @@ -306,11 +308,8 @@ private static boolean expectedExceptionTest(Tree tree, VisitorState state) { // } catch (IllegalArgumentException expected) { // } // - StatementTree statement = ASTHelpers.findEnclosingNode(state.getPath(), StatementTree.class); - if (statement != null && EXPECTED_EXCEPTION_MATCHER.matches(statement, state)) { - return true; - } - return false; + var statement = ASTHelpers.findEnclosingNode(state.getPath(), StatementTree.class); + return statement != null && EXPECTED_EXCEPTION_MATCHER.matches(statement, state); } private static final Matcher FAIL_METHOD = @@ -350,14 +349,13 @@ private static boolean expectedExceptionTest(Tree tree, VisitorState state) { * doReturn(val).when(t)}. */ private static boolean mockitoInvocation(Tree tree, VisitorState state) { - if (!(tree instanceof JCMethodInvocation)) { + if (!(tree instanceof JCMethodInvocation invocation)) { return false; } - JCMethodInvocation invocation = (JCMethodInvocation) tree; if (!(invocation.getMethodSelect() instanceof JCFieldAccess)) { return false; } - ExpressionTree receiver = ASTHelpers.getReceiver(invocation); + var receiver = ASTHelpers.getReceiver(invocation); return MOCKITO_MATCHER.matches(receiver, state); } } diff --git a/static-analysis/autodispose-error-prone/src/main/java/autodispose2/errorprone/UseAutoDispose.java b/static-analysis/autodispose-error-prone/src/main/java/autodispose2/errorprone/UseAutoDispose.java index 70577596..fa1e5ad3 100644 --- a/static-analysis/autodispose-error-prone/src/main/java/autodispose2/errorprone/UseAutoDispose.java +++ b/static-analysis/autodispose-error-prone/src/main/java/autodispose2/errorprone/UseAutoDispose.java @@ -33,12 +33,13 @@ import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher; import com.google.errorprone.matchers.Matcher; import com.google.errorprone.suppliers.Supplier; -import com.google.inject.Inject; import com.sun.source.tree.ClassTree; import com.sun.source.tree.ExpressionTree; import com.sun.tools.javac.code.Type; import java.util.Optional; import java.util.Set; +import javax.inject.Inject; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /** * Checker for subscriptions not binding to lifecycle in components with lifecycle. Use @@ -112,8 +113,7 @@ public UseAutoDispose() { @SuppressWarnings("WeakerAccess") // Public for ErrorProne @Inject public UseAutoDispose(ErrorProneFlags flags) { - Optional> inputClasses = - flags.getList("TypesWithScope").map(ImmutableSet::copyOf); + ImmutableSet inputClasses = flags.getSetOrEmpty("TypesWithScope"); Optional overrideScopes = flags.getBoolean("OverrideScopes"); ImmutableSet classesWithScope = getClassesWithScope(inputClasses, overrideScopes); @@ -150,16 +150,16 @@ public String linkUrl() { * @return the classes on which to apply the error-prone check. */ private static ImmutableSet getClassesWithScope( - Optional> inputClasses, Optional overrideScopes) { - if (inputClasses.isPresent()) { + @MonotonicNonNull ImmutableSet inputClasses, Optional overrideScopes) { + if (!inputClasses.isEmpty()) { if (overrideScopes.isPresent() && overrideScopes.get()) { // The custom scopes are exclusive, just return that. - return inputClasses.get(); + return inputClasses; } else { // The custom scopes aren't exclusive, so bundle them together with default scopes. return ImmutableSet.builder() .addAll(DEFAULT_CLASSES_WITH_LIFECYCLE) - .addAll(inputClasses.get()) + .addAll(inputClasses) .build(); } } else { diff --git a/static-analysis/autodispose-lint/build.gradle.kts b/static-analysis/autodispose-lint/build.gradle.kts index 6238b1fc..395daf32 100644 --- a/static-analysis/autodispose-lint/build.gradle.kts +++ b/static-analysis/autodispose-lint/build.gradle.kts @@ -46,8 +46,8 @@ tasks.withType().configureEach { tasks.withType().configureEach { compilerOptions { // Lint forces its embedded kotlin version, so we need to match it. - apiVersion.set(KotlinVersion.KOTLIN_1_7) - languageVersion.set(KotlinVersion.KOTLIN_1_7) + apiVersion.set(KotlinVersion.KOTLIN_2_0) + languageVersion.set(KotlinVersion.KOTLIN_2_0) jvmTarget.set(libs.versions.lintJvmTarget.map(JvmTarget::fromTarget)) } } diff --git a/static-analysis/autodispose-lint/src/main/kotlin/autodispose2/lint/AutoDisposeDetector.kt b/static-analysis/autodispose-lint/src/main/kotlin/autodispose2/lint/AutoDisposeDetector.kt index 218c95fe..4c685650 100644 --- a/static-analysis/autodispose-lint/src/main/kotlin/autodispose2/lint/AutoDisposeDetector.kt +++ b/static-analysis/autodispose-lint/src/main/kotlin/autodispose2/lint/AutoDisposeDetector.kt @@ -27,6 +27,7 @@ import com.android.tools.lint.detector.api.Scope import com.android.tools.lint.detector.api.Severity import com.android.tools.lint.detector.api.SourceCodeScanner import com.android.tools.lint.detector.api.UImplicitCallExpression +import com.android.tools.lint.detector.api.isIncorrectImplicitReturnInLambda import com.android.tools.lint.detector.api.isJava import com.android.tools.lint.detector.api.isKotlin import com.intellij.psi.PsiMethod @@ -93,8 +94,8 @@ public class AutoDisposeDetector : Detector(), SourceCodeScanner { AutoDisposeDetector::class.java, EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES), EnumSet.of(Scope.JAVA_FILE), - EnumSet.of(Scope.TEST_SOURCES) - ) + EnumSet.of(Scope.TEST_SOURCES), + ), ) private const val OBSERVABLE = "io.reactivex.rxjava3.core.Observable" @@ -111,7 +112,7 @@ public class AutoDisposeDetector : Detector(), SourceCodeScanner { "androidx.lifecycle.LifecycleOwner", "autodispose2.ScopeProvider", "android.app.Activity", - "android.app.Fragment" + "android.app.Fragment", ) private val REACTIVE_TYPES = @@ -208,7 +209,7 @@ public class AutoDisposeDetector : Detector(), SourceCodeScanner { }, callableReferenceChecker = { context, node, calledMethod -> callableReferenceChecker(context, node, calledMethod) { _, _ -> true } - } + }, ) body.accept(visitor) return@let @@ -223,7 +224,7 @@ public class AutoDisposeDetector : Detector(), SourceCodeScanner { context: JavaContext, node: UCallExpression, method: PsiMethod, - isInScope: (JavaEvaluator, UCallExpression) -> Boolean + isInScope: (JavaEvaluator, UCallExpression) -> Boolean, ) { evaluateMethodCall(node, method, context, isInScope) } @@ -232,7 +233,7 @@ public class AutoDisposeDetector : Detector(), SourceCodeScanner { context: JavaContext, node: UCallableReferenceExpression, method: PsiMethod, - isInScope: (JavaEvaluator, UCallExpression) -> Boolean + isInScope: (JavaEvaluator, UCallExpression) -> Boolean, ) { // Check if the resolved call reference is method and check that it's invocation is a // call expression so that we can get it's return type etc. @@ -245,7 +246,7 @@ public class AutoDisposeDetector : Detector(), SourceCodeScanner { private val context: JavaContext, private val callExpressionChecker: (JavaContext, UCallExpression, PsiMethod) -> Unit, private val callableReferenceChecker: - (JavaContext, UCallableReferenceExpression, PsiMethod) -> Unit + (JavaContext, UCallableReferenceExpression, PsiMethod) -> Unit, ) : AbstractUastVisitor() { override fun visitCallExpression(node: UCallExpression): Boolean { @@ -281,7 +282,7 @@ public class AutoDisposeDetector : Detector(), SourceCodeScanner { */ private fun containingClassScopeChecker( evaluator: JavaEvaluator, - node: UCallExpression + node: UCallExpression, ): Boolean { node.getContainingUClass()?.let { callingClass -> return appliedScopes.any { evaluator.inheritsFrom(callingClass, it, false) } @@ -329,7 +330,7 @@ public class AutoDisposeDetector : Detector(), SourceCodeScanner { node: UCallExpression, method: PsiMethod, context: JavaContext, - isInScope: (JavaEvaluator, UCallExpression) -> Boolean + isInScope: (JavaEvaluator, UCallExpression) -> Boolean, ) { if (!getApplicableMethodNames().contains(method.name)) return val evaluator = context.evaluator @@ -377,7 +378,8 @@ public class AutoDisposeDetector : Detector(), SourceCodeScanner { var curr: UElement = prev.uastParent ?: return true while ( curr is UQualifiedReferenceExpression && curr.selector === prev || - curr is UParenthesizedExpression + curr is UParenthesizedExpression || + curr.isIncorrectImplicitReturnInLambda() ) { prev = curr curr = curr.uastParent ?: return true @@ -385,7 +387,8 @@ public class AutoDisposeDetector : Detector(), SourceCodeScanner { @Suppress("RedundantIf") if (curr is UBlockExpression) { - if (curr.sourcePsi is PsiSynchronizedStatement) { + val sourcePsi = curr.sourcePsi + if (sourcePsi is PsiSynchronizedStatement) { return false } // In Java, it's apparent when an expression is unused: @@ -412,7 +415,7 @@ public class AutoDisposeDetector : Detector(), SourceCodeScanner { // It's the last child: see if the parent is unused val parent = skipParenthesizedExprUp(curr.uastParent) - if (parent is ULambdaExpression && isKotlin(curr.sourcePsi)) { + if (parent is ULambdaExpression && sourcePsi != null && isKotlin(sourcePsi.language)) { val expressionType = parent.getExpressionType()?.canonicalText if ( expressionType != null && @@ -428,7 +431,7 @@ public class AutoDisposeDetector : Detector(), SourceCodeScanner { return false } - if (isJava(curr.sourcePsi)) { + if (sourcePsi != null && isJava(sourcePsi.language)) { // In Java there's no implicit passing to the parent return true } diff --git a/static-analysis/autodispose-lint/src/test/kotlin/autodispose2/lint/AutoDisposeDetectorTest.kt b/static-analysis/autodispose-lint/src/test/kotlin/autodispose2/lint/AutoDisposeDetectorTest.kt index 628765d1..91d8377c 100644 --- a/static-analysis/autodispose-lint/src/test/kotlin/autodispose2/lint/AutoDisposeDetectorTest.kt +++ b/static-analysis/autodispose-lint/src/test/kotlin/autodispose2/lint/AutoDisposeDetectorTest.kt @@ -44,11 +44,13 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { // Stub LifecycleOwner private val LIFECYCLE_OWNER = - java(""" + java( + """ package androidx.lifecycle; public interface LifecycleOwner {} - """) + """ + ) .indented() // Stub Fragment @@ -65,11 +67,14 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { // Stub Scope Provider private val SCOPE_PROVIDER = - kotlin(""" + kotlin( + """ package autodispose2 interface ScopeProvider - """).indented() + """ + ) + .indented() // Stub LifecycleScopeProvider private val LIFECYCLE_SCOPE_PROVIDER = @@ -85,19 +90,24 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { // Custom Scope private val CUSTOM_SCOPE = - kotlin(""" + kotlin( + """ package autodispose2.sample class ClassWithCustomScope - """) + """ + ) .indented() private val AUTODISPOSE_CONTEXT = - kotlin(""" + kotlin( + """ package autodispose2 interface AutoDisposeContext - """).indented() + """ + ) + .indented() private val WITH_SCOPE_PROVIDER = kotlin( @@ -108,7 +118,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { fun withScope(scope: ScopeProvider, body: AutoDisposeContext.() -> Unit) { } - """ + """, ) .indented() .within("src/") @@ -124,7 +134,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { fun withScope(scope: Completable, body: AutoDisposeContext.() -> Unit) { } - """ + """, ) .indented() .within("src/") @@ -142,14 +152,14 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { fun Observable.subscribeBy( onNext: (G) -> Unit ): Disposable = subscribe() - """ + """, ) .indented() .within("src/") private fun propertiesFile( lenient: Boolean = true, - kotlinExtensionFunctions: String? = null + kotlinExtensionFunctions: String? = null, ): TestFile.PropertyTestFile { val properties = projectProperties() properties.property(LENIENT, lenient.toString()) @@ -184,7 +194,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expect( @@ -217,7 +227,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .allowCompilationErrors() // Lint 30 doesn't understand subscribeProxies for some reason .run() @@ -256,7 +266,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expect( @@ -305,7 +315,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .allowCompilationErrors() // Lint 30 doesn't understand subscribeWith for some reason .run() @@ -333,7 +343,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expectClean() @@ -360,7 +370,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expect( @@ -393,7 +403,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .allowCompilationErrors() // Lint 30 doesn't understand subscribeProxies for some reason .run() @@ -421,7 +431,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expectClean() @@ -447,7 +457,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expect( @@ -480,7 +490,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .allowCompilationErrors() // Lint 30 doesn't understand subscribeProxies for some reason .run() @@ -508,7 +518,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expectClean() @@ -534,7 +544,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expect( @@ -566,7 +576,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expectClean() @@ -593,7 +603,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expectClean() @@ -620,7 +630,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expect( @@ -653,7 +663,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .allowCompilationErrors() // Lint 30 doesn't understand subscribeProxies for some reason .run() @@ -681,7 +691,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expectClean() @@ -712,7 +722,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expect( @@ -753,7 +763,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expectClean() @@ -785,7 +795,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expectClean() @@ -821,7 +831,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .allowCompilationErrors() // TODO or replace with a real sample stub? .run() @@ -857,7 +867,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expectClean() @@ -885,7 +895,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expectClean() @@ -917,7 +927,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expectClean() @@ -946,7 +956,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expect( @@ -986,7 +996,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expect( @@ -1030,7 +1040,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expectClean() @@ -1063,7 +1073,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expect( @@ -1106,7 +1116,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expectClean() @@ -1139,7 +1149,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expect( @@ -1180,7 +1190,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expect( @@ -1220,7 +1230,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expectClean() @@ -1249,7 +1259,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expectClean() @@ -1278,7 +1288,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expect( @@ -1338,7 +1348,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expect( @@ -1399,7 +1409,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expectClean() @@ -1452,7 +1462,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expect( @@ -1508,7 +1518,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expectClean() @@ -1538,7 +1548,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expectClean() @@ -1571,7 +1581,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expect( @@ -1620,7 +1630,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expect( @@ -1667,7 +1677,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expectClean() @@ -1699,7 +1709,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expectErrorCount(1) @@ -1728,7 +1738,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .run() .expectErrorCount(1) @@ -1760,7 +1770,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .allowCompilationErrors() // Until AGP 8.2.0 // https://issuetracker.google.com/issues/283693338 @@ -1792,7 +1802,7 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { } """ ) - .indented() + .indented(), ) .allowCompilationErrors() // Until AGP 8.2.0 // https://issuetracker.google.com/issues/283693338 @@ -1803,10 +1813,8 @@ internal class AutoDisposeDetectorTest : LintDetectorTest() { private fun jars(): Array { val classLoader = AutoDisposeDetector::class.java.classLoader return arrayOf( - LibraryReferenceTestFile( - File(classLoader.getResource("rxjava-3.1.0.jar")!!.toURI()), - ), - LibraryReferenceTestFile(File(classLoader.getResource("autodispose-2.0.0.jar")!!.toURI())) + LibraryReferenceTestFile(File(classLoader.getResource("rxjava-3.1.0.jar")!!.toURI())), + LibraryReferenceTestFile(File(classLoader.getResource("autodispose-2.0.0.jar")!!.toURI())), ) } diff --git a/test-utils/src/main/java/autodispose2/test/RecordingObserver.java b/test-utils/src/main/java/autodispose2/test/RecordingObserver.java index 933f3bde..59c0c026 100644 --- a/test-utils/src/main/java/autodispose2/test/RecordingObserver.java +++ b/test-utils/src/main/java/autodispose2/test/RecordingObserver.java @@ -28,7 +28,7 @@ import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.TimeUnit; -public final class RecordingObserver<@NonNull T> +public final class RecordingObserver implements Observer, SingleObserver, MaybeObserver, CompletableObserver { public interface Logger {