Как получить числовое значение элемента enum с помощью libclang?

Предположим, у меня есть определение enum, например:

// myenum.h
enum MyEnum {
    First = 1,
    Second,
    Third,
    TwoAgain = Second
};

Я хотел бы программно сгенерировать карту из любого заданного определения перечисления, где ключ - это имя элемента перечисления, а значение - числовое значение элемента перечисления (например, myMap["TwoAgain"] == 2)

До сих пор я знаю, как пройти исходный файл, используя clang_visitChildren()и извлекать отдельные токены, используя clang_tokenize(), Повторяя через AST, я получаю курсоры / токены в следующем порядке:

  1. "MyEnum" (CXType_Enum)
    • "Первый" (CXToken_Identifier)
    • "=" (CXToken_Punctuation)
    • "1" (CXToken_Literal)
  2. "unsigned int" (CXType_UInt)
    • "1" (CXToken_Literal)
  3. "MyEnum" (CXType_Enum)
    • "Второй" (CXToken_Identifier)
  4. "MyEnum" (CXType_Enum)
    • "Третий" (CXToken_Identifier)
  5. "MyEnum" (CXType_Enum)
    • "TwoAgain" (CXToken_Identifier)
    • "=" (CXToken_Punctuation)
    • "Второй" (CXToken_Identifier)
  6. "unsigned int" (CXType_UInt)
    • "Второй" (CXToken_Identifier)

Я думаю, я мог бы написать алгоритм, который использует эту информацию для расчета каждого значения. Однако мне было интересно, есть ли более простой способ? Могу ли я получить числовые значения непосредственно из API libclang?

2 ответа

Решение

libclang раскрывает эту информацию через clang_getEnumConstantDeclValue а также clang_getEnumConstantDeclUnsignedValue, Карту, как вы описываете, можно построить, посетив детей CXCursor_EnumDecl:

static enum CXChildVisitResult VisitCursor(CXCursor cursor, CXCursor parent, CXClientData client_data) {
    if (cursor.kind == CXCursor_EnumConstantDecl) {
        CXString spelling = clang_getCursorSpelling(cursor);
        myMap[clang_getCString(spelling)] = clang_getEnumConstantDeclValue(cursor);
        clang_disposeString(spelling);
    }

    return CXChildVisit_Continue;
}

Как сказал id256, я не думаю, что вы можете сделать это с libclang, Тем не менее, Clang's libtooling и интерфейс плагина позволит вам получить доступ к AST и работать с ним напрямую. Для перечислений, вы хотите посмотреть на EnumDecl класс, который позволяет перебирать внутренние decls. Тогда это всего лишь случай построения карты, например:

for (auto declIterator = myEnumDecl.decls_begin();
     declIterator != myEnumDecl.decls_end();
     ++declIterator)
{
    myMap[declIterator->getNameAsString()] = declIterator->getInitVal;
}

Вы можете использовать следующий способ для получения имени и значения для вашей карты. Я использую clang 8.

bool VisitEnumDecl(EnumDecl *ED)
      {

        for (auto it = ED->enumerator_begin(); it != ED->enumerator_end(); it++)
        {


         std::cout <<it->getNameAsString()<<" "<<it->getInitVal().getSExtValue()<<std::endl;


        }
        return true;
      }
Другие вопросы по тегам