/// Classify the given Clang enumeration to describe how to import it. void EnumInfo::classifyEnum(const clang::EnumDecl *decl, clang::Preprocessor &pp) { // Anonymous enumerations simply get mapped to constants of the // underlying type of the enum, because there is no way to conjure up a // name for the Swift type. if (!decl->hasNameForLinkage()) { kind = EnumKind::Constants; return; } // First, check for attributes that denote the classification if (auto domainAttr = decl->getAttr<clang::NSErrorDomainAttr>()) { kind = EnumKind::Enum; attribute = domainAttr; return; } // Was the enum declared using *_ENUM or *_OPTIONS? // FIXME: Use Clang attributes instead of grovelling the macro expansion loc. auto loc = decl->getLocStart(); if (loc.isMacroID()) { StringRef MacroName = pp.getImmediateMacroName(loc); if (MacroName == "CF_ENUM" || MacroName == "__CF_NAMED_ENUM" || MacroName == "OBJC_ENUM" || MacroName == "SWIFT_ENUM" || MacroName == "SWIFT_ENUM_NAMED") { kind = EnumKind::Enum; return; } if (MacroName == "CF_OPTIONS" || MacroName == "OBJC_OPTIONS" || MacroName == "SWIFT_OPTIONS") { kind = EnumKind::Options; return; } } // Hardcode a particular annoying case in the OS X headers. if (decl->getName() == "DYLD_BOOL") { kind = EnumKind::Enum; return; } // Fall back to the 'Unknown' path. kind = EnumKind::Unknown; }
/// Classify the given Clang enumeration to describe how to import it. void EnumInfo::classifyEnum(ASTContext &ctx, const clang::EnumDecl *decl, clang::Preprocessor &pp) { assert(decl); clang::PrettyStackTraceDecl trace(decl, clang::SourceLocation(), pp.getSourceManager(), "classifying"); assert(decl->isThisDeclarationADefinition()); // Anonymous enumerations simply get mapped to constants of the // underlying type of the enum, because there is no way to conjure up a // name for the Swift type. if (!decl->hasNameForLinkage()) { kind = EnumKind::Constants; return; } // First, check for attributes that denote the classification if (auto domainAttr = decl->getAttr<clang::NSErrorDomainAttr>()) { kind = EnumKind::Enum; nsErrorDomain = ctx.AllocateCopy(domainAttr->getErrorDomain()->getName()); return; } if (decl->hasAttr<clang::FlagEnumAttr>()) { kind = EnumKind::Options; return; } if (decl->hasAttr<clang::EnumExtensibilityAttr>()) { // FIXME: Distinguish between open and closed enums. kind = EnumKind::Enum; return; } // If API notes have /removed/ a FlagEnum or EnumExtensibility attribute, // then we don't need to check the macros. for (auto *attr : decl->specific_attrs<clang::SwiftVersionedAttr>()) { if (!attr->getVersion().empty()) continue; if (isa<clang::FlagEnumAttr>(attr->getAttrToAdd()) || isa<clang::EnumExtensibilityAttr>(attr->getAttrToAdd())) { kind = EnumKind::Unknown; return; } } // Was the enum declared using *_ENUM or *_OPTIONS? // FIXME: Stop using these once flag_enum and enum_extensibility // have been adopted everywhere, or at least relegate them to Swift 3 mode // only. auto loc = decl->getLocStart(); if (loc.isMacroID()) { StringRef MacroName = pp.getImmediateMacroName(loc); if (MacroName == "CF_ENUM" || MacroName == "__CF_NAMED_ENUM" || MacroName == "OBJC_ENUM" || MacroName == "SWIFT_ENUM" || MacroName == "SWIFT_ENUM_NAMED") { kind = EnumKind::Enum; return; } if (MacroName == "CF_OPTIONS" || MacroName == "OBJC_OPTIONS" || MacroName == "SWIFT_OPTIONS") { kind = EnumKind::Options; return; } } // Hardcode a particular annoying case in the OS X headers. if (decl->getName() == "DYLD_BOOL") { kind = EnumKind::Enum; return; } // Fall back to the 'Unknown' path. kind = EnumKind::Unknown; }