diff --git a/packages/flutter_hooks_lint/CHANGELOG.md b/packages/flutter_hooks_lint/CHANGELOG.md index 9819c25..ca0201a 100644 --- a/packages/flutter_hooks_lint/CHANGELOG.md +++ b/packages/flutter_hooks_lint/CHANGELOG.md @@ -1,3 +1,13 @@ +## 1.0.3 + +- Fixed a bug in `hooks_method_visitor.dart` +- Fixed a bug in `hooks_memoized_consideration` +- Fixed a test for `hooks_unused_test` + +## 1.0.2 + +- Fixed a bug where `Unsupported operation: Cannot extract a file path from a package URI` occurred when running `dart run custom_lint`. + ## 1.0.1 - Change the version range of the analyzer to `>=6.0.0 <7.0.0` diff --git a/packages/flutter_hooks_lint/lib/src/rules/hooks_memoized_consideration_rule.dart b/packages/flutter_hooks_lint/lib/src/rules/hooks_memoized_consideration_rule.dart index dbb4ec2..a0d62fe 100644 --- a/packages/flutter_hooks_lint/lib/src/rules/hooks_memoized_consideration_rule.dart +++ b/packages/flutter_hooks_lint/lib/src/rules/hooks_memoized_consideration_rule.dart @@ -1,3 +1,4 @@ +import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/error/error.dart'; import 'package:analyzer/error/listener.dart'; import 'package:analyzer/source/source_range.dart'; @@ -32,10 +33,25 @@ class HooksMemoizedConsiderationRule extends DartLintRule { }); context.registry.addVariableDeclaration((node) { - final type = node.declaredElement?.type; + final classDeclaration = node.thisOrAncestorOfType(); + final extendsClause = classDeclaration?.extendsClause; + if (extendsClause == null) { + return; + } + final extendsElement = extendsClause.superclass.element; + if (extendsElement == null) { + return; + } + if (!HooksHelper.isHooksElement(extendsElement)) { + return; + } + + final declaredElement = node.declaredElement; + final type = declaredElement?.type; if (type == null) { return; } + if (HooksHelper.isConsiderUseMemoized(type)) { reporter.reportErrorForNode(code, node); } diff --git a/packages/flutter_hooks_lint/lib/src/visitors/hooks_method_visitor.dart b/packages/flutter_hooks_lint/lib/src/visitors/hooks_method_visitor.dart index d4db60a..742d66e 100644 --- a/packages/flutter_hooks_lint/lib/src/visitors/hooks_method_visitor.dart +++ b/packages/flutter_hooks_lint/lib/src/visitors/hooks_method_visitor.dart @@ -2,9 +2,12 @@ import 'package:analyzer/dart/analysis/analysis_context_collection.dart'; import 'package:analyzer/dart/analysis/results.dart'; import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/ast/visitor.dart'; +import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/file_system/physical_file_system.dart'; import 'package:flutter_hooks_lint/src/helpers/hooks_helper.dart'; +final _regexp = RegExp('^use[A-Z]{1}'); + class HooksMethodVisitor extends RecursiveAstVisitor { const HooksMethodVisitor({ required this.onVisitMethodInvocation, @@ -17,15 +20,18 @@ class HooksMethodVisitor extends RecursiveAstVisitor { if (element == null) { return; } + if (element.enclosingElement is ClassElement) { + return; + } final methodName = node.methodName.name; if (HooksHelper.isHooksElement(element)) { onVisitMethodInvocation(node); // NOTE: DO always prefix your hooks with use, https://pub.dev/packages/flutter_hooks#rules. - } else if (methodName.startsWith('use')) { + } else if (_regexp.hasMatch(methodName)) { try { - final filePath = element.librarySource?.uri.toFilePath(); + final filePath = element.librarySource?.fullName; if (filePath != null) { final collection = AnalysisContextCollection( includedPaths: [filePath], @@ -49,7 +55,7 @@ class HooksMethodVisitor extends RecursiveAstVisitor { onVisitMethodInvocation(node); } } catch (e) { - print(e); + print('$methodName: $e'); } } diff --git a/packages/flutter_hooks_lint/pubspec.yaml b/packages/flutter_hooks_lint/pubspec.yaml index 8cff8e4..9e906e1 100644 --- a/packages/flutter_hooks_lint/pubspec.yaml +++ b/packages/flutter_hooks_lint/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_hooks_lint description: A lint package providing guidelines for using flutter_hooks in your Flutter widget! -version: 1.0.2 +version: 1.0.3 homepage: https://github.com/nikaera/flutter_hooks_lint repository: https://github.com/nikaera/flutter_hooks_lint documentation: https://github.com/nikaera/flutter_hooks_lint diff --git a/packages/flutter_hooks_lint_flutter_test/test/hooks_memoized_consideration/hooks_memoized_consideration.dart b/packages/flutter_hooks_lint_flutter_test/test/hooks_memoized_consideration/hooks_memoized_consideration.dart index da30ced..0000f63 100644 --- a/packages/flutter_hooks_lint_flutter_test/test/hooks_memoized_consideration/hooks_memoized_consideration.dart +++ b/packages/flutter_hooks_lint_flutter_test/test/hooks_memoized_consideration/hooks_memoized_consideration.dart @@ -1,7 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; -class ConsiderationMemoizedWidget extends StatelessWidget { +class ConsiderationMemoizedWidget extends HookWidget { @override Widget build(BuildContext context) { final key = GlobalKey(); @@ -31,3 +32,13 @@ class HookConsiderationMemoizedWidget extends HookWidget { return Text(state.value.toString()); } } + +final _globalKeyProvider = Provider((ref) => GlobalKey()); + +class ConsumerConsiderationMemoizedWidget extends ConsumerWidget { + @override + Widget build(BuildContext context, WidgetRef ref) { + final globalKey = ref.watch(_globalKeyProvider); + return Text(globalKey.toString()); + } +} diff --git a/packages/flutter_hooks_lint_flutter_test/test/hooks_memoized_consideration/hooks_memoized_consideration.diff b/packages/flutter_hooks_lint_flutter_test/test/hooks_memoized_consideration/hooks_memoized_consideration.diff index 0666402..a4b86aa 100644 --- a/packages/flutter_hooks_lint_flutter_test/test/hooks_memoized_consideration/hooks_memoized_consideration.diff +++ b/packages/flutter_hooks_lint_flutter_test/test/hooks_memoized_consideration/hooks_memoized_consideration.diff @@ -1,6 +1,6 @@ Message: `Wrap with useMemoized` Priority: 30 -Diff for file `test/hooks_memoized_consideration/hooks_memoized_consideration.dart:7`: +Diff for file `test/hooks_memoized_consideration/hooks_memoized_consideration.dart:8`: ``` @override Widget build(BuildContext context) { @@ -12,7 +12,7 @@ Diff for file `test/hooks_memoized_consideration/hooks_memoized_consideration.da --- Message: `Wrap with useMemoized` Priority: 30 -Diff for file `test/hooks_memoized_consideration/hooks_memoized_consideration.dart:8`: +Diff for file `test/hooks_memoized_consideration/hooks_memoized_consideration.dart:9`: ``` Widget build(BuildContext context) { final key = GlobalKey(); @@ -24,7 +24,7 @@ Diff for file `test/hooks_memoized_consideration/hooks_memoized_consideration.da --- Message: `Wrap with useMemoized` Priority: 30 -Diff for file `test/hooks_memoized_consideration/hooks_memoized_consideration.dart:24`: +Diff for file `test/hooks_memoized_consideration/hooks_memoized_consideration.dart:25`: ``` final state = useState(0); final snapshot = @@ -36,7 +36,7 @@ Diff for file `test/hooks_memoized_consideration/hooks_memoized_consideration.da --- Message: `Wrap with useMemoized` Priority: 30 -Diff for file `test/hooks_memoized_consideration/hooks_memoized_consideration.dart:24`: +Diff for file `test/hooks_memoized_consideration/hooks_memoized_consideration.dart:25`: ``` final state = useState(0); final snapshot = diff --git a/packages/flutter_hooks_lint_flutter_test/test/hooks_unuse_widget/custom_hooks.dart b/packages/flutter_hooks_lint_flutter_test/test/hooks_unuse_widget/custom_hooks.dart index b1e5c11..049cb29 100644 --- a/packages/flutter_hooks_lint_flutter_test/test/hooks_unuse_widget/custom_hooks.dart +++ b/packages/flutter_hooks_lint_flutter_test/test/hooks_unuse_widget/custom_hooks.dart @@ -3,3 +3,11 @@ import 'package:flutter_hooks/flutter_hooks.dart'; void useEffectOnce(Dispose? Function() effect) { useEffect(effect, const []); } + +class TestHelper { + const TestHelper._(); + + static void useEffectOnce(Dispose? Function() effect) { + useEffect(effect, const []); + } +} diff --git a/packages/flutter_hooks_lint_flutter_test/test/hooks_unuse_widget/hooks_unuse_widget.dart b/packages/flutter_hooks_lint_flutter_test/test/hooks_unuse_widget/hooks_unuse_widget.dart index f9c5508..4113f72 100644 --- a/packages/flutter_hooks_lint_flutter_test/test/hooks_unuse_widget/hooks_unuse_widget.dart +++ b/packages/flutter_hooks_lint_flutter_test/test/hooks_unuse_widget/hooks_unuse_widget.dart @@ -28,6 +28,18 @@ class UseCustomHookWidget extends HookWidget { } } +class ClassCustomHookWidget extends HookWidget { + @override + Widget build(BuildContext context) { + // TODO(nikaera): Custom hooks should not be defined within a class in the first place, + // so define them with lint rules. + TestHelper.useEffectOnce(() { + return; + }); + return Text(''); + } +} + class UnuseHookConsumerWidget extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { diff --git a/packages/flutter_hooks_lint_flutter_test/test/hooks_unuse_widget/hooks_unuse_widget.diff b/packages/flutter_hooks_lint_flutter_test/test/hooks_unuse_widget/hooks_unuse_widget.diff index b672560..5fccabb 100644 --- a/packages/flutter_hooks_lint_flutter_test/test/hooks_unuse_widget/hooks_unuse_widget.diff +++ b/packages/flutter_hooks_lint_flutter_test/test/hooks_unuse_widget/hooks_unuse_widget.diff @@ -10,12 +10,24 @@ import 'custom_hooks.dart'; Widget build(BuildContext context) { ``` --- -Message: `Convert to ConsumerWidget` +Message: `Convert to StatelessWidget` Priority: 30 Diff for file `test/hooks_unuse_widget/hooks_unuse_widget.dart:31`: ``` } +- class ClassCustomHookWidget extends HookWidget { ++ class ClassCustomHookWidget extends StatelessWidget { + @override + Widget build(BuildContext context) { +``` +--- +Message: `Convert to ConsumerWidget` +Priority: 30 +Diff for file `test/hooks_unuse_widget/hooks_unuse_widget.dart:43`: +``` +} + - class UnuseHookConsumerWidget extends HookConsumerWidget { + class UnuseHookConsumerWidget extends ConsumerWidget { @override diff --git a/packages/flutter_hooks_lint_flutter_test/test/hooks_unuse_widget/hooks_unuse_widget_test.dart b/packages/flutter_hooks_lint_flutter_test/test/hooks_unuse_widget/hooks_unuse_widget_test.dart index 2654a6d..ef70c3b 100644 --- a/packages/flutter_hooks_lint_flutter_test/test/hooks_unuse_widget/hooks_unuse_widget_test.dart +++ b/packages/flutter_hooks_lint_flutter_test/test/hooks_unuse_widget/hooks_unuse_widget_test.dart @@ -11,7 +11,7 @@ void main() { (result) async { final lint = HooksUnuseWidgetRule(); final errors = await lint.testRun(result); - expect(errors, hasLength(2)); + expect(errors, hasLength(3)); final fixes = lint.getFixes().map((e) => e as DartFix); final results = await Future.wait(errors