MCPcopy Create free account
hub / github.com/banach-space/clang-tutor

github.com/banach-space/clang-tutor @main

Chat with this repo
repository ↗ · DeepWiki ↗ · + Follow
160 symbols 180 edges 52 files 54 documented · 34% updated 59d ago★ 76511 open issues

Browse by type

Functions 109 Types & classes 51
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

clang-tutor

Apple Silicon x86-Ubuntu

Example Clang plugins for C and C++ - based on Clang 22

clang-tutor is a collection of self-contained reference Clang plugins. It's a tutorial that targets novice and aspiring Clang developers. Key features:

  • Modern - based on the latest version of Clang (and updated with every release)
  • Complete - includes build scripts, LIT tests and CI set-up
  • Out of tree - builds against a binary Clang installation (no need to build Clang from sources)

Corrections and feedback always welcome!

Overview

Clang (together with LibTooling) provides a very powerful API and infrastructure for analysing and modifying source files from the C language family. With Clang's plugin framework one can relatively easily create bespoke tools that aid development and improve productivity. The aim of clang-tutor is to showcase this framework through small, self-contained and testable examples, implemented using idiomatic LLVM.

This document explains how to set-up your environment, build and run the project, and go about debugging. The source files, apart from the code itself, contain comments that will guide you through the implementation. The tests highlight what edge cases are supported, so you may want to skim through them as well.

Table of Contents

HelloWorld

The HelloWorld plugin from HelloWorld.cpp is a self-contained reference example. The corresponding CMakeLists.txt implements the minimum set-up for an out-of-tree plugin.

HelloWorld extracts some interesting information from the input translation unit. It visits all C++ record declarations (more specifically class, struct and union declarations) and counts them. Recall that translation unit consists of the input source file and all the header files that it includes (directly or indirectly).

HelloWorld prints the results on a file by file basis, i.e. separately for every header file that has been included. It visits all declarations - including the ones in header files included by other header files. This may lead to some surprising results!

You can build and run HelloWorld like this:

# Build the plugin
export Clang_DIR=<installation/dir/of/clang/22>
export CLANG_TUTOR_DIR=


mkdir build
cd build
cmake -DCT_Clang_INSTALL_DIR=$Clang_DIR $CLANG_TUTOR_DIR/HelloWorld/
make
# Run the plugin
$Clang_DIR/bin/clang -cc1 -load ./libHelloWorld.{so|dylib} -plugin hello-world $CLANG_TUTOR_DIR/test/HelloWorld-basic.cpp

You should see the following output:

# Expected output
(clang-tutor) file: 

/test/HelloWorld-basic.cpp
(clang-tutor)  count: 3

How To Analyze STL Headers

In order to see what happens with multiple indirectly included header files, you can run HelloWorld on one of the header files from the Standard Template Library. For example, you can use the following C++ file that simply includes vector.h:

// file.cpp
#include <vector>

When running a Clang plugin on a C++ file that includes headers from STL, it is easier to run it with clang++ (rather than clang -cc1) like this:

$Clang_DIR/bin/clang++ -c -Xclang -load -Xclang libHelloWorld.dylib -Xclang -plugin -Xclang hello-world file.cpp

This way you can be confident that all the necessary include paths (required to locate STL headers) are automatically added. For the above input file, HelloWorld will print:

  • an overview of all header files included when using #include <vector>, and
  • the number of C++ records declared in each.

Note that there are no explicit declarations in file.cpp and only one header file is included. However, the output on my system consists of 37 header files (one of which contains 371 declarations). Note that the actual output depends on your host OS, the C++ standard library implementation and its version. Your results are likely to be different.

Development Environment

Platform Support And Requirements

clang-tutor has been tested on Ubuntu 20.04 and Mac OS X 10.14.6. In order to build clang-tutor you will need:

  • LLVM 22 and Clang 22
  • C++ compiler that supports C++17
  • CMake 3.13.4 or higher

As Clang is a subproject within llvm-project, it depends on LLVM (i.e. clang-tutor requires development packages for both Clang and LLVM).

There are additional requirements for tests (these will be satisfied by installing LLVM 22): * lit (aka llvm-lit, LLVM tool for executing the tests) * FileCheck (LIT requirement, it's used to check whether tests generate the expected output)

Installing Clang 22 On Mac OS X

On Darwin you can install Clang 22 and LLVM 22 with Homebrew:

brew install llvm

If you already have an older version of Clang and LLVM installed, you can upgrade it to Clang 22 and LLVM 22 like this:

brew upgrade llvm

Once the installation (or upgrade) is complete, all the required header files, libraries and tools will be located in /usr/local/opt/llvm/.

Installing Clang 22 On Ubuntu

On Ubuntu Jammy Jellyfish, you can install modern LLVM from the official repository:

wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo apt-add-repository "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-22 main"
sudo apt-get update
sudo apt-get install -y llvm-22 llvm-22-dev libllvm22 llvm-22-tools clang-22 libclang-common-22-dev libclang-22-dev libmlir-22 libmlir-22-dev

This will install all the required header files, libraries and tools in /usr/lib/llvm-22/.

Building Clang 22 From Sources

Building from sources can be slow and tricky to debug. It is not necessary, but might be your preferred way of obtaining LLVM/Clang 22. The following steps will work on Linux and Mac OS X:

git clone https://github.com/llvm/llvm-project.git
cd llvm-project
git checkout release/22.x
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_TARGETS_TO_BUILD=host -DLLVM_ENABLE_PROJECTS="clang;libcxx;libcxxabi" <llvm-project/root/dir>/llvm/
cmake --build .

For more details read the official documentation.

Note for macOS users

As per this great description by Arthur O’Dwyer , add -DDEFAULT_SYSROOT="$(xcrun --show-sdk-path)" to your CMake invocation when building Clang from sources. Otherwise, clang won't be able to find e.g. standard C headers (e.g. wchar.h).

Building & Testing

You can build clang-tutor (and all the provided plugins) as follows:

cd <build/dir>
cmake -DCT_Clang_INSTALL_DIR=<installation/dir/of/clang/22> 


make

The CT_Clang_INSTALL_DIR variable should be set to the root of either the installation or build directory of Clang 22. It is used to locate the corresponding LLVMConfig.cmake script that is used to set the include and library paths.

In order to run the tests, you need to install llvm-lit (aka lit). It's not bundled with LLVM 22 packages, but you can install it with pip:

# Install lit - note that this installs lit globally
pip install lit

Running the tests is as simple as:

$ lit <build_dir>/test

Voilà! You should see all tests passing.

Overview of The Plugins

This table contains a summary of the examples available in clang-tutor. The Framework column refers to a plugin framework available in Clang that was used to implement the corresponding example. This is either RecursiveASTVisitor, ASTMatcher or both.

Name Description Framework
HelloWorld counts the number of class, struct and union declarations in the input translation unit RecursiveASTVisitor
LACommenter adds comments to literal arguments in functions calls ASTMatcher
CodeStyleChecker issue a warning if the input file does not follow one of LLVM's coding style guidelines RecursiveASTVisitor
Obfuscator obfuscates integer addition and subtraction ASTMatcher
UnusedForLoopVar issue a warning if a for-loop variable is not used RecursiveASTVisitor + ASTMatcher
CodeRefactor rename class/struct method names ASTMatcher

Once you've built this project, you can experiment with every plugin separately. All of them accept C and C++ files as input. Below you will find more detailed descriptions (except for HelloWorld, which is documented here).

LACommenter

The LACommenter (Literal Argument Commenter) plugin will comment literal arguments in function calls. For example, in the following input code:

extern void foo(int some_arg);

void bar() {
  foo(123);
}

LACommenter will decorate the invocation of foo as follows:

extern void foo(int some_arg);

void bar() {
  foo(/*some_arg=*/123);
}

This commenting style follows LLVM's oficial guidelines. LACommenter will comment character, integer, floating point, boolean and string literal arguments.

This plugin is based on a similar example by Peter Smith presented here.

Run the plugin

You can test LACommenter on the example presented above. Assuming that it was saved in input_file.c, you can add comments to it as follows:

$Clang_DIR/bin/clang -cc1 -load <build_dir>/lib/libLACommenter.dylib -plugin LAC input_file.cpp

Run the plugin through ct-la-commenter

locommenter is a standalone tool that will run the LACommenter plugin, but without the need of using clang and loading the plugin:

<build_dir>/bin/ct-la-commenter input_file.cpp --

If you don't append -- at the end of tools invocation will get the complain from Clang tools about missing compilation database as follow:

Error while trying to load a compilation database:
Could not auto-detect compilation database for file "input_file.cpp"
No compilation database found in 

 or any parent directory
fixed-compilation-database: Error while opening fixed database: No such file or directory
json-compilation-database: Error while opening JSON database: No such file or directory
Running without flags.

Another workaround to solve the issue is to set the CMAKE_EXPORT_COMPILE_COMMANDS flag during the CMake invocation. It will give you the compilation database into your build directory with the filename as compile_commands.json. More detailed explanation about it can be found on Eli Bendersky's blog.

CodeStyleChecker

This plugin demonstrates how to use Clang's DiagnosticEngine to generate custom compiler warnings. Essentially, CodeStyleChecker checks whether names of classes, functions and variables in the input translation unit adhere to LLVM's style guide. If not, a warning is printed. For every warning, CodeStyleChecker generates a suggestion that would fix the corresponding issue. This is done with the FixItHint API. SourceLocation API is used to generate valid source location.

CodeStyleChecker is robust enough to cope with complex examples like vector.h from STL, yet the actual implementation is fairly compact. For example, it can correctly analyze names expanded from macros and knows that it should ignore user-defined conversion operators.

Run the plugin

Let's test

Core symbols most depended-on inside this repo

Shape

Method 62
Class 51
Function 47

Languages

C++100%

Modules by API surface

lib/CodeStyleChecker.cpp11 symbols
lib/UnusedForLoopVar.cpp10 symbols
HelloWorld/HelloWorld.cpp10 symbols
lib/Obfuscator.cpp7 symbols
lib/CodeRefactor.cpp7 symbols
test/MBA_sub_int.cpp6 symbols
test/MBA_add_int.cpp6 symbols
test/CodeStyleCheckerMacro.cpp6 symbols
lib/LACommenter.cpp6 symbols
include/UnusedForLoopVar.h6 symbols
include/Obfuscator.h6 symbols
tools/CodeRefactorMain.cpp5 symbols

For agents

$ claude mcp add clang-tutor \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page