diff --git a/doc/rules/prefer-const-border-radius.md b/doc/rules/prefer-const-border-radius.md index cd74a7f0ac..8d3be2a6d8 100644 --- a/doc/rules/prefer-const-border-radius.md +++ b/doc/rules/prefer-const-border-radius.md @@ -6,8 +6,9 @@ prefer-const-border-radius ## Description -BorderRadius.circular constructor calls const BorderRadius.all constructor under the hood. This rule allows to replace -BorderRadius.circular(radius) with const BorderRadius.all(Radius.circular(radius)) if radius is a constant value. +[BorderRadius.circular constructor](https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/painting/border_radius.dart#L292-L295) calls `const BorderRadius.all` constructor under the hood. +This rule allows to replace `BorderRadius.circular(radius)` with `const BorderRadius.all(Radius.circular(radius))` if `radius` is a constant value. +With such replacement, you can pass default `BorderRadius` value into your widget constructor. ### Example diff --git a/lib/src/analyzers/lint_analyzer/rules/rules_list/prefer_const_border_radius/prefer_const_border_radius.dart b/lib/src/analyzers/lint_analyzer/rules/rules_list/prefer_const_border_radius/prefer_const_border_radius.dart index 78bc91d660..5b7f183c0a 100644 --- a/lib/src/analyzers/lint_analyzer/rules/rules_list/prefer_const_border_radius/prefer_const_border_radius.dart +++ b/lib/src/analyzers/lint_analyzer/rules/rules_list/prefer_const_border_radius/prefer_const_border_radius.dart @@ -1,5 +1,6 @@ import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/ast/visitor.dart'; +import 'package:analyzer/dart/element/element.dart'; import '../../../../../utils/node_utils.dart'; import '../../../lint_utils.dart'; @@ -15,7 +16,8 @@ part 'visitor.dart'; class PreferConstBorderRadiusRule extends FlutterRule { static const ruleId = 'prefer-const-border-radius'; - static const _issueMessage = 'Prefer use const constructor BorderRadius.all.'; + static const _issueMessage = + 'Prefer using const constructor BorderRadius.all'; static const _replaceComment = 'Replace with const BorderRadius constructor.'; PreferConstBorderRadiusRule([Map config = const {}]) diff --git a/lib/src/analyzers/lint_analyzer/rules/rules_list/prefer_const_border_radius/visitor.dart b/lib/src/analyzers/lint_analyzer/rules/rules_list/prefer_const_border_radius/visitor.dart index 9ca80367d3..97bac24af2 100644 --- a/lib/src/analyzers/lint_analyzer/rules/rules_list/prefer_const_border_radius/visitor.dart +++ b/lib/src/analyzers/lint_analyzer/rules/rules_list/prefer_const_border_radius/visitor.dart @@ -1,7 +1,7 @@ part of 'prefer_const_border_radius.dart'; -const borderRadiusClassName = 'BorderRadius'; -const borderRadiusConstConstructorName = 'circular'; +const _borderRadiusClassName = 'BorderRadius'; +const _borderRadiusConstructorName = 'circular'; class _Visitor extends RecursiveAstVisitor { final _expressions = []; @@ -13,10 +13,19 @@ class _Visitor extends RecursiveAstVisitor { super.visitInstanceCreationExpression(expression); if (expression.staticType?.getDisplayString(withNullability: true) == - borderRadiusClassName && - expression.constructorName.name?.name == - borderRadiusConstConstructorName) { - _expressions.add(expression); + _borderRadiusClassName && + expression.constructorName.name?.name == _borderRadiusConstructorName && + expression.argumentList.arguments.length == 1) { + final arg = expression.argumentList.arguments.first; + + if (arg is Literal) { + _expressions.add(expression); + } else if (arg is Identifier) { + final element = arg.staticElement; + if (element is PropertyAccessorElement && element.variable.isConst) { + _expressions.add(expression); + } + } } } } diff --git a/test/analyzers/lint_analyzer/rules/rules_list/prefer_const_border_radius/examples/example.dart b/test/analyzers/lint_analyzer/rules/rules_list/prefer_const_border_radius/examples/example.dart index 0288fac542..b6884c12a2 100644 --- a/test/analyzers/lint_analyzer/rules/rules_list/prefer_const_border_radius/examples/example.dart +++ b/test/analyzers/lint_analyzer/rules/rules_list/prefer_const_border_radius/examples/example.dart @@ -1,35 +1,75 @@ -const _constRadius = BorderRadius.all(16); -final _finalRadius = BorderRadius.circular(8); // LINT +const _constRadius = BorderRadius.all(Radius.circular(0.0)); +final _finalRadius = BorderRadius.circular(1.0); // LINT +const _constValue = 10.0; +final _finalValue = 15.0; class MyWidget extends StatelessWidget { - static final staticRadius = BorderRadius.circular(32); // LINT + static final staticRadius = BorderRadius.circular(2.0); // LINT + + double foo() => 20.0; Widget build(BuildContext _) { - final buildMethodRadius = BorderRadius.circular(230); // LINT + final buildMethodRadius = BorderRadius.circular(3.0); // LINT + var buildMethodRadiusVar = BorderRadius.circular(4.0); // LINT return Column(children: [ - const Container(borderRadius: _constRadius), - Container(borderRadius: BorderRadius.circular(32)), // LINT - Container(borderRadius: staticRadius), - Container(borderRadius: buildMethodRadius), - Container(borderRadius: _finalRadius), + const ClipRRect(borderRadius: _constRadius), + ClipRRect(borderRadius: BorderRadius.circular(5.0)), // LINT + ClipRRect(borderRadius: staticRadius), + ClipRRect(borderRadius: buildMethodRadius), + ClipRRect(borderRadius: buildMethodRadiusVar), + ClipRRect(borderRadius: BorderRadius.circular(_finalValue)), + ClipRRect(borderRadius: BorderRadius.circular(_constValue)), // LINT + ClipRRect(borderRadius: BorderRadius.circular(foo())), + ClipRRect( + borderRadius: BorderRadius.circular( + _constValue == 10.0 ? 25.0 : 30.0, + ), + ), ]); } } class BorderRadius { - final double borderRadius; + final Radius topLeft; + final Radius topRight; + final Radius bottomLeft; + final Radius bottomRight; + + const BorderRadius.all(Radius radius) + : this.only( + topLeft: radius, + topRight: radius, + bottomLeft: radius, + bottomRight: radius, + ); + + BorderRadius.circular(double radius) : this.all(Radius.circular(radius)); + + const BorderRadius.only({ + this.topLeft = Radius.zero, + this.topRight = Radius.zero, + this.bottomLeft = Radius.zero, + this.bottomRight = Radius.zero, + }); +} + +class Radius { + final double x; + final double y; + + const Radius.circular(double radius) : this.elliptical(radius, radius); - const BorderRadius.all(this.borderRadius); + const Radius.elliptical(this.x, this.y); - BorderRadius.circular(this.borderRadius); + static const Radius zero = Radius.circular(0); } -class Container extends Widget { +class ClipRRect extends Widget { final Widget? child; final BorderRadius? borderRadius; - const Container({this.child, this.borderRadius}); + const ClipRRect({this.child, this.borderRadius}); } class Column extends Widget { diff --git a/test/analyzers/lint_analyzer/rules/rules_list/prefer_const_border_radius/prefer_const_border_radius_test.dart b/test/analyzers/lint_analyzer/rules/rules_list/prefer_const_border_radius/prefer_const_border_radius_test.dart index f2bc274d25..2a300982a2 100644 --- a/test/analyzers/lint_analyzer/rules/rules_list/prefer_const_border_radius/prefer_const_border_radius_test.dart +++ b/test/analyzers/lint_analyzer/rules/rules_list/prefer_const_border_radius/prefer_const_border_radius_test.dart @@ -27,33 +27,41 @@ void main() { RuleTestHelper.verifyIssues( issues: issues, - startOffsets: [64, 170, 269, 417], - startLines: [2, 5, 8, 12], - startColumns: [22, 31, 31, 31], - endOffsets: [88, 195, 295, 442], + startOffsets: [82, 242, 367, 434, 582, 864], + startLines: [2, 7, 12, 13, 17, 22], + startColumns: [22, 31, 31, 32, 31, 31], + endOffsets: [108, 268, 393, 460, 608, 898], messages: [ - 'Prefer use const constructor BorderRadius.all.', - 'Prefer use const constructor BorderRadius.all.', - 'Prefer use const constructor BorderRadius.all.', - 'Prefer use const constructor BorderRadius.all.', + 'Prefer using const constructor BorderRadius.all', + 'Prefer using const constructor BorderRadius.all', + 'Prefer using const constructor BorderRadius.all', + 'Prefer using const constructor BorderRadius.all', + 'Prefer using const constructor BorderRadius.all', + 'Prefer using const constructor BorderRadius.all', ], replacementComments: [ 'Replace with const BorderRadius constructor.', 'Replace with const BorderRadius constructor.', 'Replace with const BorderRadius constructor.', 'Replace with const BorderRadius constructor.', + 'Replace with const BorderRadius constructor.', + 'Replace with const BorderRadius constructor.', ], replacements: [ - 'BorderRadius.all(Radius.circular(8))', - 'BorderRadius.all(Radius.circular(32))', - 'BorderRadius.all(Radius.circular(230))', - 'BorderRadius.all(Radius.circular(32))', + 'BorderRadius.all(Radius.circular(1.0))', + 'BorderRadius.all(Radius.circular(2.0))', + 'BorderRadius.all(Radius.circular(3.0))', + 'BorderRadius.all(Radius.circular(4.0))', + 'BorderRadius.all(Radius.circular(5.0))', + 'BorderRadius.all(Radius.circular(_constValue))', ], locationTexts: [ - 'BorderRadius.circular(8)', - 'BorderRadius.circular(32)', - 'BorderRadius.circular(230)', - 'BorderRadius.circular(32)', + 'BorderRadius.circular(1.0)', + 'BorderRadius.circular(2.0)', + 'BorderRadius.circular(3.0)', + 'BorderRadius.circular(4.0)', + 'BorderRadius.circular(5.0)', + 'BorderRadius.circular(_constValue)', ], ); });