[cfe-dev] Missing Availability Information for Enums

Richard Smith richard at metafoo.co.uk
Mon Mar 18 18:52:43 PDT 2013


On Mon, Mar 18, 2013 at 6:18 PM, Jordan Rose <jordan_rose at apple.com> wrote:

>
> On Mar 18, 2013, at 9:15 , Sebastian Hagedorn <hagi.dd at web.de> wrote:
>
> On 15/03/2013, at 17:11 , Jordan Rose <jordan_rose at apple.com> wrote:
>
>
> On Mar 15, 2013, at 7:27 , Sebastian Hagedorn <hagi.dd at web.de> wrote:
>
> I'm currently working on a Clang modification that analyses the (iOS SDK)
> version in which certain symbols were introduced. Most of it is based on
> code that looks similar to this:
>
> decl->getAttr<AvailabilityAttr>()->getIntroduced();
>
> So far, this works fine for ObjC methods, properties, classes, and C
> functions. One missing piece are enumerations, but I've found that they
> seem to lack availability information alltogether. Let's pick an example,
> I'm trying to use the PKPassKitErrorCode enum that was introduced in iOS
> 6. The framework header declares the following:
>
> typedef NS_ENUM(NSInteger, PKPassKitErrorCode) {
>     PKUnknownError = -1,
>     PKInvalidDataError = 1,
>     PKUnsupportedVersionError,
>     PKInvalidSignature,
> } NS_ENUM_AVAILABLE_IOS(6_0);
>
> Obviously, availability information is provided using the usual macros.
> This is what the preprocessor generates:
>
> typedef enum PKPassKitErrorCode : NSInteger PKPassKitErrorCode; enum
> PKPassKitErrorCode : NSInteger {
>     PKUnknownError = -1,
>     PKInvalidDataError = 1,
>     PKUnsupportedVersionError,
>     PKInvalidSignature,
> } __attribute__((availability(ios,introduced=6.0)));
>
> Still looks ok to me, all the information I'm looking for is included.
> However, when I try to get the availability information during the
> compilation process (I'm modifying Sema::DiagnoseUseOfDecl() in
> SemaExpr.cpp), there is none – getAttr<AvailabilityAttr>() returns NULL
> for EnumConstantDecls.
>
> I have not started examining the parsing of the declaration, but wanted to
> ask first whether there's an obvious reason why the information is missing,
> or there's an obvious mistake/misassumption I'm making?
>
>
> The attribute here isn't *on* the EnumConstantDecls; it's on the EnumDecl
> as a whole. You'll also have to be careful about redeclarations; in this
> case I would guess that the first EnumDecl (inside the typedef) doesn't
> have the attribute, but the second one (where the enumerators are actually
> defined) does.
>
> Jordan
>
>
> Thanks for your response!
>
> Re:EnumConstantDecl vs. EnumDecl... my bad. I actually tested both though,
> and neither the constants nor the declaration have availability information.
>
> Re:Redeclarations: How is this handled in Clang? After looking at the
> EnumDecl class and the TagDecl class specifically, I assumed Clang keeps
> all the (re)declarations it finds and makes them accessible via iterators.
> So I tried to acces the most recent declaration (which should be the one
> with the constants defined), but also go through all previous declarations
> and always test whether there's an availability attribute. Looks like
> this...
>
> EnumDecl *enumD = dyn_cast_or_null<EnumDecl>(decl);
> bool hit = false;
> if (enumD) {
>     EnumDecl *prev = enumD->getMostRecentDecl();
>     while (prev) {
>
>       if (prev->getAttr<AvailabilityAttr>()) {
>         hit = true;
>       }
>
>       prev = prev->getPreviousDecl();
>     }
> }
>
> Unfortunately, prev->getPreviousDecl() always returns NULL, so the while
> loop executes only once. And it does not find availability information for
> the most recent declaration.
>
> Is there another way to check all (re)declarations?
>
>
> Hm, that looks correct to me. It does seem strange to me that the
> forward-declared enum does not get its own declaration, but even then I'm
> not sure it would matter.
>

When built in C++11 mode, we get this, which looks much more reasonable:

TranslationUnitDecl 0x5e9b0d0 <<invalid sloc>>
|-TypedefDecl 0x5e9b610 <<invalid sloc>> __int128_t '__int128'
|-TypedefDecl 0x5e9b670 <<invalid sloc>> __uint128_t 'unsigned __int128'
|-TypedefDecl 0x5e9ba30 <<invalid sloc>> __builtin_va_list '__va_list_tag
[1]'
|-TypedefDecl 0x5e9ba90 <tmp.c:1:1, col:14> NSInteger 'long'
|-*EnumDecl 0x5e9bb10 <line:2:9, col:14> PKPassKitErrorCode
'NSInteger':'long'*
|-TypedefDecl 0x5e9bc10 <col:1, col:45> PKPassKitErrorCode 'enum
PKPassKitErrorCode':'enum PKPassKitErrorCode'
`-*EnumDecl 0x5e9bca0 prev 0x5e9bb10 <col:65, line:7:1> PKPassKitErrorCode
'NSInteger':'long'*
  |-*AvailabilityAttr 0x5ecea50 <col:18, col:49> ios 6.0 0 0 ""*
  |-EnumConstantDecl 0x5e9bd80 <line:3:5, col:23> PKUnknownError 'enum
PKPassKitErrorCode'
  | `-ImplicitCastExpr 0x5e9bd68 <col:22, col:23> 'NSInteger':'long'
<IntegralCast>
  |   `-UnaryOperator 0x5e9bd48 <col:22, col:23> 'int' prefix '-'
  |     `-IntegerLiteral 0x5e9bd28 <col:23> 'int' 1
  |-EnumConstantDecl 0x5ece960 <line:4:5, col:26> PKInvalidDataError 'enum
PKPassKitErrorCode'
  | `-ImplicitCastExpr 0x5ece940 <col:26> 'NSInteger':'long' <IntegralCast>
  |   `-IntegerLiteral 0x5e9bdd0 <col:26> 'int' 1
  |-EnumConstantDecl 0x5ece9b0 <line:5:5> PKUnsupportedVersionError 'enum
PKPassKitErrorCode'
  `-EnumConstantDecl 0x5ecea00 <line:6:5> PKInvalidSignature 'enum
PKPassKitErrorCode'

Here's what Clang's internal -ast-dump option prints out for this code:
>
> typedef long NSInteger;
> typedef enum PKPassKitErrorCode : NSInteger PKPassKitErrorCode; enum
> PKPassKitErrorCode : NSInteger {
>     PKUnknownError = -1,
>     PKInvalidDataError = 1,
>     PKUnsupportedVersionError,
>     PKInvalidSignature,
> } __attribute__((availability(ios,introduced=6.0)));
>
>
> TranslationUnitDecl 0x1020232d0 <<invalid sloc>>
> |-TypedefDecl 0x1020237b0 <<invalid sloc>> __int128_t '__int128'
> |-TypedefDecl 0x102023810 <<invalid sloc>> __uint128_t 'unsigned __int128'
> |-TypedefDecl 0x1020238a0 <<invalid sloc>> SEL 'SEL *'
> |-TypedefDecl 0x102023970 <<invalid sloc>> id 'id'
> |-TypedefDecl 0x102023a40 <<invalid sloc>> Class 'Class *'
> |-ObjCInterfaceDecl 0x102023a90 <<invalid sloc>> Protocol
> |-TypedefDecl 0x102023e30 <<invalid sloc>> __builtin_va_list
> '__va_list_tag [1]'
> |-TypedefDecl 0x102023e90 <<stdin>:1:1, col:14> NSInteger 'long'
> |-TypedefDecl 0x102058630 <line:2:1, col:45> PKPassKitErrorCode 'enum
> PKPassKitErrorCode':'enum PKPassKitErrorCode'
> `-EnumDecl 0x1020586a0 <col:65, line:7:1> PKPassKitErrorCode
> 'NSInteger':'long'
>   |-*AvailabilityAttr 0x102058900 <col:18, col:49> ios 6.0 0 0 ""*
>   |-EnumConstantDecl 0x102058780 <line:3:5, col:23> PKUnknownError
> 'NSInteger':'long'
>   | `-ImplicitCastExpr 0x102058768 <col:22, col:23> 'NSInteger':'long'
> <IntegralCast>
>   |   `-UnaryOperator 0x102058748 <col:22, col:23> 'int' prefix '-'
>   |     `-IntegerLiteral 0x102058728 <col:23> 'int' 1
>   |-EnumConstantDecl 0x102058810 <line:4:5, col:26> PKInvalidDataError
> 'NSInteger':'long'
>   | `-ImplicitCastExpr 0x1020587f0 <col:26> 'NSInteger':'long'
> <IntegralCast>
>   |   `-IntegerLiteral 0x1020587d0 <col:26> 'int' 1
>   |-EnumConstantDecl 0x102058860 <line:5:5> PKUnsupportedVersionError
> 'NSInteger':'long'
>   `-EnumConstantDecl 0x1020588b0 <line:6:5> PKInvalidSignature
> 'NSInteger':'long'
>
> So maybe there's something else going on here, because the attribute is
> clearly there. You'll have to provide a more complete test case, and
> perhaps your modification, to see what's going on here.
>
> Jordan
>
>
> _______________________________________________
> cfe-dev mailing list
> cfe-dev at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20130318/16dbef43/attachment.html>


More information about the cfe-dev mailing list