|
import sys
|
|
|
|
from clang.cindex import Config
|
|
from clang.cindex import CursorKind
|
|
from clang.cindex import Index
|
|
from clang.cindex import TranslationUnit
|
|
|
|
# Set these according to the location and version of libclang on your system
|
|
LIBCLANG_PATH = '/usr/lib/llvm-3.4/lib'
|
|
LIBCLANG_NAME = 'libclang-3.4.so'
|
|
|
|
|
|
def display_node(node):
|
|
""" A helper function to pretty print the particulars of the passed in
|
|
Cursor object
|
|
"""
|
|
start_line = node.extent.start.line
|
|
start_col = node.extent.start.column
|
|
end_line = node.extent.end.line
|
|
end_col = node.extent.end.column
|
|
print '{:s} ({:d}:{:d} - {:d}:{:d})'.format(node.displayname,
|
|
start_line, start_col,
|
|
end_line, end_col)
|
|
|
|
def find_function_calls(node):
|
|
""" A recursive function call to find all function calls that are children
|
|
of the passed in Cursor object
|
|
"""
|
|
results = []
|
|
for child_node in node.get_children():
|
|
if child_node.kind == CursorKind.CALL_EXPR:
|
|
results.append(child_node)
|
|
else:
|
|
results.extend(find_function_calls(child_node))
|
|
return results
|
|
|
|
def main():
|
|
""" This is a very simple utility that uses the Clang compiler frontend
|
|
to parse a C source file and return a list of function declarations within
|
|
that file along with the lines on which each declaration starts and ends.
|
|
"""
|
|
|
|
if len(sys.argv) < 2:
|
|
print 'ERROR: not enough arguments provided\n'
|
|
print 'USAGE: python ddc_preproc.py <file.c>'
|
|
return -1
|
|
|
|
# Configure the library (not sure why this has to be done manually)
|
|
Config.set_library_path(LIBCLANG_PATH)
|
|
Config.set_library_file(LIBCLANG_NAME)
|
|
|
|
# Build the TU from the passed file argument
|
|
source_file = sys.argv[1]
|
|
tu = TranslationUnit.from_source(source_file)
|
|
|
|
# Loop through all of the children nodes and extract function definitions
|
|
# along with their start and end lines from the specified source file
|
|
print 'Function declarations:'
|
|
print '-' * 80
|
|
main_func = None
|
|
for child in tu.cursor.get_children():
|
|
if str(child.location.file) == source_file and \
|
|
child.kind == CursorKind.FUNCTION_DECL:
|
|
# Store a reference to the main function
|
|
if child.spelling == 'main':
|
|
main_func = child
|
|
display_node(child)
|
|
print '\n'
|
|
|
|
# Find all function calls originating from the main function
|
|
print 'Function calls:'
|
|
print '-' * 80
|
|
for child in find_function_calls(main_func):
|
|
display_node(child)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|