Files
klubhaus-doorbell/libraries/FastLED/ci/tests/check_namespace_includes.py
2026-02-12 00:45:31 -08:00

115 lines
3.1 KiB
Python

# pyright: reportUnknownMemberType=false, reportMissingParameterType=false
"""Test for checking namespace includes in C++ headers."""
#!/usr/bin/env python3
"""
Script to check for includes after namespace declarations in C++ files.
This is used in CI/CD to prevent bad code patterns.
"""
import os
import re
import sys
from pathlib import Path
from typing import Any, Dict, List
def find_includes_after_namespace(file_path: Path) -> List[int]:
"""
Check if a C++ file has #include directives after namespace declarations.
Args:
file_path (Path): Path to the C++ file to check
Returns:
List[int]: List of line numbers where includes appear after namespaces
"""
try:
with open(file_path, "r", encoding="utf-8") as f:
content = f.readlines()
violations: List[int] = []
namespace_started = False
# Basic patterns
namespace_pattern = re.compile(r"^\s*namespace\s+\w+\s*\{")
include_pattern = re.compile(r"^\s*#\s*include")
for i, line in enumerate(content, 1):
line = line.strip()
# Skip empty lines and comments
if not line or line.startswith("//") or line.startswith("/*"):
continue
# Check for namespace declaration
if namespace_pattern.match(line):
namespace_started = True
# Check for #include after namespace started
if namespace_started and include_pattern.match(line):
violations.append(i)
return violations
except (UnicodeDecodeError, IOError):
# Skip files that can't be read
return []
def scan_cpp_files(directory: str = ".") -> Dict[str, Any]:
"""
Scan all C++ files in a directory for includes after namespace declarations.
Args:
directory (str): Directory to scan for C++ files
Returns:
Dict[str, Any]: Dictionary mapping file paths to lists of violation line numbers
"""
cpp_extensions = [
".cpp",
".cc",
".cxx",
".c++",
".hpp",
".h",
".hh",
".hxx",
".h++",
]
violations: Dict[str, Any] = {}
for root, dirs, files in os.walk(directory):
for file in files:
file_path = os.path.join(root, file)
# Check if it's a C++ file
if any(file.endswith(ext) for ext in cpp_extensions):
line_numbers: List[int] = find_includes_after_namespace(Path(file_path))
if line_numbers:
violations[file_path] = line_numbers
return violations
def main() -> None:
violations: Dict[str, Any] = scan_cpp_files()
if violations:
print("Found #include directives after namespace declarations:")
for file_path, line_numbers in violations.items():
print(f"\n{file_path}:")
for line_num in line_numbers:
print(f" Line {line_num}")
failing: List[str] = list(violations.keys())
print(f"\nFailing files: {failing}")
sys.exit(1)
else:
print("No violations found.")
sys.exit(0)
if __name__ == "__main__":
main()