[linter] Avoid one-off classes in flutter-related box rules

Change-Id: Ie0d8d2f66eb2c5ab5a4664eeaa588c623a395a65
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/371786
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Sam Rawlins <srawlins@google.com>
Auto-Submit: Parker Lougheed <parlough@gmail.com>
diff --git a/pkg/linter/lib/src/rules/sized_box_for_whitespace.dart b/pkg/linter/lib/src/rules/sized_box_for_whitespace.dart
index 23bcbf2..9c3265d 100644
--- a/pkg/linter/lib/src/rules/sized_box_for_whitespace.dart
+++ b/pkg/linter/lib/src/rules/sized_box_for_whitespace.dart
@@ -72,35 +72,6 @@
   }
 }
 
-class _ArgumentData {
-  var incompatibleParamsFound = false;
-
-  var positionalArgumentFound = false;
-  var seenWidth = false;
-  var seenHeight = false;
-  var seenChild = false;
-  _ArgumentData(ArgumentList node) {
-    for (var argument in node.arguments) {
-      if (argument is! NamedExpression) {
-        positionalArgumentFound = true;
-        return;
-      }
-      var label = argument.name.label;
-      if (label.name == 'width') {
-        seenWidth = true;
-      } else if (label.name == 'height') {
-        seenHeight = true;
-      } else if (label.name == 'child') {
-        seenChild = true;
-      } else if (label.name == 'key') {
-        // key doesn't matter (both SizedBox and Container have it)
-      } else {
-        incompatibleParamsFound = true;
-      }
-    }
-  }
-}
-
 class _Visitor extends SimpleAstVisitor {
   final LintRule rule;
 
@@ -112,14 +83,39 @@
       return;
     }
 
-    var data = _ArgumentData(node.argumentList);
-
-    if (data.incompatibleParamsFound || data.positionalArgumentFound) {
-      return;
-    }
-    if (data.seenChild && (data.seenWidth || data.seenHeight) ||
-        data.seenWidth && data.seenHeight) {
+    if (_shouldReportForArguments(node.argumentList)) {
       rule.reportLint(node.constructorName);
     }
   }
+
+  /// Determine if the lint [rule] should be reported for
+  /// the specified [argumentList].
+  static bool _shouldReportForArguments(ArgumentList argumentList) {
+    var hasChild = false;
+    var hasHeight = false;
+    var hasWidth = false;
+
+    for (var argument in argumentList.arguments) {
+      if (argument is! NamedExpression) {
+        // Positional arguments are not supported.
+        return false;
+      }
+      switch (argument.name.label.name) {
+        case 'child':
+          hasChild = true;
+        case 'height':
+          hasHeight = true;
+        case 'width':
+          hasWidth = true;
+        case 'key':
+          // Ignore 'key' as both SizedBox and Container have it.
+          break;
+        case _:
+          // Other named arguments are not supported.
+          return false;
+      }
+    }
+
+    return hasChild && (hasWidth || hasHeight) || hasWidth && hasHeight;
+  }
 }
diff --git a/pkg/linter/lib/src/rules/sized_box_shrink_expand.dart b/pkg/linter/lib/src/rules/sized_box_shrink_expand.dart
index b0b22ac..6588d07 100644
--- a/pkg/linter/lib/src/rules/sized_box_shrink_expand.dart
+++ b/pkg/linter/lib/src/rules/sized_box_shrink_expand.dart
@@ -85,29 +85,6 @@
   }
 }
 
-class _ArgumentData {
-  var positionalArgumentFound = false;
-
-  double? width;
-
-  double? height;
-
-  _ArgumentData(ArgumentList node) {
-    for (var argument in node.arguments) {
-      if (argument is! NamedExpression) {
-        positionalArgumentFound = true;
-        return;
-      }
-      var label = argument.name.label;
-      if (label.name == 'width') {
-        width = argument.expression.argumentValue;
-      } else if (label.name == 'height') {
-        height = argument.expression.argumentValue;
-      }
-    }
-  }
-}
-
 class _Visitor extends SimpleAstVisitor {
   final SizedBoxShrinkExpand rule;
 
@@ -121,10 +98,11 @@
       return;
     }
 
-    var data = _ArgumentData(node.argumentList);
-    if (data.positionalArgumentFound) {
+    var data = _analyzeArguments(node.argumentList);
+    if (data == null) {
       return;
     }
+
     if (data.width == 0 && data.height == 0) {
       rule.reportLint(node.constructorName, arguments: ['shrink']);
     } else if (data.width == double.infinity &&
@@ -132,6 +110,30 @@
       rule.reportLint(node.constructorName, arguments: ['expand']);
     }
   }
+
+  /// Determine the value of the arguments specified in the [argumentList],
+  /// and return `null` if there are unsupported arguments.
+  static ({double? height, double? width})? _analyzeArguments(
+      ArgumentList argumentList) {
+    double? height;
+    double? width;
+
+    for (var argument in argumentList.arguments) {
+      if (argument is! NamedExpression) {
+        // Positional arguments are not supported.
+        return null;
+      }
+
+      switch (argument.name.label.name) {
+        case 'width':
+          width = argument.expression.argumentValue;
+        case 'height':
+          height = argument.expression.argumentValue;
+      }
+    }
+
+    return (height: height, width: width);
+  }
 }
 
 extension on Expression {
diff --git a/pkg/linter/lib/src/rules/use_colored_box.dart b/pkg/linter/lib/src/rules/use_colored_box.dart
index 77849f4..9550deb 100644
--- a/pkg/linter/lib/src/rules/use_colored_box.dart
+++ b/pkg/linter/lib/src/rules/use_colored_box.dart
@@ -62,34 +62,6 @@
   }
 }
 
-class _ArgumentData {
-  var positionalArgumentsFound = false;
-  var additionalArgumentsFound = false;
-  var hasColor = false;
-  var hasChild = false;
-
-  _ArgumentData(ArgumentList node) {
-    for (var argument in node.arguments) {
-      if (argument is! NamedExpression) {
-        positionalArgumentsFound = true;
-        return;
-      }
-      var label = argument.name.label;
-      if (label.name == 'color' &&
-          argument.staticType?.nullabilitySuffix !=
-              NullabilitySuffix.question) {
-        hasColor = true;
-      } else if (label.name == 'child') {
-        hasChild = true;
-      } else if (label.name == 'key') {
-        // Ignore key
-      } else {
-        additionalArgumentsFound = true;
-      }
-    }
-  }
-}
-
 class _Visitor extends SimpleAstVisitor {
   final LintRule rule;
 
@@ -101,14 +73,38 @@
       return;
     }
 
-    var data = _ArgumentData(node.argumentList);
-
-    if (data.additionalArgumentsFound || data.positionalArgumentsFound) {
-      return;
-    }
-
-    if (data.hasChild && data.hasColor) {
+    if (_shouldReportForArguments(node.argumentList)) {
       rule.reportLint(node.constructorName);
     }
   }
+
+  /// Determine if the lint [rule] should be reported for
+  /// the specified [argumentList].
+  static bool _shouldReportForArguments(ArgumentList argumentList) {
+    var hasChild = false;
+    var hasColor = false;
+
+    for (var argument in argumentList.arguments) {
+      if (argument is! NamedExpression) {
+        // Positional arguments are not supported.
+        return false;
+      }
+      switch (argument.name.label.name) {
+        case 'child':
+          hasChild = true;
+        case 'color'
+            when argument.staticType?.nullabilitySuffix !=
+                NullabilitySuffix.question:
+          hasColor = true;
+        case 'key':
+          // Ignore 'key' as both ColoredBox and Container have it.
+          break;
+        case _:
+          // Other named arguments are not supported.
+          return false;
+      }
+    }
+
+    return hasChild && hasColor;
+  }
 }
diff --git a/pkg/linter/lib/src/rules/use_decorated_box.dart b/pkg/linter/lib/src/rules/use_decorated_box.dart
index dce1bd9..5676524 100644
--- a/pkg/linter/lib/src/rules/use_decorated_box.dart
+++ b/pkg/linter/lib/src/rules/use_decorated_box.dart
@@ -72,32 +72,6 @@
   }
 }
 
-class _ArgumentData {
-  var positionalArgumentsFound = false;
-  var additionalArgumentsFound = false;
-  var hasDecoration = false;
-  var hasChild = false;
-
-  _ArgumentData(ArgumentList node) {
-    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') {
-        hasChild = true;
-      } else if (label.name == 'key') {
-        // Ignore key
-      } else {
-        additionalArgumentsFound = true;
-      }
-    }
-  }
-}
-
 class _Visitor extends SimpleAstVisitor {
   final LintRule rule;
 
@@ -109,14 +83,36 @@
       return;
     }
 
-    var data = _ArgumentData(node.argumentList);
-
-    if (data.additionalArgumentsFound || data.positionalArgumentsFound) {
-      return;
-    }
-
-    if (data.hasChild && data.hasDecoration) {
+    if (_shouldReportForArguments(node.argumentList)) {
       rule.reportLint(node.constructorName);
     }
   }
+
+  /// Determine if the lint [rule] should be reported for
+  /// the specified [argumentList].
+  static bool _shouldReportForArguments(ArgumentList argumentList) {
+    var hasChild = false;
+    var hasDecoration = false;
+
+    for (var argument in argumentList.arguments) {
+      if (argument is! NamedExpression) {
+        // Positional arguments are not supported.
+        return false;
+      }
+      switch (argument.name.label.name) {
+        case 'child':
+          hasChild = true;
+        case 'decoration':
+          hasDecoration = true;
+        case 'key':
+          // Ignore 'key' as both DecoratedBox and Container have it.
+          break;
+        case _:
+          // Other named arguments are not supported.
+          return false;
+      }
+    }
+
+    return hasChild && hasDecoration;
+  }
 }