Flutter自定义@tupleRequired注解:基于参数类型触发警告需求
Got it, let's build this custom @tupleRequired annotation for Flutter that triggers static warnings based on the tuple type. Here's a step-by-step implementation:
First, we'll use the custom_lint package to create our custom static check. Add these dev dependencies to your pubspec.yaml:
dev_dependencies: custom_lint: ^0.5.0 custom_lint_builder: ^0.5.0 meta: ^1.9.0 # For the Required base class
Next, confirm your base classes and annotation are defined (you mentioned these already exist, but here's a reference):
import 'package:meta/meta.dart'; // Base tuple classes abstract class Tuple {} abstract class NullTuple extends Tuple {} abstract class ParamTuple extends Tuple {} // Custom annotation extending @required class TupleRequired extends Required { const TupleRequired(); }
Create a new file (e.g., tuple_required_lint.dart) in your project to define the lint detector. This rule will scan method invocations, check for @tupleRequired annotations, and validate parameter usage:
import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:custom_lint_builder/custom_lint_builder.dart'; class TupleRequiredLint extends DartLintRule { TupleRequiredLint() : super(code: _code); // Define the lint code with custom messages static const _code = LintCode( name: 'tuple_parameter_mismatch', problemMessage: 'Incorrect tuple parameter usage', correctionMessage: 'Adjust parameter based on its tuple type', ); @override void run( CustomLintResolver resolver, ErrorReporter reporter, CustomLintContext context, ) { // Listen for method invocations in the code context.registry.addMethodInvocation((node) { final methodElement = node.methodName.staticElement as MethodElement?; if (methodElement == null) return; // Check each parameter of the method for (final param in methodElement.parameters) { // Verify if the parameter has @tupleRequired annotation final hasTupleRequired = param.metadata.any( (meta) => meta.element?.name == 'TupleRequired', ); if (!hasTupleRequired) continue; // Get the parameter's type and check its tuple parent class final paramType = param.type; final isNullTuple = paramType.isSubtypeOf( resolver.typeProvider.getType('NullTuple'), ); final isParamTuple = paramType.isSubtypeOf( resolver.typeProvider.getType('ParamTuple'), ); if (!isNullTuple && !isParamTuple) continue; // Check if the parameter was passed in the current invocation final passedArg = node.argumentList.arguments.firstWhere( (arg) => arg is NamedExpression && arg.name.label.name == param.name, orElse: () => null, ); // Trigger warnings based on tuple type if (isNullTuple) { // Warn if NullTuple subclass parameter is passed if (passedArg != null) { reporter.reportErrorForNode( _code, passedArg, ['This NullTuple parameter is redundant and will be ignored'], ); } } else if (isParamTuple) { // Warn if ParamTuple subclass parameter is missing if (passedArg == null) { reporter.reportErrorForNode( _code, node.methodName, ['This ParamTuple parameter must be provided'], ); } } } }); } }
Update your analysis_options.yaml to enable the custom lint plugin and rule:
analyzer: plugins: - custom_lint linter: rules: - custom_lint/tuple_parameter_mismatch
Use your example classes to verify the warnings work as expected:
// Define concrete tuple subclasses class Tuple0 extends NullTuple {} class Tuple1 extends ParamTuple {} class Example { void nullParam({@tupleRequired Tuple0 param}) {} void withParam({@tupleRequired Tuple1 param}) {} } void main() { final example = Example(); // This will trigger a warning: "This NullTuple parameter is redundant and will be ignored" example.nullParam(param: Tuple0()); // This will trigger a warning: "This ParamTuple parameter must be provided" example.withParam(); // No warnings here (correct usage) example.nullParam(); example.withParam(param: Tuple1()); }
Once everything is set up, your IDE (like Android Studio or VS Code) will show the static warnings in real-time, just like the built-in @required annotation.
内容的提问来源于stack exchange,提问作者mohammad

