static RawComment toRawComment(ASTContext &Context, CharSourceRange Range) { if (Range.isInvalid()) return RawComment(); auto &SourceMgr = Context.SourceMgr; unsigned BufferID = SourceMgr.findBufferContainingLoc(Range.getStart()); unsigned Offset = SourceMgr.getLocOffsetInBuffer(Range.getStart(), BufferID); unsigned EndOffset = SourceMgr.getLocOffsetInBuffer(Range.getEnd(), BufferID); LangOptions FakeLangOpts; Lexer L(FakeLangOpts, SourceMgr, BufferID, nullptr, LexerMode::Swift, HashbangMode::Disallowed, CommentRetentionMode::ReturnAsTokens, TriviaRetentionMode::WithoutTrivia, Offset, EndOffset); SmallVector<SingleRawComment, 16> Comments; Token Tok; while (true) { L.lex(Tok); if (Tok.is(tok::eof)) break; assert(Tok.is(tok::comment)); addCommentToList(Comments, SingleRawComment(Tok.getRange(), SourceMgr)); } RawComment Result; Result.Comments = Context.AllocateCopy(Comments); return Result; }
/// Classify the given Clang enumeration to describe how to import it. void EnumInfo::classifyEnum(ASTContext &ctx, 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; nsErrorDomain = ctx.AllocateCopy(domainAttr->getErrorDomain()->getName()); return; } // Was the enum declared using *_ENUM or *_OPTIONS? // FIXME: Use Clang attributes instead of groveling 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; }
static StringRef extractBriefComment(ASTContext &Context, RawComment RC, const Decl *D) { PrettyStackTraceDecl StackTrace("extracting brief comment for", D); if (!D->canHaveComment()) return StringRef(); swift::markup::MarkupContext MC; auto DC = getCascadingDocComment(MC, D); if (!DC.hasValue()) return StringRef(); auto Brief = DC.getValue()->getBrief(); if (!Brief.hasValue()) return StringRef(); SmallString<256> BriefStr(""); llvm::raw_svector_ostream OS(BriefStr); swift::markup::printInlinesUnder(Brief.getValue(), OS); if (OS.str().empty()) return StringRef(); return Context.AllocateCopy(OS.str()); }
/// Determine the prefix to be stripped from the names of the enum constants /// within the given enum. void EnumInfo::determineConstantNamePrefix(ASTContext &ctx, const clang::EnumDecl *decl) { switch (getKind()) { case EnumKind::Enum: case EnumKind::Options: // Enums are mapped to Swift enums, Options to Swift option sets, both // of which attempt prefix-stripping. break; case EnumKind::Constants: case EnumKind::Unknown: // Nothing to do. return; } // If there are no enumers, there is no prefix to compute. auto ec = decl->enumerator_begin(), ecEnd = decl->enumerator_end(); if (ec == ecEnd) return; // Determine whether the given enumerator is non-deprecated and has no // specifically-provided name. auto isNonDeprecatedWithoutCustomName = []( const clang::EnumConstantDecl *elem) -> bool { if (elem->hasAttr<clang::SwiftNameAttr>()) return false; clang::VersionTuple maxVersion{~0U, ~0U, ~0U}; switch (elem->getAvailability(nullptr, maxVersion)) { case clang::AR_Available: case clang::AR_NotYetIntroduced: for (auto attr : elem->attrs()) { if (auto annotate = dyn_cast<clang::AnnotateAttr>(attr)) { if (annotate->getAnnotation() == "swift1_unavailable") return false; } if (auto avail = dyn_cast<clang::AvailabilityAttr>(attr)) { if (avail->getPlatform()->getName() == "swift") return false; } } return true; case clang::AR_Deprecated: case clang::AR_Unavailable: return false; } }; // Move to the first non-deprecated enumerator, or non-swift_name'd // enumerator, if present. auto firstNonDeprecated = std::find_if(ec, ecEnd, isNonDeprecatedWithoutCustomName); bool hasNonDeprecated = (firstNonDeprecated != ecEnd); if (hasNonDeprecated) { ec = firstNonDeprecated; } else { // Advance to the first case without a custom name, deprecated or not. while (ec != ecEnd && (*ec)->hasAttr<clang::SwiftNameAttr>()) ++ec; if (ec == ecEnd) { return; } } // Compute the common prefix. StringRef commonPrefix = (*ec)->getName(); bool followedByNonIdentifier = false; for (++ec; ec != ecEnd; ++ec) { // Skip deprecated or swift_name'd enumerators. const clang::EnumConstantDecl *elem = *ec; if (hasNonDeprecated) { if (!isNonDeprecatedWithoutCustomName(elem)) continue; } else { if (elem->hasAttr<clang::SwiftNameAttr>()) continue; } commonPrefix = getCommonWordPrefix(commonPrefix, elem->getName(), followedByNonIdentifier); if (commonPrefix.empty()) break; } if (!commonPrefix.empty()) { StringRef checkPrefix = commonPrefix; // Account for the 'kConstant' naming convention on enumerators. if (checkPrefix[0] == 'k') { bool canDropK; if (checkPrefix.size() >= 2) canDropK = clang::isUppercase(checkPrefix[1]); else canDropK = !followedByNonIdentifier; if (canDropK) checkPrefix = checkPrefix.drop_front(); } // Don't use importFullName() here, we want to ignore the swift_name // and swift_private attributes. StringRef enumNameStr = decl->getName(); StringRef commonWithEnum = getCommonPluralPrefix(checkPrefix, enumNameStr); size_t delta = commonPrefix.size() - checkPrefix.size(); // Account for the 'EnumName_Constant' convention on enumerators. if (commonWithEnum.size() < checkPrefix.size() && checkPrefix[commonWithEnum.size()] == '_' && !followedByNonIdentifier) { delta += 1; } commonPrefix = commonPrefix.slice(0, commonWithEnum.size() + delta); } constantNamePrefix = ctx.AllocateCopy(commonPrefix); }
static StmtCondition exprToCond(Expr *C, ASTContext &Ctx) { StmtConditionElement Arr[] = { StmtConditionElement(C) }; return Ctx.AllocateCopy(Arr); }
/// 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; }