1.. role:: raw-html(raw) 2 :format: html 3 4Libclang tutorial 5================= 6The C Interface to Clang provides a relatively small API that exposes facilities for parsing source code into an abstract syntax tree (AST), loading already-parsed ASTs, traversing the AST, associating physical source locations with elements within the AST, and other facilities that support Clang-based development tools. 7This C interface to Clang will never provide all of the information representation stored in Clang's C++ AST, nor should it: the intent is to maintain an API that is relatively stable from one release to the next, providing only the basic functionality needed to support development tools. 8The entire C interface of libclang is available in the file `Index.h`_ 9 10Essential types overview 11------------------------- 12 13All types of libclang are prefixed with ``CX`` 14 15CXIndex 16~~~~~~~ 17An Index that consists of a set of translation units that would typically be linked together into an executable or library. 18 19CXTranslationUnit 20~~~~~~~~~~~~~~~~~ 21A single translation unit, which resides in an index. 22 23CXCursor 24~~~~~~~~ 25A cursor representing a pointer to some element in the abstract syntax tree of a translation unit. 26 27 28Code example 29"""""""""""" 30 31.. code-block:: cpp 32 33 // file.cpp 34 struct foo{ 35 int bar; 36 int* bar_pointer; 37 }; 38 39.. code-block:: cpp 40 41 #include <clang-c/Index.h> 42 #include <iostream> 43 44 int main(){ 45 CXIndex index = clang_createIndex(0, 0); //Create index 46 CXTranslationUnit unit = clang_parseTranslationUnit( 47 index, 48 "file.cpp", nullptr, 0, 49 nullptr, 0, 50 CXTranslationUnit_None); //Parse "file.cpp" 51 52 53 if (unit == nullptr){ 54 std::cerr << "Unable to parse translation unit. Quitting.\n"; 55 return 0; 56 } 57 CXCursor cursor = clang_getTranslationUnitCursor(unit); //Obtain a cursor at the root of the translation unit 58 } 59 60Visiting elements of an AST 61~~~~~~~~~~~~~~~~~~~~~~~~~~~ 62The elements of an AST can be recursively visited with pre-order traversal with ``clang_visitChildren``. 63 64.. code-block:: cpp 65 66 clang_visitChildren( 67 cursor, //Root cursor 68 [](CXCursor current_cursor, CXCursor parent, CXClientData client_data){ 69 70 CXString current_display_name = clang_getCursorDisplayName(current_cursor); 71 //Allocate a CXString representing the name of the current cursor 72 73 std::cout << "Visiting element " << clang_getCString(current_display_name) << "\n"; 74 //Print the char* value of current_display_name 75 76 clang_disposeString(current_display_name); 77 //Since clang_getCursorDisplayName allocates a new CXString, it must be freed. This applies 78 //to all functions returning a CXString 79 80 return CXChildVisit_Recurse; 81 82 83 }, //CXCursorVisitor: a function pointer 84 nullptr //client_data 85 ); 86 87The return value of ``CXCursorVisitor``, the callable argument of ``clang_visitChildren``, can return one of the three: 88 89#. ``CXChildVisit_Break``: Terminates the cursor traversal 90 91#. ``CXChildVisit_Continue``: Continues the cursor traversal with the next sibling of the cursor just visited, without visiting its children. 92 93#. ``CXChildVisit_Recurse``: Recursively traverse the children of this cursor, using the same visitor and client data 94 95The expected output of that program is 96 97.. code-block:: 98 99 Visiting element foo 100 Visiting element bar 101 Visiting element bar_pointer 102 103 104Extracting information from a Cursor 105~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 106.. The following functions take a ``CXCursor`` as an argument and return associated information. 107 108 109 110Extracting the Cursor kind 111"""""""""""""""""""""""""" 112 113``CXCursorKind clang_getCursorKind(CXCursor)`` Describes the kind of entity that a cursor refers to. Example values: 114 115- ``CXCursor_StructDecl``: A C or C++ struct. 116- ``CXCursor_FieldDecl``: A field in a struct, union, or C++ class. 117- ``CXCursor_CallExpr``: An expression that calls a function. 118 119 120Extracting the Cursor type 121"""""""""""""""""""""""""" 122``CXType clang_getCursorType(CXCursor)``: Retrieve the type of a CXCursor (if any). 123 124A ``CXType`` represents a complete C++ type, including qualifiers and pointers. It has a member field ``CXTypeKind kind`` and additional opaque data. 125 126Example values for ``CXTypeKind kind`` 127 128- ``CXType_Invalid``: Represents an invalid type (e.g., where no type is available) 129- ``CXType_Pointer``: A pointer to another type 130- ``CXType_Int``: Regular ``int`` 131- ``CXType_Elaborated``: Represents a type that was referred to using an elaborated type keyword e.g. struct S, or via a qualified name, e.g., N::M::type, or both. 132 133Any ``CXTypeKind`` can be converted to a ``CXString`` using ``clang_getTypeKindSpelling(CXTypeKind)``. 134 135A ``CXType`` holds additional necessary opaque type info, such as: 136 137- Which struct was referred to? 138- What type is the pointer pointing to? 139- Qualifiers (e.g. ``const``, ``volatile``)? 140 141Qualifiers of a ``CXType`` can be queried with: 142 143- ``clang_isConstQualifiedType(CXType)`` to check for ``const`` 144- ``clang_isRestrictQualifiedType(CXType)`` to check for ``restrict`` 145- ``clang_isVolatileQualifiedType(CXType)`` to check for ``volatile`` 146 147Code example 148"""""""""""" 149.. code-block:: cpp 150 151 //structs.cpp 152 struct A{ 153 int value; 154 }; 155 struct B{ 156 int value; 157 A struct_value; 158 }; 159 160.. code-block:: cpp 161 162 #include <clang-c/Index.h> 163 #include <iostream> 164 165 int main(){ 166 CXIndex index = clang_createIndex(0, 0); //Create index 167 CXTranslationUnit unit = clang_parseTranslationUnit( 168 index, 169 "structs.cpp", nullptr, 0, 170 nullptr, 0, 171 CXTranslationUnit_None); //Parse "structs.cpp" 172 173 if (unit == nullptr){ 174 std::cerr << "Unable to parse translation unit. Quitting.\n"; 175 return 0; 176 } 177 CXCursor cursor = clang_getTranslationUnitCursor(unit); //Obtain a cursor at the root of the translation unit 178 179 clang_visitChildren( 180 cursor, 181 [](CXCursor current_cursor, CXCursor parent, CXClientData client_data){ 182 CXType cursor_type = clang_getCursorType(current_cursor); 183 184 CXString type_kind_spelling = clang_getTypeKindSpelling(cursor_type.kind); 185 std::cout << "Type Kind: " << clang_getCString(type_kind_spelling); 186 clang_disposeString(type_kind_spelling); 187 188 if(cursor_type.kind == CXType_Pointer || // If cursor_type is a pointer 189 cursor_type.kind == CXType_LValueReference || // or an LValue Reference (&) 190 cursor_type.kind == CXType_RValueReference){ // or an RValue Reference (&&), 191 CXType pointed_to_type = clang_getPointeeType(cursor_type);// retrieve the pointed-to type 192 193 CXString pointed_to_type_spelling = clang_getTypeSpelling(pointed_to_type); // Spell out the entire 194 std::cout << "pointing to type: " << clang_getCString(pointed_to_type_spelling);// pointed-to type 195 clang_disposeString(pointed_to_type_spelling); 196 } 197 else if(cursor_type.kind == CXType_Record){ 198 CXString type_spelling = clang_getTypeSpelling(cursor_type); 199 std::cout << ", namely " << clang_getCString(type_spelling); 200 clang_disposeString(type_spelling); 201 } 202 std::cout << "\n"; 203 return CXChildVisit_Recurse; 204 }, 205 nullptr 206 ); 207 208The expected output of program is: 209 210.. code-block:: 211 212 Type Kind: Record, namely A 213 Type Kind: Int 214 Type Kind: Record, namely B 215 Type Kind: Int 216 Type Kind: Record, namely A 217 Type Kind: Record, namely A 218 219 220Reiterating the difference between ``CXType`` and ``CXTypeKind``: For an example 221 222.. code-block:: cpp 223 224 const char* __restrict__ variable; 225 226- Type Kind will be: ``CXType_Pointer`` spelled ``"Pointer"`` 227- Type will be a complex ``CXType`` structure, spelled ``"const char* __restrict__`` 228 229Retrieving source locations 230""""""""""""""""""""""""""" 231 232``CXSourceRange clang_getCursorExtent(CXCursor)`` returns a ``CXSourceRange``, representing a half-open range in the source code. 233 234Use ``clang_getRangeStart(CXSourceRange)`` and ``clang_getRangeEnd(CXSourceRange)`` to retrieve the starting and end ``CXSourceLocation`` from a source range, respectively. 235 236Given a ``CXSourceLocation``, use ``clang_getExpansionLocation`` to retrieve file, line and column of a source location. 237 238Code example 239"""""""""""" 240.. code-block:: cpp 241 242 // Again, file.cpp 243 struct foo{ 244 int bar; 245 int* bar_pointer; 246 }; 247.. code-block:: cpp 248 249 clang_visitChildren( 250 cursor, 251 [](CXCursor current_cursor, CXCursor parent, CXClientData client_data){ 252 253 CXType cursor_type = clang_getCursorType(current_cursor); 254 CXString cursor_spelling = clang_getCursorSpelling(current_cursor); 255 CXSourceRange cursor_range = clang_getCursorExtent(current_cursor); 256 std::cout << "Cursor " << clang_getCString(cursor_spelling); 257 258 CXFile file; 259 unsigned start_line, start_column, start_offset; 260 unsigned end_line, end_column, end_offset; 261 262 clang_getExpansionLocation(clang_getRangeStart(cursor_range), &file, &start_line, &start_column, &start_offset); 263 clang_getExpansionLocation(clang_getRangeEnd (cursor_range), &file, &end_line , &end_column , &end_offset); 264 std::cout << " spanning lines " << start_line << " to " << end_line; 265 clang_disposeString(cursor_spelling); 266 267 std::cout << "\n"; 268 return CXChildVisit_Recurse; 269 }, 270 nullptr 271 ); 272 273The expected output of this program is: 274 275.. code-block:: 276 277 Cursor foo spanning lines 2 to 5 278 Cursor bar spanning lines 3 to 3 279 Cursor bar_pointer spanning lines 4 to 4 280 281Complete example code 282~~~~~~~~~~~~~~~~~~~~~ 283 284.. code-block:: cpp 285 286 #include <clang-c/Index.h> 287 #include <iostream> 288 289 int main(){ 290 CXIndex index = clang_createIndex(0, 0); //Create index 291 CXTranslationUnit unit = clang_parseTranslationUnit( 292 index, 293 "file.cpp", nullptr, 0, 294 nullptr, 0, 295 CXTranslationUnit_None); //Parse "file.cpp" 296 297 if (unit == nullptr){ 298 std::cerr << "Unable to parse translation unit. Quitting.\n"; 299 return 0; 300 } 301 CXCursor cursor = clang_getTranslationUnitCursor(unit); //Obtain a cursor at the root of the translation unit 302 303 304 clang_visitChildren( 305 cursor, 306 [](CXCursor current_cursor, CXCursor parent, CXClientData client_data){ 307 CXType cursor_type = clang_getCursorType(current_cursor); 308 309 CXString type_kind_spelling = clang_getTypeKindSpelling(cursor_type.kind); 310 std::cout << "TypeKind: " << clang_getCString(type_kind_spelling); 311 clang_disposeString(type_kind_spelling); 312 313 if(cursor_type.kind == CXType_Pointer || // If cursor_type is a pointer 314 cursor_type.kind == CXType_LValueReference || // or an LValue Reference (&) 315 cursor_type.kind == CXType_RValueReference){ // or an RValue Reference (&&), 316 CXType pointed_to_type = clang_getPointeeType(cursor_type);// retrieve the pointed-to type 317 318 CXString pointed_to_type_spelling = clang_getTypeSpelling(pointed_to_type); // Spell out the entire 319 std::cout << "pointing to type: " << clang_getCString(pointed_to_type_spelling);// pointed-to type 320 clang_disposeString(pointed_to_type_spelling); 321 } 322 else if(cursor_type.kind == CXType_Record){ 323 CXString type_spelling = clang_getTypeSpelling(cursor_type); 324 std::cout << ", namely " << clang_getCString(type_spelling); 325 clang_disposeString(type_spelling); 326 } 327 std::cout << "\n"; 328 return CXChildVisit_Recurse; 329 }, 330 nullptr 331 ); 332 333 334 clang_visitChildren( 335 cursor, 336 [](CXCursor current_cursor, CXCursor parent, CXClientData client_data){ 337 338 CXType cursor_type = clang_getCursorType(current_cursor); 339 CXString cursor_spelling = clang_getCursorSpelling(current_cursor); 340 CXSourceRange cursor_range = clang_getCursorExtent(current_cursor); 341 std::cout << "Cursor " << clang_getCString(cursor_spelling); 342 343 CXFile file; 344 unsigned start_line, start_column, start_offset; 345 unsigned end_line, end_column, end_offset; 346 347 clang_getExpansionLocation(clang_getRangeStart(cursor_range), &file, &start_line, &start_column, &start_offset); 348 clang_getExpansionLocation(clang_getRangeEnd (cursor_range), &file, &end_line , &end_column , &end_offset); 349 std::cout << " spanning lines " << start_line << " to " << end_line; 350 clang_disposeString(cursor_spelling); 351 352 std::cout << "\n"; 353 return CXChildVisit_Recurse; 354 }, 355 nullptr 356 ); 357 } 358 359 360.. _Index.h: https://github.com/llvm/llvm-project/blob/main/clang/include/clang-c/Index.h 361