Skip to content

Commit

Permalink
Disable unsupported_provider_value when a notifier returns "this"
Browse files Browse the repository at this point in the history
fixes #2302
  • Loading branch information
rrousselGit committed Apr 6, 2023
1 parent fea8a96 commit 7d73eb3
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/dart/element/type_system.dart';
import 'package:analyzer/error/listener.dart';
import 'package:custom_lint_builder/custom_lint_builder.dart';
import 'package:riverpod_analyzer_utils/riverpod_analyzer_utils.dart';

import '../riverpod_custom_lint.dart';

extension on StatefulProviderDeclaration {
/// Returns whether the value exposed by the provider is the newly created
/// Notifier itself.
bool get returnsSelf {
return valueType == node.declaredElement?.thisType;
}
}

class UnsupportedProviderValue extends RiverpodLintRule {
const UnsupportedProviderValue() : super(code: _code);

Expand All @@ -21,16 +31,26 @@ class UnsupportedProviderValue extends RiverpodLintRule {
) {
void checkCreatedType(GeneratorProviderDeclaration declaration) {
String? invalidValueName;
if (notifierBaseType.isAssignableFromType(declaration.valueType)) {
invalidValueName = 'Notifier';
} else if (asyncNotifierBaseType
.isAssignableFromType(declaration.valueType)) {
invalidValueName = 'AsyncNotifier';
}

/// If a provider returns itself, we allow it. This is to enable
/// ChangeNotifier-like mutable state.
if (invalidValueName != null &&
declaration is StatefulProviderDeclaration &&
declaration.returnsSelf) {
return;
}

if (stateNotifierType.isAssignableFromType(declaration.valueType)) {
invalidValueName = 'StateNotifier';
} else if (changeNotifierType
.isAssignableFromType(declaration.valueType)) {
invalidValueName = 'ChangeNotifier';
} else if (notifierBaseType.isAssignableFromType(declaration.valueType)) {
invalidValueName = 'Notifier';
} else if (asyncNotifierBaseType
.isAssignableFromType(declaration.valueType)) {
invalidValueName = 'AsyncNotifier';
}

if (invalidValueName != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,24 @@ class StateNotifierClass extends _$StateNotifierClass {
Future<MyStateNotifier> stateNotifierAsync(StateNotifierAsyncRef ref) async =>
MyStateNotifier();

// Regression tests for https://github.com/rrousselGit/riverpod/issues/2302
@riverpod
class SelfNotifier extends _$SelfNotifier {
Future<SelfNotifier> build() async => this;
}

// Regression tests for https://github.com/rrousselGit/riverpod/issues/2302
@riverpod
class SyncSelfNotifier extends _$SyncSelfNotifier {
SyncSelfNotifier build() => this;
}

// Regression tests for https://github.com/rrousselGit/riverpod/issues/2302
@riverpod
class StreamSelfNotifier extends _$StreamSelfNotifier {
Stream<StreamSelfNotifier> build() => Stream.value(this);
}

@riverpod
// expect_lint: unsupported_provider_value
class StateNotifierClassAsync extends _$StateNotifierClassAsync {
Expand All @@ -48,6 +66,12 @@ class MyChangeNotifier extends ChangeNotifier {}
// expect_lint: unsupported_provider_value
MyNotifier notifier(NotifierRef ref) => MyNotifier();

@riverpod
// expect_lint: unsupported_provider_value
MyAutoDisposeNotifier autoDisposeNotifier(AutoDisposeNotifierRef ref) {
return MyAutoDisposeNotifier();
}

@riverpod
// expect_lint: unsupported_provider_value
class NotifierClass extends _$NotifierClass {
Expand All @@ -59,6 +83,11 @@ class MyNotifier extends Notifier<int> {
int build() => 0;
}

class MyAutoDisposeNotifier extends AutoDisposeNotifier<int> {
@override
int build() => 0;
}

@riverpod
// expect_lint: unsupported_provider_value
MyAsyncNotifier asyncNotifier(AsyncNotifierRef ref) => MyAsyncNotifier();
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 7d73eb3

Please sign in to comment.