saropa_lints 6.1.0
saropa_lints: ^6.1.0 copied to clipboard
1964 custom lint rules with 119 quick fixes for Flutter and Dart. Static analysis for security, accessibility, and performance.
Changelog #
All notable changes to this project will be documented in this file. The format is based on Keep a Changelog, and this project adheres to Semantic Versioning. Dates are not included in version headers — pub.dev displays publish dates separately.
Looking for older changes?
See CHANGELOG_ARCHIVE.md for versions 0.1.0 through 5.0.3.
** See the current published changelog: saropa_lints/changelog
6.1.0 #
Added #
- avoid_cascade_notation (Stylistic): Discourage use of cascade notation (..) for clarity and maintainability. Reports every cascade expression. Fixture:
example_style/lib/stylistic_control_flow/avoid_cascade_notation_fixture.dart. - prefer_fold_over_reduce (Stylistic): Prefer fold() with an explicit initial value over reduce() for collections (clarity and empty-collection safety). Fixture:
example_core/lib/collection/prefer_fold_over_reduce_fixture.dart. - avoid_expensive_log_string_construction (Professional): Flag log() calls whose message argument is a string interpolation; the string is built even when the log level would not print it. Suggests a level guard or lazy message.
- avoid_returning_this (Stylistic): Flag methods that return
this; prefer explicit return types or void. - avoid_cubit_usage (Stylistic): Prefer Bloc over Cubit for event traceability (Bloc package only). Runs only when bloc package is a dependency.
- prefer_expression_body_getters (Stylistic): Prefer arrow (=>) for getters with a single return statement.
- prefer_final_fields_always (Stylistic): All instance fields should be final. Stricter than
prefer_final_fields(which only flags when never reassigned). - prefer_block_body_setters (Comprehensive): Prefer block body {} for setters instead of expression body.
- avoid_riverpod_string_provider_name (Professional): Detect manual name strings in Riverpod providers; prefer auto-generated name. Documented in
doc/guides/using_with_riverpod.md.avoid_cubit_usagedocumented indoc/guides/using_with_bloc.md. - prefer_factory_before_named (Comprehensive): Place factory constructors before named constructors in class member order.
- prefer_then_catcherror (Stylistic): Prefer .then().catchError() over try/catch for async error handling when handling a single Future.
- avoid_types_on_closure_parameters (Stylistic): Closure parameters with explicit types; consider removing when the type can be inferred.
- prefer_fire_and_forget (Stylistic): Suggest unawaited/fire-and-forget when await result is unused.
- prefer_for_in_over_foreach (Stylistic): Prefer for-in over .forEach() on iterables.
- prefer_foreach_over_map_entries (Stylistic): Prefer for-in over map.entries instead of Map.forEach.
- prefer_base_prefix (Stylistic): Abstract class names should end with Base.
- prefer_extension_suffix (Stylistic): Extension names should end with Ext.
- prefer_mixin_prefix (Stylistic): Mixin names should end with Mixin.
- prefer_overrides_last (Stylistic): Place override methods after non-override members.
- prefer_i_prefix_interfaces (Stylistic): Abstract class (interface) names should start with I.
- prefer_no_i_prefix_interfaces (Stylistic): Abstract class names should not start with I (opposite of prefer_i_prefix_interfaces).
- prefer_impl_suffix (Stylistic): Classes that implement an interface should end with Impl.
- prefer_constructor_over_literals (Stylistic): Prefer List.empty(), Map(), Set.empty() over empty list/set/map literals.
- prefer_constructors_over_static_methods (Stylistic): Prefer factory constructor when static method only returns new SameClass().
- format_test_name (Stylistic): Test names (first argument to test/testWidgets) must be snake_case.
- avoid_explicit_type_declaration (Stylistic): Prefer type inference when variable has initializer.
- prefer_explicit_null_checks (Stylistic): Prefer explicit == null / != null over !.
- prefer_non_const_constructors (Stylistic): Prefer omitting const on constructors (opinionated).
- prefer_separate_assignments (Stylistic): Prefer separate statements over cascade assignments (..).
- prefer_optional_named_params (Stylistic): Prefer optional named parameters over optional positional.
- prefer_optional_positional_params (Stylistic): Prefer optional positional over optional named for bool/flag parameters.
- prefer_positional_bool_params (Stylistic): Boolean parameters as optional positional at call sites.
- prefer_if_else_over_guards (Stylistic): Consecutive guard clauses could be expressed as if-else.
- prefer_cascade_assignments (Stylistic): Consecutive method calls on same target; consider cascade (..).
- prefer_factory_constructor (Stylistic): Prefer factory constructor over static method returning same class.
- require_auto_route_page_suffix (Stylistic): AutoRoute page classes should have a Page suffix.
- prefer_inline_function_types (Stylistic): Prefer inline function type over typedef.
- prefer_function_over_static_method (Stylistic): Static method without "this" could be top-level function.
- prefer_static_method_over_function (Stylistic): Top-level function with class-typed first param could be static/extension.
- avoid_unnecessary_null_aware_elements (Professional): Flag spread elements using
...?when the collection is non-null; suggest...instead. - prefer_import_over_part (Stylistic): Prefer import over part/part of for modularity.
- prefer_result_type (Professional): Functions should declare an explicit return type (except main).
- avoid_freezed_invalid_annotation_target (Professional): @freezed should only be used on class declarations.
- require_const_list_items (Comprehensive): List items that are no-argument constructor calls should be const when possible.
- prefer_asmap_over_indexed_iteration (Professional): Prefer asMap().entries for indexed iteration over manual index loops.
- avoid_test_on_real_device (Professional): Flag test names that suggest running on real device; prefer emulators/simulators in CI.
- avoid_referencing_subclasses (Professional): Base classes should not reference their subclasses (e.g. return/parameter types).
- prefer_correct_throws (Professional): Suggest @Throws annotation for methods/functions that throw.
- prefer_layout_builder_for_constraints (Professional): Prefer LayoutBuilder for constraint-aware layout instead of MediaQuery for widget sizing.
- prefer_cache_extent (Comprehensive): ListView.builder/GridView.builder should specify cacheExtent for predictable scroll performance. Fixture:
example_widgets/lib/scroll/prefer_cache_extent_fixture.dart. - prefer_biometric_protection (Professional): FlutterSecureStorage should use authenticationRequired in AndroidOptions/IOSOptions. Fixture:
example_async/lib/security/prefer_biometric_protection_fixture.dart. - avoid_renaming_representation_getters (Professional): Extension type should not expose the representation via a getter with a different name. Fixture:
example_core/lib/class_constructor/avoid_renaming_representation_getters_fixture.dart.
Fixed #
-
Publish script (audit failure): When the pre-publish audit fails, the script now auto-fixes only the missing
[rule_name]prefix in problem messages when applicable, then re-runs the audit. For other blocking issues (tier integrity, duplicates, spelling, .contains() baseline), it exits with a single clear message pointing to the ✗ lines in the audit output instead of offering the DX message improver (which cannot fix those). -
Report duplicate paths: The analysis report log counted the same violation twice when the same issue was reported with both relative and absolute file paths (e.g.
lib/foo.dartandD:\proj\lib\foo.dart). Consolidation now normalizes all paths to project-relative form before deduplication and in stored violation records, so totals and "files with issues" are accurate. Seebugs/history/report_duplicate_paths_deduplication.md.
Archive #
- Rules 5.0.3 and older moved to CHANGELOG_ARCHIVE.md
6.0.10 #
Fixed #
- avoid_deprecated_usage (analyzer 9): Fixed plugin crash (
NoSuchMethodError: SimpleIdentifierImpl has no getter 'staticElement') when running under analyzer 9.x. Rule now uses a compatibility helper that supports both.element(analyzer 9+) and.staticElement(older). Seebugs/history/report_avoid_deprecated_usage_analyzer_api_crash.md. - Lint message text: Removed duplicated or malformed text in
correctionMessageacross 11 rule files. No rule logic, tiers, or behavior changed. code_quality_rules:no_boolean_literal_compare— removed duplicate phrase "!x instead of x == false". structure_rules:prefer_small_length_test_files,avoid_medium_length_test_files,avoid_long_length_test_files,avoid_very_long_length_test_files— added missing space before "Disable with:". dependency_injection_rules:prefer_constructor_injection— typo "parameter:." → "parameter.", added space before example. equatable_rules:prefer_equatable_mixin— fixed "keeping." → "keeping " and sentence order. widget_lifecycle_rules:require_timer_cancellation,nullify_after_dispose— added space before continuation. ios_rules:avoid_ios_deprecated_uikit— added space before "See Xcode warnings...". record_pattern_rules:avoid_explicit_pattern_field_name— fixed "instead of." and message order. widget_layout_rules:prefer_spacing_over_sizedbox,avoid_deep_widget_nesting,prefer_safe_area_aware— fixed split/space so sentences read correctly. testing_best_practices_rules:avoid_flaky_tests— fixed "instead of." and sentence order. test_rules:avoid_test_coupling,require_test_isolation,avoid_real_dependencies_in_tests— fixed comma/period and continuation order.
6.0.9 #
Fixed #
- False positive reduction: Replaced substring/
.contains()with exact match, word-boundary regex, or type checks. CI baselines updated or removed where violations reached 0. Grouped by rule file; all affected rules listed:- animation_rules:
require_animation_controller_dispose— dispose check usesisFieldCleanedUp()fromtarget_matcher_utilsinstead of regex ondisposeBody. - api_network_rules:
require_http_status_check,require_retry_logic,require_connectivity_check,require_request_timeout,prefer_http_connection_reuse,avoid_redundant_requests,require_response_caching,prefer_api_pagination,require_offline_indicator,prefer_streaming_response,avoid_over_fetching,require_cancel_token,require_websocket_error_handling,avoid_websocket_without_heartbeat,prefer_timeout_on_requests,require_permission_rationale,require_permission_status_check,require_notification_permission_android13,require_sqflite_migration,require_websocket_reconnection,require_typed_api_response,require_image_picker_result_handling,require_sse_subscription_cancel— word-boundary regex or exact sets. Baseline removed (0 violations). - async_rules:
require_feature_flag_default, DateTime UTC storage rule, stream listen/StreamController rules,avoid_dialog_context_after_async,require_websocket_message_validation,require_loading_timeout,prefer_broadcast_stream, mounted/setState visitors,require_network_status_check,require_pending_changes_indicator,avoid_stream_sync_events,require_stream_controller_close,avoid_stream_subscription_in_field,require_stream_subscription_no_leak— exact target set,extractTargetName+endsWith, word-boundary regex, or exactStreamSubscriptiontype. Baseline removed. - disposal_rules:
require_media_player_dispose,require_tab_controller_dispose,require_receive_port_close,require_socket_close,require_debouncer_cancel,require_interval_timer_cancel,require_file_handle_close—disposeBody.contains(...)replaced withisFieldCleanedUp(). All disposal rules —typeName.contains(...)replaced with word-boundary RegExp for media/Tab/WebSocket/VideoPlayer/StreamSubscription/ReceivePort/Socket types. Baseline removed. - file_handling_rules: PDF rules, sqflite (whereargs, transaction, error handling, batch, close, reserved word, singleton, column constants), large-file rule,
require_file_path_sanitization— word-boundary regex or static lists. Baseline removed. - navigation_rules:
avoid_deep_link_sensitive_params,prefer_typed_route_params,avoid_circular_redirects,require_deep_link_fallback,require_stepper_validation,require_step_count_indicator,require_go_router_typed_params,require_url_launcher_encoding,avoid_navigator_context_issue— exact property name for queryParameters/pathSegments/pathParameters or word-boundary regex. Baseline removed. - permission_rules:
require_location_permission_rationale,require_camera_permission_check,prefer_image_cropping— word-boundary regex for rationale, camera check, cropper/crop/ImageCropper, profile-context keywords. Baseline removed. - provider_rules:
avoid_provider_for_single_value(exact set for Proxy/Multi),prefer_selector_over_single_watch(regex for.select(),avoid_provider_value_rebuild(endsWith('Provider')). - security_rules: RequireSecureStorageRule, RequireBiometricFallbackRule, AvoidStoringPasswordsRule, RequireTokenRefreshRule, AvoidJwtDecodeClientRule, RequireLogoutCleanupRule, RequireDeepLinkValidationRule, AvoidPathTraversalRule, RequireDataEncryptionRule, AvoidLoggingSensitiveDataRule, RequireSecureStorageForAuthRule, AvoidRedirectInjectionRule, PreferLocalAuthRule, RequireSecureStorageAuthDataRule, AvoidStoringSensitiveUnencryptedRule, HTTP client rule, RequireCatchLoggingRule, RequireSecureStorageErrorHandlingRule, AvoidSecureStorageLargeDataRule, RequireClipboardPasteValidationRule, OAuth PKCE rule, session timeout rule, AvoidStackTraceInProductionRule, RequireInputValidationRule — word-boundary RegExp or RegExp.escape. Baseline removed.
- widget_lifecycle_rules:
require_scroll_controller_dispose,require_focus_node_dispose— disposal check uses RegExp for.dispose()instead ofdisposeBody.contains('.dispose()'). Baseline 18→16. - False-positive reduction (complete): All remaining
.contains()anti-patterns in rule files removed. Tests:anti_pattern_detection_testasserts 9 dangerous patterns (sync with publish script);false_positive_fixes_testdocuments word-boundary regression. Discussion 062 archived tobugs/history/. Replaced with word-boundaryRegExp,isFieldCleanedUp/isExactTargetfromtarget_matcher_utils, or exact-set checks in: accessibility_rules, animation_rules, bluetooth_hardware_rules, collection_rules, dependency_injection_rules, disposal_rules, drift_rules, error_handling_rules, equatable_rules, geolocator_rules, get_it_rules, getx_rules, hive_rules, internationalization_rules, isar_rules, json_datetime_rules, memory_management_rules, package_specific_rules, state_management_rules, stylistic_error_testing_rules, type_safety_rules, ui_ux_rules, url_launcher_rules, workmanager_rules.test/anti_pattern_detection_test.dartbaseline emptied (0 violations); any new dangerous.contains()will fail CI.
- animation_rules:
- prefer_permission_request_in_context: Use exact match for Permission target (
PermissionorPermission.*) instead of substring match to avoid false positives on unrelated types.
Changed #
- Roadmap:
- Verified all 185
bugs/roadmaptask files againstlib/src/tiers.dart; none correspond to implemented rules. - Rule quality subsection made self-contained: describes the String.contains() anti-pattern audit (121+ instances across rule files; remediation via exact-match sets or type checks) and
test/anti_pattern_detection_test.dart; removed references to obsolete review documents. - Planned Enhancements table (Discussion #55–#61) removed; details live in
bugs/discussion/(one file per discussion). - Planned rules that have a task file in
bugs/roadmap/were removed from ROADMAP tables; ROADMAP now points to bugs/roadmap/ for task specs. - Deferred content merged into ROADMAP.md (Part 2). ROADMAP_DEFERRED.md removed as redundant.
- Cross-File Analysis CLI roadmap (formerly ROADMAP_CLI.md) merged into ROADMAP.md as Part 3: Cross-File Analysis CLI Tool Roadmap. ROADMAP_CLI.md removed.
- Verified all 185
- CHANGELOG: 6.0.7 Added section — consolidated six separate "new lint rules" lists into one list of 55 rules, removed redundant rule-name headers, and ordered entries alphabetically for readability.
- require_app_startup_error_handling: Documented that the rule only runs when the project has a crash-reporting dependency (e.g. firebase_crashlytics, sentry_flutter).
- Tier reclassification (no orphans): Rule logic, unit tests, and false-positive suppressors unchanged; only tier set membership in
lib/src/tiers.dartupdated. Moved to Essential:check_mounted_after_async,avoid_drift_raw_sql_interpolation. Moved to Recommended:prefer_semver_version,prefer_correct_package_name,require_macos_notarization_ready,avoid_animation_rebuild_waste,require_deep_link_fallback,require_stepper_validation,require_immutable_bloc_state. - Severity reclassification:
LintCodeseverity only; when the rule fires is unchanged. CI using--fatal-infosmay now fail where it did not. WARNING → ERROR:require_unknown_route_handler,avoid_circular_redirects,check_mounted_after_async,require_https_only,require_route_guards. - Discussion 062 (false positive reduction review): Archived to
bugs/history/discussion_062_false_positive_reduction_review.md(audit complete 2026-03-01). Ongoing guidance: CONTRIBUTING.md § Avoiding False Positives and.claude/skills/lint-rules/SKILL.md§ Reducing False Positives.
Added #
- Publish script (test coverage): Rule-instantiation status is now derived from the codebase. The Test Coverage report shows a "Rule inst." line (categories with a Rule Instantiation group / categories with a test file) and lists categories missing that group. Implemented in
scripts/modules/_rule_metrics.py(_compute_rule_instantiation_stats); does not readbugs/UNIT_TEST_COVERAGE_REVIEW.md. - Tests (behavioral): Added a second test in
test/fixture_lint_integration_test.dartthat runs custom_lint on example_async and asserts specific rule codes (avoid_catch_all, avoid_dialog_context_after_async, require_stream_controller_close, require_feature_flag_default, prefer_specifying_future_value_type) appear in parsed violations when custom_lint runs. When no violations are reported (e.g. resolver conflict), per-rule assertions are skipped. Updatedbugs/UNIT_TEST_COVERAGE_REVIEW.md§4 (Real behavioral tests — Started). - Tests (rule instantiation, full coverage): Added the Rule Instantiation group to the remaining 45 category test files (bluetooth_hardware, build_method, code_quality, dependency_injection, dialog_snackbar, file_handling, formatting, iap, internationalization, json_datetime, media, money, numeric_literal, permission, record_pattern, resource_management, state_management, stylistic_additional, stylistic_control_flow, stylistic_error_testing, stylistic_null_collection, stylistic, stylistic_whitespace_constructor, stylistic_widget, test, testing_best_practices, unnecessary_code, widget_layout, widget_patterns, plus packages: drift, flame, flutter_hooks, geolocator, graphql, package_specific, qr_scanner, shared_preferences, supabase, url_launcher, workmanager, and platforms: android, ios, linux, macos, windows). All 99 category test files now have Rule Instantiation (one test per rule: code.name, problemMessage, correctionMessage). Updated
bugs/UNIT_TEST_COVERAGE_REVIEW.md§3. - Tests:
test/fixture_lint_integration_test.dart— runsdart run custom_linton example_async and asserts output is parseable withparseViolations. - Missing fixtures (single-per-category): Added fixtures and test list entries for: freezed (
avoid_freezed_any_map_issue), notification (prefer_local_notification_for_immediate), type_safety (avoid_redundant_null_check), ui_ux (prefer_master_detail_for_large), widget_lifecycle (require_init_state_idempotent). - Missing fixtures (two-per-category batch): Added fixtures and test list entries for: api_network (
prefer_batch_requests,require_compression), code_quality (avoid_inferrable_type_arguments), collection (avoid_function_literals_in_foreach_calls,prefer_inlined_adds), firebase (avoid_firebase_user_data_in_auth,require_firebase_app_check_production), stylistic_additional (prefer_sorted_imports,prefer_import_group_comments), web (avoid_js_rounded_ints,prefer_csrf_protection). - Missing fixtures (three-per-category batch): Added fixtures and test list entries for: control_flow (
avoid_double_and_int_checks,prefer_if_elements_to_conditional_expressions,prefer_null_aware_method_calls), hive (avoid_hive_datetime_local,avoid_hive_type_modification,avoid_hive_large_single_entry), performance (avoid_cache_stampede,prefer_binary_format,prefer_pool_pattern), widget_patterns (avoid_print_in_production,avoid_static_route_config,require_locale_for_text). - Missing fixtures (naming_style, type, class_constructor): Added fixtures and test list entries for: naming_style (
prefer_adjective_bool_getters,prefer_lowercase_constants,prefer_noun_class_names,prefer_verb_method_names), type (avoid_shadowing_type_parameters,avoid_private_typedef_functions,prefer_final_locals,prefer_const_declarations), class_constructor (avoid_accessing_other_classes_private_members,avoid_unused_constructor_parameters,avoid_field_initializers_in_const_classes,prefer_asserts_in_initializer_lists,prefer_const_constructors_in_immutables,prefer_final_fields). - UNIT_TEST_COVERAGE_REVIEW.md: Updated §2 table to show 0 missing fixtures for all 27 categories; added completion note and marked recommendation as done.
- Tests (rule instantiation): Added Rule Instantiation groups to
animation_rules_test.dart(19 rules),collection_rules_test.dart(25 rules),control_flow_rules_test.dart(31 rules),type_rules_test.dart(18 rules),naming_style_rules_test.dart(28 rules),class_constructor_rules_test.dart(20 rules),structure_rules_test.dart(45 rules). Each test instantiates the rule and assertscode.name,problemMessagecontains[code_name],problemMessage.length> 50, andcorrectionMessageis non-null. - Tests (rule instantiation, expanded): Added the same Rule Instantiation group to 24 additional category test files:
api_network_rules_test.dart(38),firebase_rules_test.dart(28),performance_rules_test.dart(46),ui_ux_rules_test.dart(19),widget_lifecycle_rules_test.dart(36),type_safety_rules_test.dart(17),async_rules_test.dart(46),security_rules_test.dart(55),navigation_rules_test.dart(36),accessibility_rules_test.dart(39),provider_rules_test.dart(26),riverpod_rules_test.dart(34),bloc_rules_test.dart(46),getx_rules_test.dart(23),architecture_rules_test.dart(9),documentation_rules_test.dart(9),dio_rules_test.dart(14),get_it_rules_test.dart(3),image_rules_test.dart(22),scroll_rules_test.dart(17),equatable_rules_test.dart(14),forms_rules_test.dart(27), andfreezed_rules_test.dart(10). These tests catch registration and code-name mismatches; behavioral tests (linter-on-code) remain a separate effort. Updatedbugs/UNIT_TEST_COVERAGE_REVIEW.md§1 and §3 accordingly. - Missing fixtures (structure): Added fixtures and test list entries for:
avoid_classes_with_only_static_members,avoid_setters_without_getters,prefer_getters_before_setters,prefer_static_before_instance,prefer_mixin_over_abstract,prefer_record_over_tuple_class,prefer_sealed_classes,prefer_sealed_for_state,prefer_constructors_first,prefer_extension_methods,prefer_extension_over_utility_class,prefer_extension_type_for_wrapper. - Tests (rule instantiation + fixtures): Added rule-instantiation tests (code.name, problemMessage, correctionMessage) and/or missing fixtures for: Debug:
prefer_fail_test_case,avoid_debug_print,avoid_unguarded_debug,prefer_commenting_analyzer_ignores,prefer_debugPrint,avoid_print_in_release,require_structured_logging,avoid_sensitive_in_logs,require_log_level_for_production. Complexity:avoid_bitwise_operators_with_booleans,avoid_cascade_after_if_null,avoid_complex_arithmetic_expressions,avoid_complex_conditions,avoid_duplicate_cascades,avoid_excessive_expressions,avoid_immediately_invoked_functions,avoid_nested_shorthands,avoid_multi_assignment,binary_expression_operand_order,prefer_moving_to_variable,prefer_parentheses_with_if_null,avoid_deep_nesting,avoid_high_cyclomatic_complexity. Connectivity:require_connectivity_error_handling,avoid_connectivity_equals_internet,require_connectivity_timeout(fixture added). Sqflite:avoid_sqflite_type_mismatch,prefer_sqflite_encryption(fixture added). Config:avoid_hardcoded_config,avoid_hardcoded_config_test,avoid_mixed_environments,require_feature_flag_type_safety,avoid_string_env_parsing,avoid_platform_specific_imports,prefer_semver_version. Lifecycle:avoid_work_in_paused_state,require_resume_state_refresh,require_did_update_widget_check,require_late_initialization_in_init_state,require_app_lifecycle_handling,require_conflict_resolution_strategy. Return:avoid_returning_cascades,avoid_returning_void,avoid_unnecessary_return,prefer_immediate_return,prefer_returning_shorthands,avoid_returning_null_for_void,avoid_returning_null_for_future. Exception:avoid_non_final_exception_class_fields,avoid_only_rethrow,avoid_throw_in_catch_block,avoid_throw_objects_without_tostring,prefer_public_exception_classes. Equality:avoid_equal_expressions,avoid_negations_in_equality_checks,avoid_self_assignment,avoid_self_compare,avoid_unnecessary_compare_to,no_equal_arguments,avoid_datetime_comparison_without_precision. Crypto:avoid_hardcoded_encryption_keys,prefer_secure_random_for_crypto,avoid_deprecated_crypto_algorithms,require_unique_iv_per_encryption,require_secure_key_generation. Db_yield:require_yield_after_db_write,suggest_yield_after_db_read,avoid_return_await_db. Context:avoid_storing_context,avoid_context_across_async,avoid_context_after_await_in_static,avoid_context_in_async_static,avoid_context_in_static_methods,avoid_context_dependency_in_callback. Theming:require_dark_mode_testing,avoid_elevation_opacity_in_dark,prefer_theme_extensions,require_semantic_colors. Platform:require_platform_check,prefer_platform_io_conditional,prefer_foundation_platform_check. Notification:require_notification_channel_android,avoid_notification_payload_sensitive,require_notification_initialize_per_platform,require_notification_timezone_awareness,avoid_notification_same_id,prefer_notification_grouping,avoid_notification_silent_failure,prefer_local_notification_for_immediate. Memory management:avoid_large_objects_in_state,require_image_disposal,avoid_capturing_this_in_callbacks,require_cache_eviction_policy,prefer_weak_references_for_cache,avoid_expando_circular_references,avoid_large_isolate_communication,require_cache_expiration,avoid_unbounded_cache_growth,require_cache_key_uniqueness,avoid_retaining_disposed_widgets,avoid_closure_capture_leaks,require_expando_cleanup. Disposal:require_media_player_dispose,require_tab_controller_dispose,require_text_editing_controller_dispose,require_page_controller_dispose,require_lifecycle_observer,avoid_websocket_memory_leak,require_video_player_controller_dispose,require_stream_subscription_cancel,require_change_notifier_dispose,require_receive_port_close,require_socket_close,require_debouncer_cancel,require_interval_timer_cancel,require_file_handle_close,require_dispose_implementation,prefer_dispose_before_new_instance,dispose_class_fields. Error handling:avoid_swallowing_exceptions,avoid_losing_stack_trace,avoid_generic_exceptions,require_error_context,prefer_result_pattern,require_async_error_documentation,avoid_nested_try_statements,require_error_boundary,avoid_uncaught_future_errors,avoid_print_error,require_error_handling_graceful,avoid_catch_all,avoid_catch_exception_alone,avoid_exception_in_constructor,require_cache_key_determinism,require_permission_permanent_denial_handling,require_notification_action_handling,require_finally_cleanup,require_error_logging,require_app_startup_error_handling,avoid_assert_in_production,handle_throwing_invocations.
6.0.7 #
Fixed #
- Unimplemented rule references: Removed four rules from the plugin registry, tiers, analysis_options_template, and roadmap fixture that were never implemented:
avoid_equals_and_hash_code_on_mutable_classes,avoid_implementing_value_types,avoid_null_checks_in_equality_operators,avoid_redundant_argument_values. They remain documented in CHANGELOG 6.0.6 Added; can be re-added when implemented. - require_yield_after_db_write: Suppress when write is last statement, when next statement is
return, when insidecompute()/Isolate.run(), and when file is in test directory. RecognizeFuture.microtask,Future.delayed(Duration.zero), andSchedulerBinding.instance.endOfFrameas valid yields. Replace fragiletoString()check in SchedulerBinding detection with AST-based identifier check. - verify_documented_parameters_exist: Whitelist built-in types and literals (
[String],[int],[null], etc.) to avoid false positives on valid doc references. - Style: Satisfy
curly_braces_in_flow_control_structuresin rule implementation files (api_network, control_flow, lifecycle, naming_style, notification, sqflite, performance, web, security, structure, ui_ux, widget_patterns). Single-statementifbodies are now wrapped in blocks; no behavior change.
Changed #
- Firebase reauth rule: Reauth is now compared by source offset (earliest reauth in method) so order is correct regardless of visit order.
- Firebase token rule: Stored detection now includes VariableDeclaration initializer (e.g.
final t = await user.getIdToken()). - Performance: Firebase Auth rules set requiredPatterns for earlier file skip when content does not match.
- no_empty_block: Confirmed existing implementation in
unnecessary_code_rules.dart; roadmap task archived. - GitHub:
- Closed issues #13 (prefer_pool_pattern), #14 (require_expando_cleanup), #15 (require_compression), #16 (prefer_batch_requests), #18 (prefer_binary_format). Each was commented with resolution version v6.0.7 and closed as completed.
- Closed issues #20, #29 (require_pagination_for_large_lists, v6.0.7), #25, #34 (require_rtl_layout_support, v4.15.1), #24, #33 (prefer_sliverfillremaining_for_empty, v4.14.5), #26, #35 (require_stepper_state_management, v4.14.5), #38 (avoid_infinite_scroll_duplicate_requests, v4.14.5). Each was commented with the resolution version and closed as completed.
Added #
- 55 new lint rules:
avoid_deprecated_usage(Recommended, WARNING) — use of deprecated APIs from other packages; same-package and generated files ignored.avoid_unnecessary_containers(Recommended, INFO) — Container with only child (and optionally key); remove and use child directly (widget files only).banned_usage(Professional, WARNING) — Configurable ban list for identifiers (e.g.print). No-op without config inanalysis_options_custom.yaml. Whole-word match; optionalallowedFilesper entry.handle_throwing_invocations(Professional, INFO) — invocations that can throw (e.g. @Throws, readAsStringSync, jsonDecode) not in try/catch.prefer_adjacent_strings(Recommended, INFO) — use adjacent string literals instead of+for literal concatenation.prefer_adjective_bool_getters(Professional, INFO) — bool getters should use predicate names (is/has/can) not verb names (validate/load).prefer_asserts_in_initializer_lists(Professional, INFO) — move leading assert() from constructor body to initializer list.prefer_batch_requests(Professional, INFO) — await in for-loop with fetch-like method names; suggest batch endpoints. Resolves #16.prefer_binary_format(Comprehensive, INFO) — jsonDecode in hot path (timer/stream); suggest protobuf/MessagePack or compute(). Resolves #18.prefer_const_constructors_in_immutables(Professional, INFO) — @immutable or StatelessWidget/StatefulWidget subclasses with only final fields should have a const constructor.prefer_const_declarations(Recommended, INFO) — final variables with constant initializers could be const (locals, static, top-level).prefer_const_literals_to_create_immutables(Recommended, INFO) — non-const collection literals passed to immutable widget constructors (widget files only).prefer_constructors_first(Professional, INFO) — constructors should appear before methods in a class.prefer_csrf_protection(Professional, WARNING) — State-changing HTTP with Cookie header must include CSRF token or Bearer auth. Web/WebView projects only. OWASP M3/A07.prefer_extension_methods(Professional, INFO) — top-level functions that could be extension methods on first parameter type.prefer_extension_over_utility_class(Professional, INFO) — class with only static methods sharing first param type could be an extension.prefer_extension_type_for_wrapper(Professional, INFO) — single-field wrapper class could be an extension type (Dart 3.3+).prefer_final_fields(Professional, INFO) — fields never reassigned (except via setter) could be final.prefer_final_locals(Recommended, INFO) — local variables never reassigned should be final.prefer_form_bloc_for_complex(Professional, INFO) — Form with >5 fields suggests form state management (FormBloc, reactive_forms, etc.).prefer_getters_before_setters(Professional, INFO) — setter should appear after its getter.prefer_if_elements_to_conditional_expressions(Recommended, INFO) — use if element instead of ternary with null in collections.prefer_inlined_adds(Recommended, INFO) — prefer inline list/set literal over empty then add/addAll.prefer_interpolation_to_compose(Recommended, INFO) — prefer string interpolation over + with literals.prefer_local_notification_for_immediate(Recommended, INFO) — FCM for server-triggered messages; use flutter_local_notifications for app-generated.prefer_lowercase_constants(Recommended, INFO) — const/static final should use lowerCamelCase.prefer_master_detail_for_large(Professional, INFO) — list navigation without MediaQuery/LayoutBuilder; suggest master-detail on tablets.prefer_mixin_over_abstract(Professional, INFO) — abstract class with no abstract members and no generative constructor → mixin.prefer_named_bool_params(Professional, INFO) — prefer named bool parameters in small functions.prefer_no_commented_code— Alias for existingprefer_no_commented_out_code(stylistic).prefer_noun_class_names(Professional, INFO) — concrete classes should use noun/agent names, not gerund/-able.prefer_null_aware_method_calls(Recommended, INFO) — use ?. instead of if (x != null) { x.foo(); }.prefer_pool_pattern(Comprehensive, INFO) — non-const allocation in hot path (timer/animation); suggest object pool. Resolves #13.prefer_raw_strings(Professional, INFO) — use raw string when only escaped backslashes (e.g. regex).prefer_record_over_tuple_class(Professional, INFO) — simple data class with only final fields → record.prefer_sealed_classes(Professional, INFO) — abstract class with 2+ concrete subclasses in same file → sealed.prefer_sealed_for_state(Professional, INFO) — state/event/result abstract with local subclasses → sealed.prefer_semver_version(Essential, WARNING) — pubspec.yamlversionmust be major.minor.patch (e.g. 1.0.0, 2.3.1+4). Reports when invalid.prefer_sqflite_encryption(Professional, WARNING) — Sensitive DB paths (user/auth/health/payment etc.) with sqflite should use sqflite_sqlcipher. OWASP M9.prefer_static_before_instance(Professional, INFO) — static members before instance in same category.prefer_verb_method_names(Professional, INFO) — methods should use verb names, not noun-only.require_compression(Comprehensive, INFO) — HTTP get/post/put/delete without Accept-Encoding; suggest gzip. Resolves #15.require_conflict_resolution_strategy(Professional, WARNING) — Sync/upload/push methods that overwrite data should compare timestamps or show conflict UI.require_connectivity_timeout(Essential, WARNING) — HTTP/client/dio requests must have a timeout (e.g..timeout(Duration(seconds: 30))).require_error_handling_graceful— flag raw exception (e.toString(), e.message, $e) shown in Text/SnackBar/AlertDialog inside catch blocks; recommend friendly messages.require_exhaustive_sealed_switch— switch on sealed types must use explicit cases; avoid default/wildcard (same logic as avoid_wildcard_cases_with_sealed_classes, Essential-tier name).require_expando_cleanup(Comprehensive, INFO) — Expando with entries added but no cleanup (expando[key] = null). Resolves #14.require_firebase_reauthentication— sensitive Firebase Auth ops (delete, updateEmail, updatePassword) must be preceded by reauthenticateWithCredential/reauthenticateWithProvider in the same method (firebase_auth only).require_firebase_token_refresh— getIdToken() result stored (variable/prefs) without idTokenChanges listener or forceRefresh (firebase_auth only).require_init_state_idempotent(Essential, WARNING) — addListener/addObserver in initState must have matching removeListener/removeObserver in dispose (Flutter widget files).require_input_validation(Essential, WARNING) — Raw controller.textin post/put/patch body without trim/validate/isEmpty. OWASP M1/M4.require_late_access_check(Professional, WARNING) — late non-final field set in a method other than constructor/initState and read in another method without initialization check; risk of LateInitializationError.require_pagination_for_large_lists(Essential, WARNING) — ListView.builder/GridView.builder with itemCount from bulk-style list (e.g. allProducts.length) without pagination; OOM and jank risk. Suppressed when project uses infinite_scroll_pagination. Resolves #20, #29.require_ssl_pinning_sensitive(Professional, WARNING) — HTTP POST/PUT/PATCH to sensitive paths (/auth, /login, /token) without certificate pinning; OWASP M5, M3. Suppressed when project uses http_certificate_pinning or ssl_pinning_plugin, and for localhost.require_text_scale_factor_awareness— Container/SizedBox with literal height containing Text may overflow at large text scale; recommend flexible layout (widget files only).
6.0.6 #
Added #
- 15 new lint rules:
avoid_bool_in_widget_constructors(Professional, INFO) — widget constructors with named bool params; prefer enum or decompositionavoid_classes_with_only_static_members(Recommended, INFO) — prefer top-level functions/constantsavoid_double_and_int_checks(Professional, INFO) — flagis int && is double(always false) andis int || is double(useis num)avoid_equals_and_hash_code_on_mutable_classes(Professional, INFO) — custom ==/hashCode with mutable fields breaks Set/Mapavoid_escaping_inner_quotes(Stylistic, INFO) — switch quote delimiter to avoid escaped inner quotesavoid_field_initializers_in_const_classes(Professional, INFO) — move field initializers to const constructor initializer listavoid_function_literals_in_foreach_calls(Stylistic, INFO) — prefer for-in over .forEach with a literalavoid_implementing_value_types(Professional, INFO) — implements type with custom ==/hashCode without overriding themavoid_js_rounded_ints(Comprehensive, INFO) — integer literals exceeding JS safe integer range (2^53)avoid_null_checks_in_equality_operators(Professional, INFO) — redundant other == null when is! type test presentavoid_positional_boolean_parameters(Professional, INFO) — use named parameters for boolsavoid_private_typedef_functions(Comprehensive, INFO) — private typedef for function type; prefer inline typeavoid_redundant_argument_values(Recommended, INFO) — named argument equals parameter defaultavoid_setters_without_getters(Professional, INFO) — setter with no matching getteravoid_single_cascade_in_expression_statements(Stylistic, INFO) — single cascade as statement; use direct call
Changed #
- Init wizard (stylistic walkthrough): Boolean naming rules are in their own category so "[a] enable all in category" applies to all four; progress shows global position (e.g. 51/143) on resume instead of resetting to 1/N; GOOD/BAD labels are bold and colored; the four boolean rules now have distinct good/bad examples (fields, params, locals, and all booleans) so the wizard differentiates them clearly.
Fixed #
require_minimum_contrast— ignore comments were not honored; rule now respects// ignore: require_minimum_contrastand// ignore_for_file: require_minimum_contrast(and hyphenated forms) viaIgnoreUtils
6.0.5 #
Fixed #
avoid_path_traversal— false positive when trusted platform path (e.g.,getApplicationDocumentsDirectory) is passed to a private helper method; now traces trust through call sites of private methodsrequire_file_path_sanitization— same false positive asavoid_path_traversal; shared inter-procedural platform path trust check
6.0.4 #
Fixed #
avoid_dynamic_sql— false positive on SQLite PRAGMA statements which do not support parameter binding; now exempts PRAGMA syntax. Also improved SQL keyword matching to use word boundaries (prevents false positives from identifiers likeselection,updateTime)avoid_ref_read_inside_build— false positive onref.read()inside callbacks (onPressed, onSubmit, etc.) defined inline inbuild(); now stops traversal at closure boundariesavoid_ref_in_build_body— same false positive as above; now shares the corrected visitor withavoid_ref_read_inside_buildavoid_ref_watch_outside_build— false positive onref.watch()inside Riverpod provider bodies (Provider,StreamProvider,FutureProvider, etc.); now recognizes provider callbacks as reactive contexts alongsidebuild()avoid_path_traversal— false positive when file path parameter originates from platform path APIs (getApplicationDocumentsDirectory,getTemporaryDirectory, etc.); now recognizes these as trusted sourcesrequire_file_path_sanitization— same false positive asavoid_path_traversal; now recognizes platform path APIs as trustedavoid_unsafe_collection_methods— false positive on.first/.lastwhen guarded by early-return (if (list.isEmpty) return;) or when the collection is a callback parameter guaranteed non-empty (e.g.,SegmentedButton.onSelectionChanged)avoid_unsafe_reduce— false positive onreduce()guarded byif (list.length < N) return;orif (list.isEmpty) return;; now detects early-return and if/ternary guardsrequire_app_startup_error_handling— false positive on apps without a crash reporting dependency; now only fires when a monitoring package (e.g.,firebase_crashlytics,sentry_flutter) is detected in pubspec.yamlrequire_search_debounce— false positive when Timer-based debounce is defined as a class field rather than inline in the callback; now checks enclosing class for Timer/Debouncer field declarationsrequire_minimum_contrast— false positive when text color is light but background is set via a variable that can't be resolved statically; now recognizes containers with unresolvable background colors as intentionally set
6.0.3 #
Fixed #
avoid_drift_close_streams_in_tests— rule never fired becausetestRelevancewas not overridden; the framework skipped test files before the rule could run. Now correctly set toTestRelevance.testOnlyavoid_drift_update_without_where— removed unreachable dead code branch
6.0.2 #
Changed #
- Widened
analysis_server_pluginandanalyzer_plugindependency constraints from pinned to^range to reduce version conflicts for consumers
Fixed #
- CI publish workflow: dry run step failed on exit code 65 (warnings) due to
set -ekilling the shell before the exit code could be evaluated; warnings are now reported via GitHub Actions annotations without blocking the publish
6.0.1 #
Added #
- 10 additional Drift lint rules covering common gotchas, Value semantics, migration safety, and Isar-to-Drift migration patterns (total: 31 Drift rules)
avoid_drift_value_null_vs_absent(Recommended, WARNING) — detectsValue(null)instead ofValue.absent()require_drift_equals_value(Recommended, WARNING) — detects.equals()with enum/converter columns instead of.equalsValue()require_drift_read_table_or_null(Recommended, WARNING) — detectsreadTable()with leftOuterJoin instead ofreadTableOrNull()require_drift_create_all_in_oncreate(Recommended, WARNING) — detectsonCreatecallback missingcreateAll()avoid_drift_validate_schema_production(Professional, WARNING) — detectsvalidateDatabaseSchema()without debug guardavoid_drift_replace_without_all_columns(Professional, INFO) — detects.replace()on update builder instead of.write()avoid_drift_missing_updates_param(Professional, INFO) — detectscustomUpdate/customInsertwithoutupdatesparameteravoid_isar_import_with_drift(Recommended, WARNING) — detects files importing both Isar and Drift packagesprefer_drift_foreign_key_declaration(Professional, INFO) — detectsId-suffixed columns withoutreferences()require_drift_onupgrade_handler(Recommended, WARNING) — detects schemaVersion > 1 withoutonUpgradehandler
Fixed #
avoid_drift_missing_updates_param— missing drift import check caused false positives on non-driftcustomUpdate()callsprefer_drift_foreign_key_declaration— false positives on non-FK column names (androidId,deviceId,sessionId, etc.)require_drift_equals_value— false positives on non-enum uppercase types (DateTime,Duration,BigInt, etc.)require_drift_onupgrade_handler— reduced performance cost by checking individual members instead of full classtoSource()
6.0.0 #
Breaking #
- Upgraded
analyzerfrom ^8.0.0 to ^9.0.0 - Pinned
analysis_server_pluginto 0.3.4 (only version targeting analyzer v9) - Pinned
analyzer_pluginto 0.13.11 (only version targeting analyzer v9) - Requires Dart SDK >=3.10.0
Added #
- 21 new Drift (SQLite) database lint rules covering data safety, resource management, SQL injection prevention, migration correctness, performance, and web platform safety
avoid_drift_enum_index_reorder(Essential, ERROR)require_drift_database_close(Recommended, WARNING)avoid_drift_update_without_where(Recommended, WARNING)require_await_in_drift_transaction(Recommended, WARNING)require_drift_foreign_key_pragma(Recommended, WARNING)avoid_drift_raw_sql_interpolation(Recommended, ERROR)prefer_drift_batch_operations(Recommended, WARNING)require_drift_stream_cancel(Recommended, WARNING)avoid_drift_database_on_main_isolate(Professional, INFO)avoid_drift_log_statements_production(Professional, WARNING)avoid_drift_get_single_without_unique(Professional, INFO)prefer_drift_use_columns_false(Professional, INFO)avoid_drift_lazy_database(Professional, INFO)prefer_drift_isolate_sharing(Professional, INFO)avoid_drift_query_in_migration(Comprehensive, WARNING)require_drift_schema_version_bump(Comprehensive, INFO)avoid_drift_foreign_key_in_migration(Comprehensive, INFO)require_drift_reads_from(Comprehensive, INFO)avoid_drift_unsafe_web_storage(Comprehensive, INFO)avoid_drift_close_streams_in_tests(Comprehensive, INFO)avoid_drift_nullable_converter_mismatch(Comprehensive, INFO)
- Drift added as supported package in package filtering system
Changed #
- Migrated all
NamedType.name2references toNamedType.name(analyzer v9 API) - Migrated
VariableDeclaration.declaredElementtodeclaredFragment.element(analyzer v9 API) - Removed deprecated
errorCodeparameter fromSaropaDiagnosticReporter.atOffset()
5.0.3 and Earlier #
For details on the initial release and versions 0.1.0 through 5.0.3, please refer to CHANGELOG_ARCHIVE.md.