JKSH
JKSH

Reputation: 2718

How do I get an enum element's numerical value using libclang?

Suppose I have an enum definition, e.g.:

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

I would like to programmatically generate a map from any given enum definition, where the key is the enum element's name, and the value is the enum element's numerical value (e.g. myMap["TwoAgain"] == 2)

So far, I know how to traverse the source file using clang_visitChildren(), and extract individual tokens using clang_tokenize(). Recursing through the AST, I get cursors/tokens in this order:

  1. "MyEnum" (CXType_Enum)
    • "First" (CXToken_Identifier)
    • "=" (CXToken_Punctuation)
    • "1" (CXToken_Literal)
  2. "unsigned int" (CXType_UInt)
    • "1" (CXToken_Literal)
  3. "MyEnum" (CXType_Enum)
    • "Second" (CXToken_Identifier)
  4. "MyEnum" (CXType_Enum)
    • "Third" (CXToken_Identifier)
  5. "MyEnum" (CXType_Enum)
    • "TwoAgain" (CXToken_Identifier)
    • "=" (CXToken_Punctuation)
    • "Second" (CXToken_Identifier)
  6. "unsigned int" (CXType_UInt)
    • "Second" (CXToken_Identifier)

I guess I could write an algorithm that uses this information to calculate every value. However, I was wondering if there's a simpler way? Can I get the numerical values directly from the libclang API?

Upvotes: 8

Views: 2632

Answers (3)

sunil
sunil

Reputation: 701

You can use following way in get name and value for your map. i am using 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;
      }

Upvotes: 0

Matt Stevens
Matt Stevens

Reputation: 13343

libclang exposes this information through clang_getEnumConstantDeclValue and clang_getEnumConstantDeclUnsignedValue. A map like you describe can be built by visiting the children of a 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;
}

Upvotes: 9

TartanLlama
TartanLlama

Reputation: 65750

As id256 said, I don't think you can do this with libclang. However, Clang's libtooling and plugin interface allow you to access the AST and operate on that directly. For enums, you'll want to look at the EnumDecl class, which allows you to iterate over the inner decls. Then it's just a case of building up a map like:

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

Upvotes: 1

Related Questions