libClang前端语法解析(CXCursor使用)

  • 工程结构:
funning@funning-PC:~/workspace/workspace/recode/gg/TestApp$ tree
.
├── CMakeLists.txt
├── FindLibClang.cmake
├── main.cpp
├── modela.cpp
└── modela.hpp

  • FindLibClang.cmake:
if (NOT CLANG_ROOT)
  set(CLANG_ROOT $ENV{CLANG_ROOT})
endif ()

if (NOT LLVM_CONFIG)
  set(LLVM_CONFIG $ENV{LLVM_CONFIG})
  if (NOT LLVM_CONFIG)
    set(llvm_config_names llvm-config)
    foreach(minor RANGE 9 1)
      list(APPEND llvm_config_names "llvm-config3${minor}" "llvm-config-3.${minor}" "llvm-config-mp-3.${minor}")
    endforeach ()
    find_program(LLVM_CONFIG NAMES ${llvm_config_names})
  endif ()
endif ()

if (LLVM_CONFIG)
  message(STATUS "llvm-config found at: ${LLVM_CONFIG}")
else ()
  message(FATAL_ERROR "Could NOT find llvm-config executable.")
endif ()

if (NOT EXISTS ${CLANG_INCLUDEDIR})
  execute_process(COMMAND ${LLVM_CONFIG} --includedir OUTPUT_VARIABLE CLANG_INCLUDEDIR OUTPUT_STRIP_TRAILING_WHITESPACE)
  if (NOT EXISTS ${CLANG_INCLUDEDIR})
    message(FATAL_ERROR "Could NOT find clang includedir. You can fix this by setting CLANG_INCLUDEDIR in your shell or as a cmake variable.")
  endif ()
endif ()

if (NOT EXISTS ${CLANG_LIBDIR})
  execute_process(COMMAND ${LLVM_CONFIG} --libdir OUTPUT_VARIABLE CLANG_LIBDIR OUTPUT_STRIP_TRAILING_WHITESPACE)
  if (NOT EXISTS ${CLANG_LIBDIR})
    message(FATAL_ERROR "Could NOT find clang libdir. You can fix this by setting CLANG_LIBDIR in your shell or as a cmake variable.")
  endif ()
endif ()

if (NOT CLANG_LIBS)
  find_library(CLANG_LIB_HACK_CMAKECACHE_DOT_TEXT_BULLSHIT NAMES clang libclang ${CLANG_ROOT}/lib ${CLANG_LIBDIR} NO_DEFAULT_PATH)
  if (NOT EXISTS ${CLANG_CLANG_LIB_HACK_CMAKECACHE_DOT_TEXT_BULLSHIT})
    find_library(CLANG_LIBS NAMES clang libclang)
    if (NOT EXISTS ${CLANG_LIBS})
      if (MSVC)
        set (CLANG_LIBS "${CLANG_LIBDIR}/libclang.lib")
      else()
        set (CLANG_LIBS "-L${CLANG_LIBDIR}" "-lclang" "-Wl,-rpath,${CLANG_LIBDIR}")
      endif()
    endif ()
  else ()
    set(CLANG_LIBS "${CLANG_LIB_HACK_CMAKECACHE_DOT_TEXT_BULLSHIT}")
  endif ()
endif ()

execute_process(COMMAND ${LLVM_CONFIG} --version OUTPUT_VARIABLE CLANG_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE)
message("-- Using Clang ${CLANG_VERSION} from ${CLANG_LIBDIR} with LIBS ${CLANG_LIBS} and CXXFLAGS ${CLANG_CXXFLAGS}")

  • cmakeList.txt:
cmake_minimum_required(VERSION 2.8)
set(CMAKE_VERBOSE_MAKEFILE ON)
project(untitled2)

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}")
find_package(LibClang REQUIRED)
include_directories(${CLANG_INCLUDEDIR})
add_executable(${PROJECT_NAME} main.cpp modela.hpp modela.cpp)

target_link_libraries(${PROJECT_NAME} ${CLANG_LIBS})

  • main.cpp: 
#include 
#include 
#include 

using namespace std;

ostream& operator<<(ostream& stream, const CXString& str)
{
    stream << clang_getCString(str);
    clang_disposeString(str);
    return stream;
}

typedef struct{
    CXFile file;
    CXTranslationUnit unit;
}VisitData;

CXChildVisitResult printVisitChildren(CXCursor current, CXCursor parent, CXClientData client_data)
{
    auto iData = (VisitData*)(client_data);
    CXFile visitFile;
    unsigned int line;
    unsigned int col;
    unsigned int offset;
    clang_getSpellingLocation(clang_getCursorLocation(current), &visitFile, &line, &col, &offset);

    auto srcCursor = clang_getCursor(iData->unit, clang_getCursorLocation(current));
    CXFile srcFile;
    unsigned int srcLine;
    unsigned int srcCol;
    unsigned int srcOffset;
    clang_getSpellingLocation(clang_getCursorLocation(srcCursor), &srcFile, &srcLine, &srcCol, &srcOffset);

    std::set filterSet;
    filterSet.insert(CXCursorKind::CXCursor_StructDecl);
    filterSet.insert(CXCursorKind::CXCursor_UnionDecl);
    filterSet.insert(CXCursorKind::CXCursor_ClassDecl);
    filterSet.insert(CXCursorKind::CXCursor_EnumDecl);
    filterSet.insert(CXCursorKind::CXCursor_FieldDecl);
    filterSet.insert(CXCursorKind::CXCursor_EnumConstantDecl);
    filterSet.insert(CXCursorKind::CXCursor_FunctionDecl);
    filterSet.insert(CXCursorKind::CXCursor_VarDecl);
    filterSet.insert(CXCursorKind::CXCursor_ParmDecl);
    filterSet.insert(CXCursorKind::CXCursor_TypedefDecl);
    filterSet.insert(CXCursorKind::CXCursor_CXXMethod);
    filterSet.insert(CXCursorKind::CXCursor_Constructor);
    filterSet.insert(CXCursorKind::CXCursor_Destructor);

    if(filterSet.end() != filterSet.find(clang_getCursorKind(current))) {
        std::cout << "SourceFile: " << clang_getFileName(iData->file) << "\n"
                  << "    range.begin:" << clang_getCursorExtent(srcCursor).begin_int_data << "\n"
                  << "    range.end:" << clang_getCursorExtent(srcCursor).begin_int_data << "\n"
                  << "    SourceCursor: " << clang_getCursorSpelling(srcCursor) << "\n"
                  << "    Kind: " << clang_getCursorKindSpelling(clang_getCursorKind(srcCursor)) << "\n"
                  << "    Type: " << clang_getTypeSpelling(clang_getCursorType(srcCursor)) << "\n"
                  << "    FileName: " << clang_getFileName(srcFile) << "\n"
                  << "    Line: " << srcLine << "\n"
                  << "    colunm: " << srcCol << "\n"
                  << "    offset: " << srcOffset << "\n"
                  << "Location: \n"
                  << "    Cursor: " << clang_getCursorSpelling(current) << "\n"
                  << "    Kind: " << clang_getCursorKindSpelling(clang_getCursorKind(current)) << "\n"
                  << "    Type: " << clang_getTypeSpelling(clang_getCursorType(current)) << "\n"
                  << "    FileName: " << clang_getFileName(visitFile) << "\n"
                  << "    Line: " << line << "\n"
                  << "    colunm: " << col << "\n"
                  << "    offset: " << offset << "\n"
                  << std::endl;
    }
    return CXChildVisit_Recurse;
};

#include "modela.hpp"

int main()
{
    Test2 test2;
    const char *loadFile = "/home/funning/workspace/workspace/recode/gg/TestApp/modela.cpp";
    CXIndex index = clang_createIndex(0, 0);
    CXTranslationUnit unit = clang_parseTranslationUnit(
                index,
                loadFile, nullptr, 0,
                nullptr, 0,
                CXTranslationUnit_None);
    if (unit == nullptr) {
        cerr << "Unable to parse translation unit. Quitting." << endl;
        exit(-1);
    }

    VisitData data;
    data.file = clang_getFile(unit, loadFile);
    data.unit = unit;
    clang_visitChildren(clang_getTranslationUnitCursor(unit), printVisitChildren, &data);
    clang_disposeTranslationUnit(unit);
    clang_disposeIndex(index);
}

注:main函数中路径需要替换成自己的源码文件路径。 

  • modela.hpp:
#ifndef MODELA_H
#define MODELA_H

#include 

union unionTest
{
    int a;
    char b;
};

enum {
    One,
    Two
};

class Test
{
    char Pri_M_T1 = 'c';
public:
    Test(){}
    ~Test(){}
    virtual void virtualFoo();
    void foo();
    inline void inlineFoo(){}
};

class Test2 : public Test
{
    char PM_M_T2;
public:
    Test2(){}
};

void foo();
#endif MODELA_H
  •  modela.cpp:
#include "modela.hpp"

void Test::virtualFoo(){}

void Test::foo(){}

void foo()
{
    std::cout << __FUNCTION__ <
  • 效果如下: 
SourceFile: /home/funning/workspace/workspace/recode/gg/TestApp/modela.cpp
    range.begin:1830468
    range.end:1830468
    SourceCursor: __sb
    Kind: VarDecl
    Type: __streambuf_type *
    FileName: /../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/istream.tcc
    Line: 1033
    colunm: 25
    offset: 28342
Location: 
    Cursor: __sb
    Kind: VarDecl
    Type: __streambuf_type *
    FileName: /../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/istream.tcc
    Line: 1033
    colunm: 25
    offset: 28342

你可能感兴趣的:(LLVM,c++,clang)