initial commit
This commit is contained in:
114
libraries/FastLED/ci/tests/check_namespace_includes.py
Normal file
114
libraries/FastLED/ci/tests/check_namespace_includes.py
Normal file
@@ -0,0 +1,114 @@
|
||||
# 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()
|
||||
Reference in New Issue
Block a user