Skip to content

Commit

Permalink
Fix "Too many elements" error. (#2316)
Browse files Browse the repository at this point in the history
This was triggered by the analysis incorrectly trying to decode generated
providers as legacy providers.

fixes #2194
  • Loading branch information
rrousselGit authored Mar 13, 2023
1 parent f96052a commit ac605ea
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 11 deletions.
5 changes: 5 additions & 0 deletions packages/riverpod_analyzer_utils/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## Unreleased minor

- Added `providerForType` TypeChecker for `ProviderFor` annotation
- Generated providers inside `.g.dart` no-longer are incorrectly parsed as legacy providers.

## 0.1.4 - 2023-03-10

- Fixed an `Unsupported operation: Unknown type SimpleIdentifierImpl` crash
Expand Down
6 changes: 0 additions & 6 deletions packages/riverpod_analyzer_utils/lib/src/riverpod_ast.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:collection/collection.dart';
import 'package:crypto/crypto.dart';
import 'package:custom_lint_core/custom_lint_core.dart';
import 'package:meta/meta.dart';

import '../riverpod_analyzer_utils.dart';
Expand All @@ -31,11 +30,6 @@ part 'riverpod_ast/widget_ref_invocation.dart';
part 'riverpod_ast/provider_scope.dart';
part 'riverpod_ast/provider_override.dart';

const _providerForAnnotationChecker = TypeChecker.fromName(
'ProviderFor',
packageName: 'riverpod_annotation',
);

@sealed
abstract class RiverpodAst {
RiverpodAst? _parent;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ class ProviderListenableExpression extends RiverpodAst {
if (element is PropertyAccessorElement) {
DartObject? annotation;
try {
annotation = _providerForAnnotationChecker
.firstAnnotationOfExact(element.variable);
annotation =
providerForType.firstAnnotationOfExact(element.variable);
} catch (_) {
return;
}
Expand Down
13 changes: 13 additions & 0 deletions packages/riverpod_analyzer_utils/lib/src/riverpod_element.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:io';

import 'package:analyzer/dart/constant/value.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
Expand Down Expand Up @@ -193,6 +195,14 @@ class LegacyProviderDeclarationElement implements ProviderDeclarationElement {
VariableElement element,
) {
return _cache.putIfAbsent(element, () {
// Search for @ProviderFor annotation. If present, then this is a generated provider
if (providerForType.hasAnnotationOfExact(
element,
throwOnUnresolved: false,
)) {
return null;
}

bool isAutoDispose;
LegacyFamilyInvocationElement? familyElement;
LegacyProviderType providerType;
Expand All @@ -206,6 +216,9 @@ class LegacyProviderDeclarationElement implements ProviderDeclarationElement {
'call',
element.library!,
)!;
if (callFn.parameters.length != 1) {
stdout.writeln('Problem eleemnt: $element');
}
final parameter = callFn.parameters.single;

isAutoDispose = !alwaysAliveProviderListenableType
Expand Down
6 changes: 6 additions & 0 deletions packages/riverpod_analyzer_utils/lib/src/riverpod_types.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import 'package:custom_lint_core/custom_lint_core.dart';

/// TypeChecker for the `ProviderFor` annotation
const providerForType = TypeChecker.fromName(
'ProviderFor',
packageName: 'riverpod_annotation',
);

/// Matches with the `Riverpod` annotation from riverpod_annotation.
const riverpodType =
TypeChecker.fromName('Riverpod', packageName: 'riverpod_annotation');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import 'package:riverpod_analyzer_utils/riverpod_analyzer_utils.dart';
import 'package:riverpod_generator/src/riverpod_generator.dart';
import 'package:test/test.dart';

int _testNumber = 0;

/// Due to [resolveSource] throwing if trying to interact with the resolver
/// after the future completed, we change the syntax to make sure our test
/// executes within the resolver scope.
Expand All @@ -20,17 +22,21 @@ void testSource(
required String source,
bool runGenerator = false,
}) {
final testId = _testNumber++;
test(
description,
() async {
// Giving a unique name to the package to avoid the analyzer cache
// messing up tests.
final packageName = 'test_lib$testId';
final sourceWithLibrary = 'library foo;$source';

final enclosingZone = Zone.current;

String? generated;
if (runGenerator) {
final analysisResult = await resolveSources(
{'test_lib|lib/foo.dart': sourceWithLibrary},
{'$packageName|lib/foo.dart': sourceWithLibrary},
(resolver) {
return resolver.resolveRiverpodLibraryResult(
ignoreErrors: true,
Expand All @@ -41,9 +47,9 @@ void testSource(
}

await resolveSources({
'test_lib|lib/foo.dart': sourceWithLibrary,
'$packageName|lib/foo.dart': sourceWithLibrary,
if (generated != null)
'test_lib|lib/foo.g.dart': 'part of "foo.dart";$generated',
'$packageName|lib/foo.g.dart': 'part of "foo.dart";$generated',
}, (resolver) async {
try {
final originalZone = Zone.current;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,28 @@ import 'analyser_test_utils.dart';

void main() {
group('LegacyProviderDefinition.parse', () {
testSource('Does not try to parse generated providers',
runGenerator: true, source: '''
import 'package:riverpod/riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'foo.g.dart';
final legacy = Provider<int>((ref) => 0);
@riverpod
int simple(SimpleRef ref) => 0;
// Regression test for https://github.com/rrousselGit/riverpod/issues/2194
@riverpod
int complex(ComplexRef ref, {int? id, String? another}) => 0;
''', (resolver) async {
final result = await resolver.resolveRiverpodAnalyssiResult();

expect(result.legacyProviderDeclarations, hasLength(1));
expect(result.generatorProviderDeclarations, hasLength(2));
});

testSource('Decode name', source: '''
import 'package:riverpod/riverpod.dart';
Expand Down
4 changes: 4 additions & 0 deletions packages/riverpod_lint/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## Unreleased fix

- No-longer throw "Bad state: Too many elements"

## 1.1.5 - 2023-03-10

- `riverpod_analyzer_utils` upgraded to `0.1.4`
Expand Down

0 comments on commit ac605ea

Please sign in to comment.