1*e5dd7070Spatrick#!/usr/bin/env python
2*e5dd7070Spatrick
3*e5dd7070Spatrick#===- cindex-dump.py - cindex/Python Source Dump -------------*- python -*--===#
4*e5dd7070Spatrick#
5*e5dd7070Spatrick# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
6*e5dd7070Spatrick# See https://llvm.org/LICENSE.txt for license information.
7*e5dd7070Spatrick# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8*e5dd7070Spatrick#
9*e5dd7070Spatrick#===------------------------------------------------------------------------===#
10*e5dd7070Spatrick
11*e5dd7070Spatrick"""
12*e5dd7070SpatrickA simple command line tool for dumping a source file using the Clang Index
13*e5dd7070SpatrickLibrary.
14*e5dd7070Spatrick"""
15*e5dd7070Spatrick
16*e5dd7070Spatrickdef get_diag_info(diag):
17*e5dd7070Spatrick    return { 'severity' : diag.severity,
18*e5dd7070Spatrick             'location' : diag.location,
19*e5dd7070Spatrick             'spelling' : diag.spelling,
20*e5dd7070Spatrick             'ranges' : diag.ranges,
21*e5dd7070Spatrick             'fixits' : diag.fixits }
22*e5dd7070Spatrick
23*e5dd7070Spatrickdef get_cursor_id(cursor, cursor_list = []):
24*e5dd7070Spatrick    if not opts.showIDs:
25*e5dd7070Spatrick        return None
26*e5dd7070Spatrick
27*e5dd7070Spatrick    if cursor is None:
28*e5dd7070Spatrick        return None
29*e5dd7070Spatrick
30*e5dd7070Spatrick    # FIXME: This is really slow. It would be nice if the index API exposed
31*e5dd7070Spatrick    # something that let us hash cursors.
32*e5dd7070Spatrick    for i,c in enumerate(cursor_list):
33*e5dd7070Spatrick        if cursor == c:
34*e5dd7070Spatrick            return i
35*e5dd7070Spatrick    cursor_list.append(cursor)
36*e5dd7070Spatrick    return len(cursor_list) - 1
37*e5dd7070Spatrick
38*e5dd7070Spatrickdef get_info(node, depth=0):
39*e5dd7070Spatrick    if opts.maxDepth is not None and depth >= opts.maxDepth:
40*e5dd7070Spatrick        children = None
41*e5dd7070Spatrick    else:
42*e5dd7070Spatrick        children = [get_info(c, depth+1)
43*e5dd7070Spatrick                    for c in node.get_children()]
44*e5dd7070Spatrick    return { 'id' : get_cursor_id(node),
45*e5dd7070Spatrick             'kind' : node.kind,
46*e5dd7070Spatrick             'usr' : node.get_usr(),
47*e5dd7070Spatrick             'spelling' : node.spelling,
48*e5dd7070Spatrick             'location' : node.location,
49*e5dd7070Spatrick             'extent.start' : node.extent.start,
50*e5dd7070Spatrick             'extent.end' : node.extent.end,
51*e5dd7070Spatrick             'is_definition' : node.is_definition(),
52*e5dd7070Spatrick             'definition id' : get_cursor_id(node.get_definition()),
53*e5dd7070Spatrick             'children' : children }
54*e5dd7070Spatrick
55*e5dd7070Spatrickdef main():
56*e5dd7070Spatrick    from clang.cindex import Index
57*e5dd7070Spatrick    from pprint import pprint
58*e5dd7070Spatrick
59*e5dd7070Spatrick    from optparse import OptionParser, OptionGroup
60*e5dd7070Spatrick
61*e5dd7070Spatrick    global opts
62*e5dd7070Spatrick
63*e5dd7070Spatrick    parser = OptionParser("usage: %prog [options] {filename} [clang-args*]")
64*e5dd7070Spatrick    parser.add_option("", "--show-ids", dest="showIDs",
65*e5dd7070Spatrick                      help="Compute cursor IDs (very slow)",
66*e5dd7070Spatrick                      action="store_true", default=False)
67*e5dd7070Spatrick    parser.add_option("", "--max-depth", dest="maxDepth",
68*e5dd7070Spatrick                      help="Limit cursor expansion to depth N",
69*e5dd7070Spatrick                      metavar="N", type=int, default=None)
70*e5dd7070Spatrick    parser.disable_interspersed_args()
71*e5dd7070Spatrick    (opts, args) = parser.parse_args()
72*e5dd7070Spatrick
73*e5dd7070Spatrick    if len(args) == 0:
74*e5dd7070Spatrick        parser.error('invalid number arguments')
75*e5dd7070Spatrick
76*e5dd7070Spatrick    index = Index.create()
77*e5dd7070Spatrick    tu = index.parse(None, args)
78*e5dd7070Spatrick    if not tu:
79*e5dd7070Spatrick        parser.error("unable to load input")
80*e5dd7070Spatrick
81*e5dd7070Spatrick    pprint(('diags', [get_diag_info(d) for d in  tu.diagnostics]))
82*e5dd7070Spatrick    pprint(('nodes', get_info(tu.cursor)))
83*e5dd7070Spatrick
84*e5dd7070Spatrickif __name__ == '__main__':
85*e5dd7070Spatrick    main()
86*e5dd7070Spatrick
87