Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding anonymous enums with libclang

Is there a way to detect anonymous enumerations using libclang without relying on the text in the spelling name?

The python bindings to libclang include functionality to detect whether C/C++ structs or unions are anonymous using clang.cindex.Cursor.is_anonymous, which ends up calling clang_Cursor_isAnonymous.

The following sample demonstrates the issue.

import sys
from clang.cindex import *

def nodeinfo(n):
    return (n.kind, n.is_anonymous(), n.spelling, n.type.spelling)

idx = Index.create()

# translation unit parsed correctly
tu = idx.parse(sys.argv[1], ['-std=c++11'])
assert(len(tu.diagnostics) == 0)

for n in tu.cursor.walk_preorder():
    if n.kind == CursorKind.STRUCT_DECL and n.is_anonymous():
        print nodeinfo(n)
    if n.kind == CursorKind.UNION_DECL and n.is_anonymous():
        print nodeinfo(n)
    if n.kind == CursorKind.ENUM_DECL:
        if n.is_anonymous():
            print nodeinfo(n)
        else:
            print 'INCORRECT', nodeinfo(n)

Which when run on sample.cpp

enum
{
    VAL = 1
};

struct s
{
    struct {};
    union
    {
        int x;
        float y;
    };
};

Gives:

INCORRECT (CursorKind.ENUM_DECL, False, '', '(anonymous enum at sample1.cpp:1:1)')
(CursorKind.STRUCT_DECL, True, '', 's::(anonymous struct at sample1.cpp:8:5)')
(CursorKind.UNION_DECL, True, '', 's::(anonymous union at sample1.cpp:9:5)')
like image 904
Andrew Walker Avatar asked Jan 31 '16 11:01

Andrew Walker


People also ask

Can you return an anonymous enum as a member?

You're not *returning an anonymous enum*. an anonymous enum as a member. Replies have been disabled for this discussion. Problems with enums across a dll interface?

How to get the canonical type of an array in Clang?

Retrieve the alignment of the record. Retrieve the type of the elements of the array type. Retrieve the size of the constant array. Return the canonical type for a Type. Clang’s type system explicitly models typedefs and all the ways a specific type can be represented. The canonical type is the underlying type with all the “sugar” removed.

Is it possible to extract a token from the libclang API?

It's not immediately obvious from the libclang API what an appropriate approach to extracting token is. However, it's rare that you would ever need (or want) to drop down to this level - the cursor layer is typically much more useful.


1 Answers

Unfortunately clang_Cursor_isAnonymous works only with structs and unions as you can see from clang source code in tools/libclang/CXType.cpp

unsigned clang_Cursor_isAnonymous(CXCursor C){
  if (!clang_isDeclaration(C.kind))
    return 0;
  const Decl *D = cxcursor::getCursorDecl(C);
  if (const RecordDecl *FD = dyn_cast_or_null<RecordDecl>(D))
    return FD->isAnonymousStructOrUnion();
  return 0;
}

So fallback to the conf.lib.clang_Cursor_isAnonymous in clang.cindex.Cursor.is_anonymous does nothing new as cursor type has been already checked against FIELD_DECL (which is true only for structs and unions)

def is_anonymous(self):
        """
        Check if the record is anonymous.
        """
        if self.kind == CursorKind.FIELD_DECL:
            return self.type.get_declaration().is_anonymous()
        return conf.lib.clang_Cursor_isAnonymous(self)

You can try to extract identifier of current element (n in your sample) and check if it exists or is null

like image 91
Alexander Ushakov Avatar answered Sep 30 '22 16:09

Alexander Ushakov