blob: caf5ad7e5303eceeb083b8d15f282a2200c13112 [file]
#!/usr/bin/env vpython3
# Copyright 2026 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Lint `chrome://flags` source code.
These checks aren't run as `AboutFlagsTest.*` because they require access to the
original source code.
"""
import json
import pathlib
import re
import sys
import flags_utils
_ROOT_PATH = pathlib.Path(__file__).parents[2]
def find_unused_flags_in_metadata(
root_path: pathlib.Path = _ROOT_PATH) -> set[str]:
metadata = flags_utils.load_metadata(root_path=root_path)
unused_flags = {entry['name'] for entry in metadata}
# Skip a few permanent debugging flags whose internal names are provided by
# constants in `**/*switches.{h,cc}` (mostly unrelated to flags).
unused_flags -= {'enable-benchmarking', 'enable-ui-devtools'}
internal_name_pattern = re.compile(r'"(?P<maybe_name>\w+(-\w+)*)"')
for about_flags_path in [
root_path / 'chrome' / 'browser' / 'about_flags.cc',
root_path / 'ios' / 'chrome' / 'browser' / 'flags' / 'about_flags.mm',
# Check other files that are known to define internal flag name constants.
# Since most names are inlined in `about_flags.{cc,mm}`, this list is not
# expected to grow.
root_path / 'chrome' / 'browser' / 'site_isolation' / 'about_flags.h',
]:
with about_flags_path.open() as about_flags_file:
# `about_flags.cc` is huge, so only make a single pass.
for line in about_flags_file:
for match in internal_name_pattern.finditer(line):
unused_flags.discard(match['maybe_name'])
return unused_flags
def main() -> int:
if unused_flags := find_unused_flags_in_metadata():
report = {'unused_flags': sorted(unused_flags)}
json.dump(report, sys.stdout, separators=(',', ':'))
return 1
return 0
if __name__ == '__main__':
exit(main())