()
| 238 | |
| 239 | |
| 240 | def main() -> int: |
| 241 | parser = argparse.ArgumentParser( |
| 242 | description="Add FL_NOEXCEPT to functions using clang-query AST analysis" |
| 243 | ) |
| 244 | parser.add_argument( |
| 245 | "--scope", |
| 246 | required=True, |
| 247 | help="Path scope to match (e.g., fl/stl, platforms/esp/32)", |
| 248 | ) |
| 249 | parser.add_argument( |
| 250 | "--apply", action="store_true", help="Apply changes (default: dry-run)" |
| 251 | ) |
| 252 | args = parser.parse_args() |
| 253 | |
| 254 | print( |
| 255 | f"{'APPLYING' if args.apply else 'DRY RUN'}: " |
| 256 | f"Adding FL_NOEXCEPT to functions in {args.scope}" |
| 257 | ) |
| 258 | print() |
| 259 | |
| 260 | # Step 1: Get AST-accurate list |
| 261 | print("Running clang-query (AST analysis)...") |
| 262 | hits = run_clang_query(args.scope) |
| 263 | print(f"Found {len(hits)} functions missing noexcept") |
| 264 | print() |
| 265 | |
| 266 | if not hits: |
| 267 | print("Nothing to do!") |
| 268 | return 0 |
| 269 | |
| 270 | # Group by file |
| 271 | by_file: dict[str, list[int]] = {} |
| 272 | for filepath, line_num in hits: |
| 273 | by_file.setdefault(filepath, []).append(line_num) |
| 274 | |
| 275 | # Step 2: Process each file |
| 276 | total_changes = 0 |
| 277 | total_skipped = 0 |
| 278 | |
| 279 | for filepath in sorted(by_file): |
| 280 | full_path = PROJECT_ROOT / filepath |
| 281 | if not full_path.exists(): |
| 282 | continue |
| 283 | |
| 284 | content = full_path.read_text(encoding="utf-8", errors="replace") |
| 285 | lines = content.split("\n") |
| 286 | |
| 287 | file_changes = 0 |
| 288 | file_skipped = 0 |
| 289 | |
| 290 | for line_num in sorted(by_file[filepath]): |
| 291 | if line_num < 1 or line_num > len(lines): |
| 292 | continue |
| 293 | |
| 294 | old_line = lines[line_num - 1] |
| 295 | new_line = insert_fl_noexcept_in_line(old_line) |
| 296 | |
| 297 | if new_line is not None and new_line != old_line: |
no test coverage detected