Run clang-query to find functions missing noexcept. Returns list of (filepath, line_number, line_text) tuples.
(clang_query: str)
| 78 | |
| 79 | |
| 80 | def _find_missing_noexcept(clang_query: str) -> list[tuple[str, int, str]]: |
| 81 | """Run clang-query to find functions missing noexcept. |
| 82 | |
| 83 | Returns list of (filepath, line_number, line_text) tuples. |
| 84 | """ |
| 85 | tu_path = PROJECT_ROOT / _TU |
| 86 | if not tu_path.exists(): |
| 87 | print(f"ERROR: Translation unit not found: {_TU}") |
| 88 | sys.exit(1) |
| 89 | |
| 90 | query = ( |
| 91 | f"set output diag\n" |
| 92 | f"match functionDecl(" |
| 93 | f"unless(isNoThrow()), " |
| 94 | f"unless(isDeleted()), " |
| 95 | f"unless(isDefaulted()), " |
| 96 | f"unless(isImplicit()), " |
| 97 | f'isExpansionInFileMatching("{_FILE_REGEX}"))' |
| 98 | ) |
| 99 | |
| 100 | result = subprocess.run( |
| 101 | [clang_query, _TU, "--"] + _COMPILER_ARGS, |
| 102 | input=query, |
| 103 | capture_output=True, |
| 104 | text=True, |
| 105 | cwd=str(PROJECT_ROOT), |
| 106 | timeout=300, |
| 107 | ) |
| 108 | |
| 109 | output = result.stdout + result.stderr |
| 110 | |
| 111 | # Parse "file:line:col: note: "root" binds here" |
| 112 | pattern = re.compile(r"(src[\\/]\S+):(\d+):\d+: note: .root. binds here") |
| 113 | hits: list[tuple[str, int, str]] = [] |
| 114 | seen: set[tuple[str, int]] = set() |
| 115 | |
| 116 | for m in pattern.finditer(output): |
| 117 | filepath = m.group(1).replace("\\", "/") |
| 118 | line_num = int(m.group(2)) |
| 119 | key = (filepath, line_num) |
| 120 | if key not in seen: |
| 121 | seen.add(key) |
| 122 | # Read the actual source line for display |
| 123 | full_path = PROJECT_ROOT / filepath |
| 124 | line_text = "" |
| 125 | if full_path.exists(): |
| 126 | try: |
| 127 | lines = full_path.read_text( |
| 128 | encoding="utf-8", errors="replace" |
| 129 | ).splitlines() |
| 130 | if 0 < line_num <= len(lines): |
| 131 | line_text = lines[line_num - 1].strip() |
| 132 | except KeyboardInterrupt as ki: |
| 133 | from ci.util.global_interrupt_handler import ( |
| 134 | handle_keyboard_interrupt, |
| 135 | ) |
| 136 | |
| 137 | handle_keyboard_interrupt(ki) |