check method
void
check(
- DcqRegistry registry
)
Implementation
@override
void check(DcqRegistry registry) {
// Collect private function/method declarations and their call sites.
// Key: element id, Value: (declaration params, call arg info).
final paramDecls = <int, List<FormalParameter>>{};
final callArgs = <int, List<_CallInfo>>{};
registry.addFunctionDeclaration((node) {
final element = node.declaredFragment?.element;
if (element == null) return;
if (!element.isPrivate) return;
final id = element.id;
paramDecls[id] = node.functionExpression.parameters?.parameters ?? [];
});
registry.addMethodDeclaration((node) {
final element = node.declaredFragment?.element;
if (element == null) return;
if (!element.isPrivate) return;
final id = element.id;
paramDecls[id] = node.parameters?.parameters ?? [];
});
registry.addMethodInvocation((node) {
final element = node.methodName.element;
if (element is! ExecutableElement) return;
if (!element.isPrivate) return;
callArgs
.putIfAbsent(element.id, () => [])
.add(
_CallInfo(node.argumentList),
);
});
registry.addFunctionExpressionInvocation((node) {
final fn = node.function;
if (fn is! SimpleIdentifier) return;
final element = fn.element;
if (element is! ExecutableElement) return;
if (!element.isPrivate) return;
callArgs
.putIfAbsent(element.id, () => [])
.add(
_CallInfo(node.argumentList),
);
});
registry.afterLibrary(() {
for (final entry in paramDecls.entries) {
final id = entry.key;
final params = entry.value;
final calls = callArgs[id];
if (calls == null || calls.isEmpty) continue;
for (var i = 0; i < params.length; i++) {
final param = params[i];
final paramName = param.name?.lexeme;
if (paramName == null) continue;
final alwaysNull = calls.every((call) {
final arg = call.argumentFor(i, paramName);
if (arg == null) {
// Omitted optional parameter — effectively null if no default
// or default is null.
return _hasNullDefault(param);
}
return arg is NullLiteral;
});
if (alwaysNull) {
reportAtNode(param);
}
}
}
});
}