run method
void
run(
- CustomLintResolver resolver,
- DiagnosticReporter reporter,
- CustomLintContext context
Emits lints for a given file.
run will only be invoked with files respecting filesToAnalyze
Implementation
@override
void run(
CustomLintResolver resolver,
DiagnosticReporter reporter,
CustomLintContext context,
) {
context.registry.addInstanceCreationExpression((node) {
final type = node.staticType;
if (type == null) {
return;
}
final typeName = type.element?.name;
// Check for interactive widgets
final interactiveTypes = [
'IconButton',
'InkWell',
'GestureDetector',
'TextButton',
'ElevatedButton',
'OutlinedButton',
];
if (!interactiveTypes.contains(typeName)) {
return;
}
// For IconButton, check if iconSize or constraints are specified
if (typeName == 'IconButton') {
for (final arg in node.argumentList.arguments) {
if (arg is NamedExpression) {
final paramName = arg.name.label.name;
// Check iconSize parameter
if (paramName == 'iconSize') {
final value = extractNumericValue(arg.expression);
if (value != null && value < minimumSize) {
reporter.atNode(node, code);
return;
}
}
}
}
// IconButton defaults to 48x48, so only warn if explicitly set smaller
// We'll skip reporting if no size is specified (uses default)
}
// For Material buttons, check if style overrides minimum size
if (typeName == 'TextButton' ||
typeName == 'ElevatedButton' ||
typeName == 'OutlinedButton') {
for (final arg in node.argumentList.arguments) {
if (arg is NamedExpression && arg.name.label.name == 'style') {
final dimensions = extractButtonStyleSize(arg.expression);
if (dimensions != null &&
(dimensions.width < minimumSize ||
dimensions.height < minimumSize)) {
reporter.atNode(node, code);
return;
}
}
}
}
// For InkWell/GestureDetector, check if they wrap a SizedBox or Container with size
// OR if they are wrapped by a SizedBox/Container with small size
if (typeName == 'InkWell' || typeName == 'GestureDetector') {
bool foundSmallSize = false;
// First check if the widget itself wraps a sized child
for (final arg in node.argumentList.arguments) {
if (arg is NamedExpression && arg.name.label.name == 'child') {
final child = arg.expression;
if (child is InstanceCreationExpression) {
final childType = child.staticType?.element?.name;
// Check if child is SizedBox or Container with explicit size
if (childType == 'SizedBox' || childType == 'Container') {
final dimensions = extractDimensions(child);
if (dimensions != null) {
if (dimensions.width < minimumSize ||
dimensions.height < minimumSize) {
foundSmallSize = true;
break;
}
}
}
}
}
}
// Also check if the widget is wrapped by a SizedBox/Container with small size
if (!foundSmallSize) {
AstNode? parent = node.parent;
while (parent != null) {
if (parent is NamedExpression &&
parent.name.label.name == 'child') {
final grandParent = parent.parent?.parent;
if (grandParent is InstanceCreationExpression) {
final parentType = grandParent.staticType?.element?.name;
if (parentType == 'SizedBox' || parentType == 'Container') {
final dimensions = extractDimensions(grandParent);
if (dimensions != null) {
if (dimensions.width < minimumSize ||
dimensions.height < minimumSize) {
foundSmallSize = true;
break;
}
}
}
}
}
parent = parent.parent;
}
}
if (foundSmallSize) {
reporter.atNode(node, code);
}
}
});
}