diff --git a/lib/src/rules/use_colored_box.dart b/lib/src/rules/use_colored_box.dart index aa0b460e4..fca61485b 100644 --- a/lib/src/rules/use_colored_box.dart +++ b/lib/src/rules/use_colored_box.dart @@ -6,6 +6,7 @@ import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/ast/visitor.dart'; import '../analyzer.dart'; +import '../util/dart_type_utilities.dart'; import '../util/flutter_utils.dart'; const _desc = r'Use `ColoredBox`.'; @@ -49,16 +50,17 @@ class UseColoredBox extends LintRule { @override void registerNodeProcessors( NodeLintRegistry registry, LinterContext context) { - var visitor = _Visitor(this); + var visitor = _Visitor(this, context); registry.addInstanceCreationExpression(this, visitor); } } class _Visitor extends SimpleAstVisitor { - final LintRule rule; + _Visitor(this.rule, this.context); - _Visitor(this.rule); + final LintRule rule; + final LinterContext context; @override void visitInstanceCreationExpression(InstanceCreationExpression node) { @@ -66,13 +68,13 @@ class _Visitor extends SimpleAstVisitor { return; } - var data = _ArgumentData(node.argumentList); + var data = _ArgumentData(node.argumentList, context); if (data.additionalArgumentsFound || data.positionalArgumentsFound) { return; } - if (data.hasColor) { + if (data.hasNonNullColor) { rule.reportLint(node.constructorName); } } @@ -81,20 +83,25 @@ class _Visitor extends SimpleAstVisitor { class _ArgumentData { var positionalArgumentsFound = false; var additionalArgumentsFound = false; - var hasColor = false; + var hasNonNullColor = false; - _ArgumentData(ArgumentList node) { + _ArgumentData(ArgumentList node, LinterContext context) { for (var argument in node.arguments) { if (argument is! NamedExpression) { positionalArgumentsFound = true; return; } - var label = argument.name.label; - if (label.name == 'color') { - hasColor = true; - } else if (label.name == 'child') { + var name = argument.name.label.name; + if (name == 'color') { + // Not lint if color is null or nullable because a ColoredBox only + // accepts a non-null Color + if (DartTypeUtilities.isNonNullable( + context, argument.expression.staticType)) { + hasNonNullColor = true; + } + } else if (name == 'child') { // Ignore child - } else if (label.name == 'key') { + } else if (name == 'key') { // Ignore key } else { additionalArgumentsFound = true; diff --git a/lib/src/rules/use_decorated_box.dart b/lib/src/rules/use_decorated_box.dart index f4c12914b..2ff3924bb 100644 --- a/lib/src/rules/use_decorated_box.dart +++ b/lib/src/rules/use_decorated_box.dart @@ -6,6 +6,7 @@ import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/ast/visitor.dart'; import '../analyzer.dart'; +import '../util/dart_type_utilities.dart'; import '../util/flutter_utils.dart'; const _desc = r'Use `DecoratedBox`.'; @@ -59,16 +60,17 @@ class UseDecoratedBox extends LintRule { @override void registerNodeProcessors( NodeLintRegistry registry, LinterContext context) { - var visitor = _Visitor(this); + var visitor = _Visitor(this, context); registry.addInstanceCreationExpression(this, visitor); } } class _Visitor extends SimpleAstVisitor { - final LintRule rule; + _Visitor(this.rule, this.context); - _Visitor(this.rule); + final LintRule rule; + final LinterContext context; @override void visitInstanceCreationExpression(InstanceCreationExpression node) { @@ -76,13 +78,13 @@ class _Visitor extends SimpleAstVisitor { return; } - var data = _ArgumentData(node.argumentList); + var data = _ArgumentData(node.argumentList, context); if (data.additionalArgumentsFound || data.positionalArgumentsFound) { return; } - if (data.hasDecoration) { + if (data.hasNonNullDecoration) { rule.reportLint(node.constructorName); } } @@ -91,20 +93,25 @@ class _Visitor extends SimpleAstVisitor { class _ArgumentData { var positionalArgumentsFound = false; var additionalArgumentsFound = false; - var hasDecoration = false; + var hasNonNullDecoration = false; - _ArgumentData(ArgumentList node) { + _ArgumentData(ArgumentList node, LinterContext context) { for (var argument in node.arguments) { if (argument is! NamedExpression) { positionalArgumentsFound = true; return; } - var label = argument.name.label; - if (label.name == 'decoration') { - hasDecoration = true; - } else if (label.name == 'child') { + var name = argument.name.label.name; + if (name == 'decoration') { + // Not lint if decoration is null or nullable because a DecoratedBox + // only accepts a non-null Decoration + if (DartTypeUtilities.isNonNullable( + context, argument.expression.staticType)) { + hasNonNullDecoration = true; + } + } else if (name == 'child') { // Ignore child - } else if (label.name == 'key') { + } else if (name == 'key') { // Ignore key } else { additionalArgumentsFound = true; diff --git a/test_data/mock_packages/flutter/lib/painting.dart b/test_data/mock_packages/flutter/lib/painting.dart index 58158555b..5835ed6e1 100644 --- a/test_data/mock_packages/flutter/lib/painting.dart +++ b/test_data/mock_packages/flutter/lib/painting.dart @@ -2,4 +2,4 @@ // 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. -export 'src/painting/box_decoration.dart'; +export 'src/painting/decoration.dart'; diff --git a/test_data/mock_packages/flutter/lib/src/painting/box_decoration.dart b/test_data/mock_packages/flutter/lib/src/painting/decoration.dart similarity index 90% rename from test_data/mock_packages/flutter/lib/src/painting/box_decoration.dart rename to test_data/mock_packages/flutter/lib/src/painting/decoration.dart index 881503b90..8ab2445fb 100644 --- a/test_data/mock_packages/flutter/lib/src/painting/box_decoration.dart +++ b/test_data/mock_packages/flutter/lib/src/painting/decoration.dart @@ -2,4 +2,4 @@ // 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. -class BoxDecoration {} +class Decoration {} diff --git a/test_data/rules/use_colored_box.dart b/test_data/rules/use_colored_box.dart index 3c90df244..e2235e34d 100644 --- a/test_data/rules/use_colored_box.dart +++ b/test_data/rules/use_colored_box.dart @@ -7,9 +7,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; -class Color { - Color(int value); -} +class Color {} Widget containerWithoutArguments() { return Container(); // OK @@ -23,7 +21,7 @@ Widget containerWithKey() { Widget containerWithColor() { return Container( // LINT - color: Color(0xffffffff), + color: Color(), ); } @@ -43,13 +41,13 @@ Widget containerWithKeyAndChild() { Widget containerWithKeyAndColor() { return Container( // LINT key: Key('abc'), - color: Color(0xffffffff), + color: Color(), ); } Widget containerWithColorAndChild() { return Container( // LINT - color: Color(0xffffffff), + color: Color(), child: SizedBox(), ); } @@ -57,7 +55,7 @@ Widget containerWithColorAndChild() { Widget containerWithKeyAndColorAndChild() { return Container( // LINT key: Key('abc'), - color: Color(0xffffffff), + color: Color(), child: SizedBox(), ); } @@ -70,15 +68,49 @@ Widget containerWithAnotherArgument() { Widget containerWithColorAndAdditionalArgument() { return Container( // OK - color: Color(0xffffffff), + color: Color(), width: 20, ); } Widget containerWithColorAndAdditionalArgumentAndChild() { return Container( // OK - color: Color(0xffffffff), + color: Color(), width: 20, child: SizedBox(), ); } + +Widget containerWithNullColor() { + return Container( // OK + color: null, + child: SizedBox(), + ); +} + +const Color? _nullableColor = null; + +Widget containerWithNullableColor() { + return Container( // OK + color: _nullableColor, + child: SizedBox(), + ); +} + +final _nonNullColor = Color(); + +Widget containerWithNonNullColor() { + return Container( // LINT + color: _nonNullColor, + child: SizedBox(), + ); +} + +Color? _getColor() => null; + +Widget nullableReturnValue() { + return Container( // OK + color: _getColor(), + child: SizedBox(), + ); +} diff --git a/test_data/rules/use_decorated_box.dart b/test_data/rules/use_decorated_box.dart index fbf4e511d..8a3cc783a 100644 --- a/test_data/rules/use_decorated_box.dart +++ b/test_data/rules/use_decorated_box.dart @@ -20,7 +20,7 @@ Widget containerWithKey() { Widget containerWithDecoration() { return Container( // LINT - decoration: BoxDecoration(), + decoration: Decoration(), ); } @@ -40,13 +40,13 @@ Widget containerWithKeyAndChild() { Widget containerWithKeyAndDecoration() { return Container( // LINT key: Key('abc'), - decoration: BoxDecoration(), + decoration: Decoration(), ); } Widget containerWithDecorationAndChild() { return Container( // LINT - decoration: BoxDecoration(), + decoration: Decoration(), child: SizedBox(), ); } @@ -54,7 +54,7 @@ Widget containerWithDecorationAndChild() { Widget containerWithKeyAndDecorationAndChild() { return Container( // LINT key: Key('abc'), - decoration: BoxDecoration(), + decoration: Decoration(), child: SizedBox(), ); } @@ -67,15 +67,49 @@ Widget containerWithAnotherArgument() { Widget containerWithDecorationAndAdditionalArgument() { return Container( // OK - decoration: BoxDecoration(), + decoration: Decoration(), width: 20, ); } Widget containerWithDecorationAndAdditionalArgumentAndChild() { return Container( // OK - decoration: BoxDecoration(), + decoration: Decoration(), width: 20, child: SizedBox(), ); } + +Widget containerWithNullDecoration() { + return Container( // OK + decoration: null, + child: SizedBox(), + ); +} + +const Decoration? _nullableDecoration = null; + +Widget containerWithNullableDecoration() { + return Container( // OK + decoration: _nullableDecoration, + child: SizedBox(), + ); +} + +final _nonNullDecoration = Decoration(); + +Widget containerWithNonNullDecoration() { + return Container( // LINT + decoration: _nonNullDecoration, + child: SizedBox(), + ); +} + +Decoration? _getDecoration() => null; + +Widget nullableReturnValue() { + return Container( // OK + decoration: _getDecoration(), + child: SizedBox(), + ); +}