Skip to content

Pseudomanifold/libclang-experiments

Repository files navigation

libclang-experiments — Some experiments with libclang

This repository contains some of my experiments with libclang, or, to be more precise, the C bindings of libclang. I already detailed some of my experiments in two blog posts. The first deals with walking an abstract syntax tree, while the second deals with counting the extents of a function.

Requirements

  • libclang (for parsing ASTs)
  • clang (for creating ASTs)

Building the examples

$ mkdir build
$ cd build
$ cmake ../
$ make

Obtaining an AST

Some of the example programs require the explicit creation of an abstract syntax tree, while others make use of a database of compile commands. In order to obtain an abstract syntax tree, call clang with the following parameters:

clang++ -std=c++11 -emit-ast FILE

Optionally, you can add -I or any other parameter that is required for compiling a given program.

The experiments

Let me briefly explain how to use some of the experiments.

ast-dumper & ast-walker

These programs walk an abstract syntax tree. They roughly follow the implementation given in this blog post. To use one of them (I am exemplarily demonstrating ast-walker), you require the creation of an abstract syntax tree:

$ clang++ -std=c++11 -emit-ast ../examples/tuple.cc
$ ./ast-walker tuple.ast

This should result in an output similar to this:

 ClassDecl (foo)
- CXXAccessSpecifier ()
- CXXConstructor (foo)
-- ParmDecl (n_)
-- ParmDecl (c_)
-- ParmDecl (d_)
-- MemberRef (n)
-- InitListExpr ()
--- UnexposedExpr (n_)
---- DeclRefExpr (n_)
-- MemberRef (c)
-- InitListExpr ()
--- UnexposedExpr (c_)
---- DeclRefExpr (c_)
-- MemberRef (d)
-- InitListExpr ()
--- UnexposedExpr (d_)
---- DeclRefExpr (d_)
-- CompoundStmt ()
- FriendDecl ()
-- FunctionDecl (operator<)
--- ParmDecl (lh)
---- TypeRef (class foo)
--- ParmDecl (rh)
---- TypeRef (class foo)
--- CompoundStmt ()
---- ReturnStmt ()
----- UnexposedExpr ()
------ CallExpr (operator<)
------- UnexposedExpr ()
-------- UnexposedExpr (tie)
--------- CallExpr (tie)
---------- UnexposedExpr (tie)
----------- DeclRefExpr (tie)
------------ NamespaceRef (std)
---------- MemberRefExpr (n)
----------- DeclRefExpr (lh)
---------- MemberRefExpr (c)
----------- DeclRefExpr (lh)
---------- MemberRefExpr (d)
----------- DeclRefExpr (lh)
------- UnexposedExpr (operator<)
-------- DeclRefExpr (operator<)
------- UnexposedExpr ()
-------- UnexposedExpr (tie)
--------- CallExpr (tie)
---------- UnexposedExpr (tie)
----------- DeclRefExpr (tie)
------------ NamespaceRef (std)
---------- MemberRefExpr (n)
----------- DeclRefExpr (rh)
---------- MemberRefExpr (c)
----------- DeclRefExpr (rh)
---------- MemberRefExpr (d)
----------- DeclRefExpr (rh)
- CXXAccessSpecifier ()
- FieldDecl (n)
- FieldDecl (c)
- FieldDecl (d)

count-function-extents

Getting this program to run can be a tiny bit more trickier. We should supply it with the default paths required by clang++. To determine them, call

$ clang++ -v -c FILE

where FILE is a source file of your choice. The resulting output should contain the line

#include <...> search starts here:

and a list of paths. Copy them and put them into one command-line variable, like so:

$ export CPLUS_INCLUDE_PATH=/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/7.1.1/../../../../include/c++/7.1.1:/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/7.1.1/../../../../include/c++/7.1.1/x86_64-pc-linux-gnu:/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/7.1.1/../../../../include/c++/7.1.1/backward:/usr/local/include:/usr/bin/../lib/clang/4.0.1/include

Afterwards, you can call the program on a test executable:

$ ./count-function-extents ../examples/functions.cc

This should result in the following output:

Obtained 0 compile commands
  theAnswerToLifeTheUniverseAndEverything: 3
  sum: 3
  square: 3
  cube: 3
  factorial: 6
  fibonacci: 14

You can also call the function for any executable specified in a compile_commands.json data base:

$ ./count-function-extents ../count-function-extents.cc
Parsing /home/brieck/Projects/libclang-experiments/count-function-extents.cc...
Obtained 1 compile commands
  getCursorSpelling: 7
  resolvePath: 17
  functionVisitor: 24
  main: 74

I am sure that these programs could be easily improved. I look forward to your changes!

Additional information