""" This script extracts the function that contains a specified line number in a C++ file. """ from argparse import ArgumentParser import os from typing import List, Tuple import clang.cindex def get_functions_at_lines(fpath: os.PathLike, lines: List[int], clang_path: os.PathLike = None) -> List[Tuple[str, Tuple[int, int]]]: """ Find all the functions that contain the specified lines in a file. """ functions = [] for line in lines: # check if we've already found this line if any(start <= line <= end for _, (start, end) in functions): continue function_body, range = get_function_at_line(fpath, line, clang_path=clang_path) if function_body: functions.append((function_body, range)) return functions def remove_macros(filename: str, line_numbers: List[int]) -> List[int]: """ Remove all macros from a file. Lines is a list of numbers that you would like to have mapped to their new line numbers after the macros are removed. """ with open(filename, 'r') as f: lines = f.readlines() new_line_numbers = [] new_lines = [] num_removed = 0 for i, line in enumerate(lines): if line.startswith('#'): num_removed += 1 else: new_lines.append(line) if i in line_numbers: new_line_numbers.append(i - num_removed) with open(filename, 'w') as f: f.write(''.join(new_lines)) return new_line_numbers def get_function_at_line(filename, line_number, clang_path=None): if clang_path and not clang.cindex.Config.loaded: clang.cindex.Config.set_library_file(clang_path) index = clang.cindex.Index.create() try: translation_unit = index.parse(filename) except clang.cindex.TranslationUnitLoadError: return None, None def find_function(node, line_number): # Check if node is function-like and contains the line number if node.kind == clang.cindex.CursorKind.FUNCTION_DECL or node.kind == clang.cindex.CursorKind.CXX_METHOD: start_line = node.extent.start.line end_line = node.extent.end.line #print(f"Checking function {node.spelling} at lines {start_line} - {end_line}") if start_line <= line_number <= end_line: return node for child in node.get_children(): result = find_function(child, line_number) if result: return result return None # Start from the root node (translation unit) and find the function function_node = find_function(translation_unit.cursor, line_number) if function_node: start_line = function_node.extent.start.line end_line = function_node.extent.end.line with open(filename, 'r') as f: lines = f.readlines() return ''.join(lines[start_line - 1:end_line]), (start_line, end_line) else: return None, None if __name__ == "__main__": parser = ArgumentParser(description="Extract the function that contains a specified line number in a C++ file.") parser.add_argument("filename", help="The C++ file to analyze") parser.add_argument("line_number", type=int, help="The line number to search for") parser.add_argument("--clang_path", help="Path to libclang.so if necessary") args = parser.parse_args() result, rnge = get_function_at_line(args.filename, args.line_number, clang_path=args.clang_path) if result is None: result = f"No function found at line {args.line_number}" print(result, rnge)