-
Notifications
You must be signed in to change notification settings - Fork 166
Lint for SizedBox.shrink(...)
and SizedBox.expand(...)
#3039
Changes from 6 commits
fa50b93
7783d72
18fbbee
3c4b01e
ad2cd87
cb49098
7949bac
a23896f
52afbec
33878df
33e2474
0b7f972
cbced5f
a100c3e
975f8f4
03ee685
bd3582c
e308807
48fa245
e4f0b0b
bd4a9d4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
import 'package:analyzer/dart/ast/ast.dart'; | ||
import 'package:analyzer/dart/ast/visitor.dart'; | ||
|
||
import '../analyzer.dart'; | ||
import '../util/flutter_utils.dart'; | ||
|
||
const _sizedBoxShrinkDescription = | ||
r'Use the SizedBox.shrink(...) named constructor.'; | ||
pq marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
const _sizedBoxExpandDescription = | ||
r'Use the SizedBox.expand(...) named constructor'; | ||
|
||
const _details = | ||
r'''Use SizedBox.shrink and SizedBox.expand constructors appropriately. | ||
|
||
The `SizedBox.shrink(...)` and `SizedBox.expand(...)` constructors should be used | ||
instead of the more general `SizedBox(...)` constructor for specific use cases. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider defining / describing the use cases for which this lint applies. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Took a first swing, unsure how I feel about it tho There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe something that suggests this is for readability purposes? /fyi @goderbauer @Hixie who might have opinions. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe replace the generic "for specific use cases" with "to improve readability"? |
||
|
||
**Examples** | ||
|
||
**BAD:** | ||
``` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider adding the dart language tag to these code blocks. =>
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
Widget buildLogo() { | ||
return SizedBox( | ||
height: 0, | ||
width: 0, | ||
child:const MyLogo(), | ||
); | ||
} | ||
``` | ||
``` | ||
Widget buildLogo() { | ||
return SizedBox( | ||
height: double.infinity, | ||
width: double.infinity, | ||
child:const MyLogo(), | ||
); | ||
} | ||
``` | ||
|
||
**GOOD:** | ||
``` | ||
Widget buildLogo() { | ||
return SizedBox.shrink( | ||
child:const MyLogo(), | ||
); | ||
} | ||
``` | ||
``` | ||
Widget buildLogo() { | ||
return SizedBox.expand( | ||
child:const MyLogo(), | ||
); | ||
} | ||
``` | ||
'''; | ||
|
||
class SizedBoxShrinkExpand extends LintRule { | ||
SizedBoxShrinkExpand() | ||
: super( | ||
name: 'sized_box_shrink_expand', | ||
description: '', | ||
pq marked this conversation as resolved.
Show resolved
Hide resolved
|
||
details: _details, | ||
group: Group.style) { | ||
lintCode = LintCode(name, 'Unused'); | ||
} | ||
|
||
@override | ||
void registerNodeProcessors( | ||
NodeLintRegistry registry, LinterContext context) { | ||
var visitor = _Visitor(this); | ||
|
||
registry.addInstanceCreationExpression(this, visitor); | ||
} | ||
|
||
@override | ||
late LintCode lintCode; | ||
} | ||
|
||
class _Visitor extends SimpleAstVisitor { | ||
final SizedBoxShrinkExpand rule; | ||
|
||
_Visitor(this.rule); | ||
|
||
@override | ||
void visitInstanceCreationExpression(InstanceCreationExpression node) { | ||
// Only interested in the default constructor for the SizedBox widget | ||
if (!isExactWidgetTypeSizedBox(node.staticType) || | ||
node.constructorName.name != null) { | ||
return; | ||
} | ||
|
||
var data = _ArgumentData(node.argumentList); | ||
if (data.width == 0 && data.height == 0) { | ||
rule.lintCode = LintCode(rule.name, _sizedBoxShrinkDescription); | ||
rule.reportLint(node.constructorName); | ||
pq marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} else if (data.width == double.infinity && | ||
data.height == double.infinity) { | ||
rule.lintCode = LintCode(rule.name, _sizedBoxExpandDescription); | ||
rule.reportLint(node.constructorName); | ||
} | ||
} | ||
} | ||
|
||
class _ArgumentData { | ||
_ArgumentData(ArgumentList node) { | ||
for (var argument in node.arguments.cast<NamedExpression>()) { | ||
pq marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (argument.name.label.name == 'width') { | ||
var argumentVisitor = _ArgumentVisitor(); | ||
argument.expression.visitChildren(argumentVisitor); | ||
width = argumentVisitor.argument; | ||
} else if (argument.name.label.name == 'height') { | ||
var argumentVisitor = _ArgumentVisitor(); | ||
argument.expression.visitChildren(argumentVisitor); | ||
height = argumentVisitor.argument; | ||
} | ||
} | ||
} | ||
|
||
double? width; | ||
double? height; | ||
} | ||
|
||
class _ArgumentVisitor extends SimpleAstVisitor { | ||
pq marked this conversation as resolved.
Show resolved
Hide resolved
|
||
double? argument; | ||
|
||
@override | ||
visitIntegerLiteral(IntegerLiteral node) { | ||
argument = node.value!.toDouble(); | ||
} | ||
|
||
@override | ||
visitDoubleLiteral(DoubleLiteral node) { | ||
argument = node.value; | ||
} | ||
|
||
@override | ||
visitSimpleIdentifier(SimpleIdentifier node) { | ||
if (node.name.toLowerCase() == 'infinity') { | ||
argument = double.infinity; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
// test w/ `dart test -N sized_box_shrink_expand` | ||
|
||
import 'package:flutter/foundation.dart'; | ||
import 'package:flutter/widgets.dart'; | ||
|
||
Widget sizedBoxWithZeroWidthZeroHeight() { | ||
return SizedBox( | ||
// LINT | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe that the 'LINT' marker needs to be on the same line as that on which the lint will be reported. The lint is currently (correctly IMO) reported on the name of the class on line 11, so I think this marker needs to be moved onto line 11. Similarly below. This probably isn't what's causing the current test failure, but I suspect it will cause a different form of test failure after the current failure is fixed. The 'OK' markers won't cause that problem, but should probably be moved up to the preceding line for consistency. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The issue is that the dart format tooling is automatically moving the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Even with this change, I'm still seeing a failure. $ dart test -N sized_box_shrink_expand
00:05 +0: test/rule_test.dart: rule dart sized_box_shrink_expand
/Users/brettmorgan/Documents/GitHub/linter/test_data/rules/sized_box_shrink_expand.dart 11:10 [lint] Use the `SizedBox.shrink` constructor.
return SizedBox( // LINT
^^^^^^^^
null files analyzed, 1 issue found, in null ms.
00:05 +0 -1: test/rule_test.dart: rule dart sized_box_shrink_expand [E]
Expected: matches [Annotation:<[LINT]: "null" (line: 11) - [null:null]>, Annotation:<[LINT]: "null" (line: 19) - [null:null]>] unordered
Actual: [
Annotation:[LINT]: "Use the `SizedBox.shrink` constructor." (line: 11) - [10:8]
]
Which: has too few elements (1 < 2)
package:test_api expect
test/rule_test.dart 254:7 testRule.<fn>
00:05 +0 -1: loading test/rule_test.dart
Consider enabling the flag chain-stack-traces to receive more detailed exceptions.
For example, 'dart test --chain-stack-traces'.
00:05 +0 -1: Some tests failed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I consider the formatter's behavior to be a bug, so I opened dart-lang/dart_style#1070. But I'm not surprised that it's still failing. I mentioned the placement of the comments because I suspect that the test code first verifies that the correct number of lints were produced, and then verifies that each of the lints was in the expected location. With the markers in the wrong places, fixing the number of lints would cause the second failure to occur. It appears that the missing lint is the one on line 19 (the |
||
height: 0, | ||
width: 0, | ||
child: Container(), | ||
); | ||
bwilkerson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
Widget sizedBoxWithInfiniteWidthInfiniteHeight() { | ||
return SizedBox( | ||
// LINT | ||
height: double.INFINITY, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With @scheglov's updates to the mock SDK, I think you'll want to bump these to:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Any idea when this will land? Or should I commit this file with a TODO? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be already available in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
width: double.INFINITY, | ||
child: Container(), | ||
); | ||
} | ||
|
||
Widget sizedBoxWithInfiniteWidthzeroHeight() { | ||
return SizedBox( | ||
// OK | ||
height: 0, | ||
width: double.INFINITY, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
child: Container(), | ||
); | ||
} | ||
|
||
Widget sizedBoxWithZeroWidthInfiniteHeight() { | ||
return SizedBox( | ||
// OK | ||
height: double.INFINITY, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
width: 0, | ||
child: Container(), | ||
); | ||
} | ||
|
||
Widget sizedBoxWithMixedWidthsAndHeights() { | ||
return SizedBox( | ||
// OK | ||
height: 26, | ||
width: 42, | ||
child: Container(), | ||
); | ||
} | ||
|
||
Widget sizedBoxWithZeroWidth() { | ||
return SizedBox( | ||
// OK | ||
width: 0, | ||
child: Container(), | ||
); | ||
} | ||
|
||
Widget sizedBoxWithInfiniteWidth() { | ||
return SizedBox( | ||
// OK | ||
width: double.INFINITY, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
child: Container(), | ||
); | ||
} | ||
|
||
Widget sizedBoxWithZeroHeight() { | ||
return SizedBox( | ||
// OK | ||
height: 0, | ||
child: Container(), | ||
); | ||
} | ||
|
||
Widget sizedBoxWithInfiniteHeight() { | ||
return SizedBox( | ||
// OK | ||
height: double.INFINITY, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
child: Container(), | ||
); | ||
} |
Uh oh!
There was an error while loading. Please reload this page.