Skip to content
This repository was archived by the owner on Jul 16, 2023. It is now read-only.
5 changes: 3 additions & 2 deletions doc/rules/prefer-const-border-radius.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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<String, Object> config = const {}])
Expand Down
Original file line number Diff line number Diff line change
@@ -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<void> {
final _expressions = <InstanceCreationExpression>[];
Expand All @@ -13,10 +13,19 @@ class _Visitor extends RecursiveAstVisitor<void> {
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);
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)',
],
);
});
Expand Down