How to extract C/C++ function extent (from..to source lines) from source code using clang

The following program shows how to extract the extent of a C/C++ function using the clang library. The extent is defined by the start and end source lines of the function.

#include <clang-c/Index.h>
#include <iostream>
#include <string>

int main(int argc, char** argv) {
    if (argc < 3) {
        std::cerr << "Usage: " << argv[0] << " <source-file> <function-name>" << std::endl;
        return 1;
    }
    const char* filename = argv[1];
    const char* funcname = argv[2];
    CXIndex index = clang_createIndex(0, 0);
    CXTranslationUnit unit = clang_parseTranslationUnit(
        index, filename, nullptr, 0, nullptr, 0, CXTranslationUnit_None);
    if (unit == nullptr) {
        std::cerr << "Unable to parse translation unit." << std::endl;
        return 1;
    }
    struct VisitorData {
        std::string target;
        unsigned start_line = 0;
        unsigned end_line = 0;
    } data;
    data.target = funcname;
    auto visitor = [](CXCursor c, CXCursor parent, CXClientData client_data) {
        VisitorData* data = static_cast<VisitorData*>(client_data);
        if (clang_getCursorKind(c) == CXCursor_FunctionDecl && clang_isCursorDefinition(c)) {
            CXString name = clang_getCursorSpelling(c);
            std::string func_name = clang_getCString(name);
            clang_disposeString(name);
            if (func_name == data->target) {
                CXSourceRange range = clang_getCursorExtent(c);
                CXSourceLocation start = clang_getRangeStart(range);
                CXSourceLocation end = clang_getRangeEnd(range);
                unsigned start_line, start_col, end_line, end_col;
                clang_getSpellingLocation(start, nullptr, &start_line, &start_col, nullptr);
                clang_getSpellingLocation(end, nullptr, &end_line, &end_col, nullptr);
                data->start_line = start_line;
                data->end_line = end_line;
                // Stop traversal
                return CXChildVisit_Break;
            }
        }
        return CXChildVisit_Recurse;
    };
    clang_visitChildren(clang_getTranslationUnitCursor(unit), visitor, &data);
    if (data.start_line != 0 && data.end_line != 0) {
        std::cout << data.target << "() extent: lines " << data.start_line << " to " << data.end_line << std::endl;
    } else {
        std::cout << "Function not found." << std::endl;
    }
    clang_disposeTranslationUnit(unit);
    clang_disposeIndex(index);
    return 0;
}

How to compile

g++ -O2 -std=c++20 -march=corei7 -g extractfunction.cpp -o extractfunction -I/usr/lib/llvm-19/include -L/usr/lib/llvm-19/lib -lclang -lLLVM

How to run

./extractfunction <source-file> <function-name>

Example output

$ ./commentextract extractfunction.cpp main
main() extent: lines 5 to 55