Checker that bans *.cpp.hpp includes in src/ (except _build/build files) and tests/. No opt-out.
| 23 | |
| 24 | |
| 25 | class CppHppIncludesChecker(FileContentChecker): |
| 26 | """Checker that bans *.cpp.hpp includes in src/ (except _build/build files) and tests/. No opt-out.""" |
| 27 | |
| 28 | def __init__(self) -> None: |
| 29 | self.violations: dict[str, list[tuple[int, str]]] = {} |
| 30 | |
| 31 | def should_process_file(self, file_path: str) -> bool: |
| 32 | """Check if file should be processed.""" |
| 33 | normalized = file_path.replace("\\", "/") |
| 34 | |
| 35 | is_src = normalized.startswith(str(SRC_ROOT).replace("\\", "/") + "/") |
| 36 | is_tests = normalized.startswith(str(TESTS_ROOT).replace("\\", "/") + "/") |
| 37 | |
| 38 | if not is_src and not is_tests: |
| 39 | return False |
| 40 | |
| 41 | # Check C++ file extensions |
| 42 | if is_src and not normalized.endswith((".cpp", ".h", ".hpp", ".cpp.hpp")): |
| 43 | return False |
| 44 | if is_tests and not normalized.endswith((".cpp", ".h", ".hpp")): |
| 45 | return False |
| 46 | |
| 47 | # src/ exclusions: build files are ALLOWED to include .cpp.hpp |
| 48 | if is_src: |
| 49 | if ( |
| 50 | file_path.endswith("_build.hpp") |
| 51 | or file_path.endswith("_build.cpp") |
| 52 | or file_path.endswith("_build.cpp.hpp") |
| 53 | ): |
| 54 | return False |
| 55 | |
| 56 | build_dir = str(SRC_ROOT / "fl" / "build").replace("\\", "/") |
| 57 | if normalized.startswith(build_dir + "/"): |
| 58 | return False |
| 59 | |
| 60 | return True |
| 61 | |
| 62 | def check_file_content(self, file_content: FileContent) -> list[str]: |
| 63 | """Check file content for includes of other *.cpp.hpp files.""" |
| 64 | violations: list[tuple[int, str]] = [] |
| 65 | in_multiline_comment = False |
| 66 | is_test = file_content.path.replace("\\", "/").startswith( |
| 67 | str(TESTS_ROOT).replace("\\", "/") + "/" |
| 68 | ) |
| 69 | |
| 70 | for line_number, line in enumerate(file_content.lines, 1): |
| 71 | stripped = line.strip() |
| 72 | |
| 73 | # Track multi-line comment state |
| 74 | if "/*" in line: |
| 75 | in_multiline_comment = True |
| 76 | if "*/" in line: |
| 77 | in_multiline_comment = False |
| 78 | continue # Skip the line with closing */ |
| 79 | |
| 80 | if in_multiline_comment: |
| 81 | continue |
| 82 |
no outgoing calls
no test coverage detected