-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: defined_void_callback_type (#39)
* feat: defined_void_callback_type * docs: add docs for defined_void_callback_type * test: add not lint test patterns * docs: fix target sdk
- Loading branch information
Showing
5 changed files
with
199 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
92 changes: 92 additions & 0 deletions
92
packages/nilts/lib/src/lints/defined_void_callback_type.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import 'package:analyzer/dart/element/type.dart'; | ||
import 'package:analyzer/error/error.dart'; | ||
import 'package:analyzer/error/listener.dart'; | ||
import 'package:custom_lint_builder/custom_lint_builder.dart'; | ||
import 'package:nilts/src/change_priority.dart'; | ||
|
||
/// A class for `defined_void_callback_type` rule. | ||
/// | ||
/// This rule checks defining `void Function()` type. | ||
/// | ||
/// - Target SDK: Any versions nilts supports | ||
/// - Rule type: Practice | ||
/// - Maturity level: Experimental | ||
/// - Quick fix: ✅ | ||
/// | ||
/// **Consider** replace `void Function()` with `VoidCallback` which is defined | ||
/// in Flutter SDK. | ||
/// | ||
/// **BAD:** | ||
/// ```dart | ||
/// final void Function() callback; | ||
/// ``` | ||
/// | ||
/// **GOOD:** | ||
/// ```dart | ||
/// final VoidCallback callback; | ||
/// ``` | ||
class DefinedVoidCallbackType extends DartLintRule { | ||
/// Create a new instance of [DefinedVoidCallbackType]. | ||
const DefinedVoidCallbackType() : super(code: _code); | ||
|
||
static const _code = LintCode( | ||
name: 'defined_void_callback_type', | ||
problemMessage: 'VoidCallback type is defined in Flutter SDK.', | ||
url: 'https://github.com/ronnnnn/nilts#defined_void_callback_type', | ||
); | ||
|
||
@override | ||
void run( | ||
CustomLintResolver resolver, | ||
ErrorReporter reporter, | ||
CustomLintContext context, | ||
) { | ||
context.registry.addTypeAnnotation((node) { | ||
final type = node.type; | ||
// Do nothing if the type is not Function. | ||
if (type is! FunctionType) return; | ||
|
||
// Do nothing if Function has parameters. | ||
if (type.parameters.isNotEmpty) return; | ||
|
||
// Do nothing if the return type is not void. | ||
final returnType = type.returnType; | ||
if (returnType is! VoidType) return; | ||
|
||
reporter.reportErrorForNode(_code, node); | ||
}); | ||
} | ||
|
||
@override | ||
List<Fix> getFixes() => [ | ||
_ReplaceWithVoidCallbackType(), | ||
]; | ||
} | ||
|
||
class _ReplaceWithVoidCallbackType extends DartFix { | ||
@override | ||
void run( | ||
CustomLintResolver resolver, | ||
ChangeReporter reporter, | ||
CustomLintContext context, | ||
AnalysisError analysisError, | ||
List<AnalysisError> others, | ||
) { | ||
context.registry.addTypeAnnotation((node) { | ||
if (!node.sourceRange.intersects(analysisError.sourceRange)) return; | ||
|
||
reporter | ||
.createChangeBuilder( | ||
message: 'Replace with VoidCallback', | ||
priority: ChangePriority.replaceWithVoidCallback, | ||
) | ||
.addDartFileEdit((builder) { | ||
final delta = node.question != null ? -1 : 0; | ||
builder.addSimpleReplacement( | ||
node.sourceRange.getMoveEnd(delta), | ||
'VoidCallback', | ||
); | ||
}); | ||
}); | ||
} | ||
} |
79 changes: 79 additions & 0 deletions
79
packages/nilts_test/test/lints/defined_void_callback_type.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
// ignore_for_file: prefer_function_declarations_over_variables | ||
// ignore_for_file: type_init_formals | ||
// ignore_for_file: unused_element | ||
|
||
import 'package:flutter/material.dart'; | ||
|
||
void main() { | ||
runApp(const MainApp()); | ||
} | ||
|
||
class MainApp extends StatelessWidget { | ||
const MainApp({super.key}); | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return MaterialApp( | ||
home: Scaffold( | ||
body: Center( | ||
child: MainButton(() {}), | ||
), | ||
), | ||
); | ||
} | ||
} | ||
|
||
class MainButton extends StatelessWidget { | ||
const MainButton( | ||
// expect_lint: defined_void_callback_type | ||
void Function() this.onPressed, { | ||
// expect_lint: defined_void_callback_type | ||
void Function()? this.onNullablePressed, | ||
void Function(int)? this.onParamPressed, | ||
int Function()? this.onNotVoidPressed, | ||
super.key, | ||
}); | ||
|
||
// expect_lint: defined_void_callback_type | ||
final void Function() onPressed; | ||
// expect_lint: defined_void_callback_type | ||
final void Function()? onNullablePressed; | ||
final void Function(int)? onParamPressed; | ||
final int Function()? onNotVoidPressed; | ||
|
||
void _onPressed( | ||
// expect_lint: defined_void_callback_type | ||
void Function() onPressed, { | ||
// expect_lint: defined_void_callback_type | ||
void Function()? onNullablePressed, | ||
void Function(int)? onParamPressed, | ||
int Function()? onNotVoidPressed, | ||
}) {} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return FilledButton( | ||
onPressed: () { | ||
_onPressed(() {}); | ||
onPressed(); | ||
}, | ||
child: const Text('Hello World!'), | ||
); | ||
} | ||
} | ||
|
||
// expect_lint: defined_void_callback_type | ||
final void Function() globalFunction = () {}; | ||
// expect_lint: defined_void_callback_type | ||
const void Function()? globalNullableFunction = null; | ||
const void Function(int)? globalParamFunction = null; | ||
const int Function()? globalNotVoidFunction = null; | ||
|
||
void _globalFunction( | ||
// expect_lint: defined_void_callback_type | ||
void Function() onPressed, { | ||
// expect_lint: defined_void_callback_type | ||
void Function()? onNullablePressed, | ||
void Function(int)? onParamPressed, | ||
int Function()? onNotVoidPressed, | ||
}) {} |