[cfe-commits] r96106 - in /cfe/trunk/bindings/python: clang/cindex.py examples/cindex/cindex-includes.py tests/cindex/INPUTS/header1.h tests/cindex/INPUTS/header2.h tests/cindex/INPUTS/header3.h tests/cindex/INPUTS/include.cpp tests/cindex/test_translation_unit.py

Daniel Dunbar daniel at zuster.org
Sat Feb 13 10:33:19 PST 2010


Author: ddunbar
Date: Sat Feb 13 12:33:18 2010
New Revision: 96106

URL: http://llvm.org/viewvc/llvm-project?rev=96106&view=rev
Log:
cindex/Python: Add TranslationUnit.get_includes, patch by Andrew Sutton!

Added:
    cfe/trunk/bindings/python/examples/cindex/cindex-includes.py
    cfe/trunk/bindings/python/tests/cindex/INPUTS/header1.h
    cfe/trunk/bindings/python/tests/cindex/INPUTS/header2.h
    cfe/trunk/bindings/python/tests/cindex/INPUTS/header3.h
    cfe/trunk/bindings/python/tests/cindex/INPUTS/include.cpp
Modified:
    cfe/trunk/bindings/python/clang/cindex.py
    cfe/trunk/bindings/python/tests/cindex/test_translation_unit.py

Modified: cfe/trunk/bindings/python/clang/cindex.py
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/bindings/python/clang/cindex.py?rev=96106&r1=96105&r2=96106&view=diff

==============================================================================
--- cfe/trunk/bindings/python/clang/cindex.py (original)
+++ cfe/trunk/bindings/python/clang/cindex.py Sat Feb 13 12:33:18 2010
@@ -719,6 +719,25 @@
         """Get the original translation unit source file name."""
         return TranslationUnit_spelling(self)
 
+    def get_includes(self):
+        """
+        Return an iterable sequence of FileInclusion objects that describe the
+        sequence of inclusions in a translation unit. The first object in
+        this sequence is always the input file. Note that this method will not
+        recursively iterate over header files included through precompiled
+        headers.
+        """
+        def visitor(fobj, lptr, depth, includes):
+            loc = lptr.contents
+            includes.append(FileInclusion(loc.file, File(fobj), loc, depth))
+
+        # Automatically adapt CIndex/ctype pointers to python objects
+        includes = []
+        TranslationUnit_includes(self,
+                                 TranslationUnit_includes_callback(visitor),
+                                 includes)
+        return iter(includes)
+
 class File(ClangObject):
     """
     The File class represents a particular source file that is part of a
@@ -735,6 +754,26 @@
         """Return the last modification time of the file."""
         return File_time(self)
 
+class FileInclusion(object):
+    """
+    The FileInclusion class represents the inclusion of one source file by
+    another via a '#include' directive or as the input file for the translation
+    unit. This class provides information about the included file, the including
+    file, the location of the '#include' directive and the depth of the included
+    file in the stack. Note that the input file has depth 0.
+    """
+
+    def __init__(self, src, tgt, loc, depth):
+        self.source = src
+        self.include = tgt
+        self.location = loc
+        self.depth = depth
+
+    @property
+    def is_input_file(self):
+        """True if the included file is the input file."""
+        return self.depth == 0
+
 # Additional Functions and Types
 
 # String Functions
@@ -870,6 +909,15 @@
 TranslationUnit_dispose = lib.clang_disposeTranslationUnit
 TranslationUnit_dispose.argtypes = [TranslationUnit]
 
+TranslationUnit_includes_callback = CFUNCTYPE(None,
+                                              c_object_p,
+                                              POINTER(SourceLocation),
+                                              c_uint, py_object)
+TranslationUnit_includes = lib.clang_getInclusions
+TranslationUnit_includes.argtypes = [TranslationUnit,
+                                     TranslationUnit_includes_callback,
+                                     py_object]
+
 # File Functions
 File_name = lib.clang_getFileName
 File_name.argtypes = [File]

Added: cfe/trunk/bindings/python/examples/cindex/cindex-includes.py
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/bindings/python/examples/cindex/cindex-includes.py?rev=96106&view=auto

==============================================================================
--- cfe/trunk/bindings/python/examples/cindex/cindex-includes.py (added)
+++ cfe/trunk/bindings/python/examples/cindex/cindex-includes.py Sat Feb 13 12:33:18 2010
@@ -0,0 +1,62 @@
+#!/usr/bin/env python
+
+#===- cindex-includes.py - cindex/Python Inclusion Graph -----*- python -*--===#
+#
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+"""
+A simple command line tool for dumping a Graphviz description (dot) that
+describes include dependencies.
+"""
+
+def main():
+    import sys
+    from clang.cindex import Index
+
+    # FIXME: Allow the user to pass command line options to clang so that
+    # we can use -D and -U.
+    from optparse import OptionParser, OptionGroup
+
+    parser = OptionParser("usage: %prog [options] {filename} [clang-args*]")
+    parser.disable_interspersed_args()
+    (opts, args) = parser.parse_args()
+    if len(args) == 0:
+        parser.error('invalid number arguments')
+
+    # FIXME: Add an output file option
+    out = sys.stdout
+
+    input_path = args.pop(0)
+
+
+    index = Index.create()
+    tu = index.parse(input_path, args)
+    if not tu:
+        parser.error("unable to load input")
+
+    # A helper function for generating the node name.
+    def name(f):
+        return "\"" + f.name + "\""
+
+    # Generate the include graph
+    out.write("digraph G {\n")
+    for i in tu.get_includes():
+        line = "  ";
+        if i.is_input_file:
+            # Always write the input file as a node just in case it doesn't
+            # actually include anything. This would generate a 1 node graph.
+            line += name(i.include)
+        else:
+            line += name(i.source) + "->" + name(i.include)
+        line += "\n";
+        out.write(line)
+    out.write("}\n")
+
+if __name__ == '__main__':
+    main()
+

Added: cfe/trunk/bindings/python/tests/cindex/INPUTS/header1.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/bindings/python/tests/cindex/INPUTS/header1.h?rev=96106&view=auto

==============================================================================
--- cfe/trunk/bindings/python/tests/cindex/INPUTS/header1.h (added)
+++ cfe/trunk/bindings/python/tests/cindex/INPUTS/header1.h Sat Feb 13 12:33:18 2010
@@ -0,0 +1,6 @@
+#ifndef HEADER1
+#define HEADER1
+
+#include "header3.h"
+
+#endif

Added: cfe/trunk/bindings/python/tests/cindex/INPUTS/header2.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/bindings/python/tests/cindex/INPUTS/header2.h?rev=96106&view=auto

==============================================================================
--- cfe/trunk/bindings/python/tests/cindex/INPUTS/header2.h (added)
+++ cfe/trunk/bindings/python/tests/cindex/INPUTS/header2.h Sat Feb 13 12:33:18 2010
@@ -0,0 +1,6 @@
+#ifndef HEADER2
+#define HEADER2
+
+#include "header3.h"
+
+#endif

Added: cfe/trunk/bindings/python/tests/cindex/INPUTS/header3.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/bindings/python/tests/cindex/INPUTS/header3.h?rev=96106&view=auto

==============================================================================
--- cfe/trunk/bindings/python/tests/cindex/INPUTS/header3.h (added)
+++ cfe/trunk/bindings/python/tests/cindex/INPUTS/header3.h Sat Feb 13 12:33:18 2010
@@ -0,0 +1,3 @@
+// Not a guarded header!
+
+void f();

Added: cfe/trunk/bindings/python/tests/cindex/INPUTS/include.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/bindings/python/tests/cindex/INPUTS/include.cpp?rev=96106&view=auto

==============================================================================
--- cfe/trunk/bindings/python/tests/cindex/INPUTS/include.cpp (added)
+++ cfe/trunk/bindings/python/tests/cindex/INPUTS/include.cpp Sat Feb 13 12:33:18 2010
@@ -0,0 +1,5 @@
+#include "header1.h"
+#include "header2.h"
+#include "header1.h"
+
+int main() { }

Modified: cfe/trunk/bindings/python/tests/cindex/test_translation_unit.py
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/bindings/python/tests/cindex/test_translation_unit.py?rev=96106&r1=96105&r2=96106&view=diff

==============================================================================
--- cfe/trunk/bindings/python/tests/cindex/test_translation_unit.py (original)
+++ cfe/trunk/bindings/python/tests/cindex/test_translation_unit.py Sat Feb 13 12:33:18 2010
@@ -49,3 +49,25 @@
             ('fake.c', StringIO.StringIO('int x;'))])
     spellings = [c.spelling for c in tu.cursor.get_children()]
     assert spellings[-1] == 'x'
+
+
+def test_includes():
+    def eq(expected, actual):
+        if not actual.is_input_file:
+            return expected[0] == actual.source.name and \
+                   expected[1] == actual.include.name
+        else:
+            return expected[1] == actual.include.name
+
+    src = os.path.join(kInputsDir, 'include.cpp')
+    h1 = os.path.join(kInputsDir, "header1.h")
+    h2 = os.path.join(kInputsDir, "header2.h")
+    h3 = os.path.join(kInputsDir, "header3.h")
+    inc = [(None, src), (src, h1), (h1, h3), (src, h2), (h2, h3)]
+
+    index = Index.create()
+    tu = index.parse(src)
+    for i in zip(inc, tu.get_includes()):
+        assert eq(i[0], i[1])
+
+





More information about the cfe-commits mailing list