detectStaleIgnores function

List<StaleIgnore> detectStaleIgnores({
  1. required List<ScanDiagnostic> diagnostics,
  2. required List<String> files,
})

Detects stale // ignore: comments across the given files by comparing them against diagnostics from a scan run.

A stale ignore is one where the scan did not produce a diagnostic for the referenced rule on the target line — meaning the diagnostic no longer fires and the ignore comment is dead weight.

Implementation

List<StaleIgnore> detectStaleIgnores({
  required List<ScanDiagnostic> diagnostics,
  required List<String> files,
}) {
  // Build a lookup: (filePath, line) -> set of rule names that fired.
  // This makes per-ignore checking O(1) instead of scanning the full
  // diagnostics list for each ignore comment.
  // Paths are normalized so backslash/forward-slash and drive-letter
  // casing differences on Windows do not cause silent key mismatches.
  final firedRules = <String, Set<String>>{};
  for (final d in diagnostics) {
    // Key by "normalizedPath:line" for fast lookup.
    final key = '${_normalizePath(d.filePath)}:${d.line}';
    firedRules.putIfAbsent(key, () => <String>{}).add(d.ruleName);
  }

  final stale = <StaleIgnore>[];

  for (final filePath in files) {
    final file = File(filePath);
    if (!file.existsSync()) continue;

    final content = file.readAsStringSync();
    final entries = _parseIgnoreComments(content, filePath);

    for (final entry in entries) {
      // Normalize to match the diagnostic-side keys built above.
      final key = '${_normalizePath(entry.filePath)}:${entry.targetLine}';
      final rulesOnLine = firedRules[key];

      // If no diagnostic with this rule name fired on the target line,
      // the ignore is stale.
      if (rulesOnLine == null || !rulesOnLine.contains(entry.ruleName)) {
        stale.add(
          StaleIgnore(
            filePath: entry.filePath,
            commentLine: entry.commentLine,
            targetLine: entry.targetLine,
            ruleName: entry.ruleName,
            commentText: entry.commentText,
          ),
        );
      }
    }
  }

  return stale;
}