Skip to content

Commit

Permalink
(riverpod_lint) Add new lint avoid_passing_build_context_to_providers (
Browse files Browse the repository at this point in the history
  • Loading branch information
charlescyt authored Sep 28, 2023
1 parent dfe84e0 commit 7642120
Show file tree
Hide file tree
Showing 5 changed files with 462 additions and 0 deletions.
34 changes: 34 additions & 0 deletions packages/riverpod_lint/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Riverpod_lint adds various warnings with quick fixes and refactoring options, su
- [provider\_dependencies (riverpod\_generator only)](#provider_dependencies-riverpod_generator-only)
- [scoped\_providers\_should\_specify\_dependencies (generator only)](#scoped_providers_should_specify_dependencies-generator-only)
- [avoid\_manual\_providers\_as\_generated\_provider\_dependency](#avoid_manual_providers_as_generated_provider_dependency)
- [avoid\_build\_context\_in\_providers (riverpod\_generator only)](#avoid_build_context_in_providers-riverpod_generator-only)
- [provider\_parameters](#provider_parameters)
- [avoid\_public\_notifier\_properties](#avoid_public_notifier_properties)
- [unsupported\_provider\_value (riverpod\_generator only)](#unsupported_provider_value-riverpod_generator-only)
Expand Down Expand Up @@ -346,6 +347,39 @@ int example(ExampleRef ref) {
}
```

### avoid_build_context_in_providers (riverpod_generator only)

Providers should not interact with `BuildContext`.

**Good**:

```dart
@riverpod
int fn(FnRef ref) => 0;
@riverpod
class MyNotifier extends _$MyNotifier {
int build() => 0;
void event() {}
}
```

**Bad**:

```dart
// Providers should not receive a BuildContext as a parameter.
int fn(FnRef ref, BuildContext context) => 0;
@riverpod
class MyNotifier extends _$MyNotifier {
int build() => 0;
// Notifiers should not have methods that receive a BuildContext as a parameter.
void event(BuildContext context) {}
}
```

### provider_parameters

Providers' parameters should have a consistent ==. Meaning either the values should be cached, or the parameters should override ==.
Expand Down
2 changes: 2 additions & 0 deletions packages/riverpod_lint/lib/riverpod_lint.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'src/assists/convert_to_widget_utils.dart';
import 'src/assists/functional_to_class_based_provider.dart';
import 'src/assists/wrap_with_consumer.dart';
import 'src/assists/wrap_with_provider_scope.dart';
import 'src/lints/avoid_build_context_in_providers.dart';
import 'src/lints/avoid_manual_providers_as_generated_provider_dependency.dart';
import 'src/lints/avoid_public_notifier_properties.dart';
import 'src/lints/avoid_ref_inside_state_dispose.dart';
Expand All @@ -24,6 +25,7 @@ PluginBase createPlugin() => _RiverpodPlugin();
class _RiverpodPlugin extends PluginBase {
@override
List<LintRule> getLintRules(CustomLintConfigs configs) => [
const AvoidBuildContextInProviders(),
const AvoidPublicNotifierProperties(),
const FunctionalRef(),
const MissingProviderScope(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/error/listener.dart';
import 'package:custom_lint_builder/custom_lint_builder.dart';

import '../riverpod_custom_lint.dart';

const TypeChecker buildContextType = TypeChecker.fromName(
'BuildContext',
packageName: 'flutter',
);

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

static const _code = LintCode(
name: 'avoid_build_context_in_providers',
problemMessage:
'Passing BuildContext to providers indicates mixing UI with the business logic.',
errorSeverity: ErrorSeverity.WARNING,
);

@override
void run(
CustomLintResolver resolver,
ErrorReporter reporter,
CustomLintContext context,
) {
riverpodRegistry(context).addFunctionalProviderDeclaration((declaration) {
final parameters = declaration.node.functionExpression.parameters!;
_emitWarningsForBuildContext(reporter, parameters);
});

riverpodRegistry(context).addClassBasedProviderDeclaration((declaration) {
final methods = declaration.node.members.whereType<MethodDeclaration>();

for (final method in methods) {
final parameters = method.parameters!;
_emitWarningsForBuildContext(reporter, parameters);
}
});
}

void _emitWarningsForBuildContext(
ErrorReporter reporter,
FormalParameterList parameters,
) {
final buildContextParameters = parameters.parameters.where(
(e) =>
e.declaredElement?.type != null &&
buildContextType.isExactlyType(e.declaredElement!.type),
);

for (final contextParameter in buildContextParameters) {
reporter.reportErrorForNode(_code, contextParameter);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import 'package:flutter/widgets.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'avoid_build_context_in_providers.g.dart';

@riverpod
int fn(
FnRef ref,
// expect_lint: avoid_build_context_in_providers
BuildContext context1, {
// expect_lint: avoid_build_context_in_providers
required BuildContext context2,
}) =>
0;

@riverpod
class MyNotifier extends _$MyNotifier {
int build(
// expect_lint: avoid_build_context_in_providers
BuildContext context1, {
// expect_lint: avoid_build_context_in_providers
required BuildContext context2,
}) =>
0;

void event(
// expect_lint: avoid_build_context_in_providers
BuildContext context3, {
// expect_lint: avoid_build_context_in_providers
required BuildContext context4,
}) {}
}
Loading

0 comments on commit 7642120

Please sign in to comment.