[cfe-dev] [libClang] Determining whether enum is enum class

Sam Vanheer via cfe-dev cfe-dev at lists.llvm.org
Thu Jul 6 03:05:47 PDT 2017


I need to determine whether an enum is an enum class.

I found this answer: 
https://stackoverflow.com/questions/26168121/how-do-you-detect-the-difference-between-an-enum-and-a-scoped-enum-using-libclan

This isn't a suitable solution for code that exclusively uses the 
libClang API.


I have come up with a solution that relies on parsing the source code 
surrounding the declaration:

bool IsEnumEnumClass( const CXCursor& cursor )
{
     auto TU = clang_getTranslationUnit( cursor );

     CXToken* pTokens = nullptr;
     unsigned int uiNumTokens = 0;

     clang_tokenize( TU, clang_getCursorExtent( cursor ), &pTokens, 
&uiNumTokens );

     bool bEncounteredEnumKeyword = false;

     bool bIsStronglyScoped = false;

     //Check the declaration until we find an "enum" keyword. If it's 
followed by "class", it's strongly scoped.
     //Possible input: typedef enum class {} Foo; (typedef is apparently 
ignored, but can't hurt to account for it)
     for( decltype( uiNumTokens ) uiToken = 0; uiToken < uiNumTokens; 
++uiToken )
     {
         auto spelling = clang::ToStdString( clang_getTokenSpelling( TU, 
pTokens[ uiToken ] ) );

         if( spelling == "enum" )
         {
             bEncounteredEnumKeyword = true;
         }
         else if( bEncounteredEnumKeyword )
         {
             if( spelling == "class" )
             {
                 bIsStronglyScoped = true;
             }

             //No "class" keyword encountered, so it's a weakly scoped enum.
             break;
         }
     }

     clang_disposeTokens( TU, pTokens, uiNumTokens );

     return bIsStronglyScoped;
}


clang::ToStdString converts a CXString to std::string.


This solution works, but isn't very pretty and may not work properly in 
all cases.

I suppose a new function int clang_isScopedEnum( CXCursor C ) would be 
helpful here, implemented as:

int clang_Cursor_isScopedEnum( CXCursor C )
{
     if( clang_getCursorKind( C ) != CXCursor_EnumDecl )
         return 0;

     if( const EnumDecl *TD = dyn_cast_or_null<EnumDecl>( getCursorDecl( 
C ) ) )
     {
         return TD->isScoped();
     }

     return 0;
}

I have no experience implementing new features in libClang, and i'd 
rather not break anything. Can anyone assist with such an 
implementation, if it is acceptable?


More information about the cfe-dev mailing list