8

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?

JKSH
  • 2,658
  • 15
  • 33

3 Answers3

9

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;
}
Matt Stevens
  • 13,093
  • 3
  • 33
  • 27
  • That's perfect, @MattStevens; thank you! We really can't get any simpler and cleaner than this. I was trying to work with CXTypeKind, but I had somehow missed CXCursorKind. – JKSH Apr 06 '15 at 15:05
1

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;
}
TartanLlama
  • 63,752
  • 13
  • 157
  • 193
  • Thanks for providing an alternative solution, @TartanLlama! I half-suspected this is out of scope for `libclang`, but it's good to have confirmation and the alternative. – JKSH Mar 26 '15 at 12:50
  • Actually, it is possible through `libclang`. See @MattStevens' answer. – JKSH Apr 06 '15 at 15:06
0

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;
      }
sunil
  • 660
  • 8
  • 20