| //===--- Attr.cpp - Swift Language Attr ASTs ------------------------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements routines relating to declaration attributes. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "swift/AST/Attr.h" |
| #include "swift/AST/ASTContext.h" |
| #include "swift/AST/ASTPrinter.h" |
| #include "swift/AST/Decl.h" |
| #include "swift/AST/Expr.h" |
| #include "swift/AST/GenericEnvironment.h" |
| #include "swift/AST/Module.h" |
| #include "swift/AST/Types.h" |
| #include "swift/Basic/Defer.h" |
| #include "llvm/ADT/SmallString.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include "llvm/Support/ErrorHandling.h" |
| #include "llvm/ADT/StringSwitch.h" |
| using namespace swift; |
| |
| #define DECL_ATTR(_, Id, ...) \ |
| static_assert(IsTriviallyDestructible<Id##Attr>::value, \ |
| "Attrs are BumpPtrAllocated; the destructor is never called"); |
| #include "swift/AST/Attr.def" |
| static_assert(IsTriviallyDestructible<DeclAttributes>::value, |
| "DeclAttributes are BumpPtrAllocated; the d'tor is never called"); |
| static_assert(IsTriviallyDestructible<TypeAttributes>::value, |
| "TypeAttributes are BumpPtrAllocated; the d'tor is never called"); |
| |
| |
| // Only allow allocation of attributes using the allocator in ASTContext. |
| void *AttributeBase::operator new(size_t Bytes, ASTContext &C, |
| unsigned Alignment) { |
| return C.Allocate(Bytes, Alignment); |
| } |
| |
| StringRef swift::getAccessLevelSpelling(AccessLevel value) { |
| switch (value) { |
| case AccessLevel::Private: return "private"; |
| case AccessLevel::FilePrivate: return "fileprivate"; |
| case AccessLevel::Internal: return "internal"; |
| case AccessLevel::Public: return "public"; |
| case AccessLevel::Open: return "open"; |
| } |
| |
| llvm_unreachable("Unhandled AccessLevel in switch."); |
| } |
| |
| /// Given a name like "autoclosure", return the type attribute ID that |
| /// corresponds to it. This returns TAK_Count on failure. |
| /// |
| TypeAttrKind TypeAttributes::getAttrKindFromString(StringRef Str) { |
| return llvm::StringSwitch<TypeAttrKind>(Str) |
| #define TYPE_ATTR(X) .Case(#X, TAK_##X) |
| #include "swift/AST/Attr.def" |
| .Default(TAK_Count); |
| } |
| |
| /// Return the name (like "autoclosure") for an attribute ID. |
| const char *TypeAttributes::getAttrName(TypeAttrKind kind) { |
| switch (kind) { |
| default: llvm_unreachable("Invalid attribute ID"); |
| #define TYPE_ATTR(X) case TAK_##X: return #X; |
| #include "swift/AST/Attr.def" |
| } |
| } |
| |
| |
| |
| /// Given a name like "inline", return the decl attribute ID that corresponds |
| /// to it. Note that this is a many-to-one mapping, and that the identifier |
| /// passed in may only be the first portion of the attribute (e.g. in the case |
| /// of the 'unowned(unsafe)' attribute, the string passed in is 'unowned'. |
| /// |
| /// Also note that this recognizes both attributes like '@inline' (with no @) |
| /// and decl modifiers like 'final'. This returns DAK_Count on failure. |
| /// |
| DeclAttrKind DeclAttribute::getAttrKindFromString(StringRef Str) { |
| return llvm::StringSwitch<DeclAttrKind>(Str) |
| #define DECL_ATTR(X, CLASS, ...) .Case(#X, DAK_##CLASS) |
| #define DECL_ATTR_ALIAS(X, CLASS) .Case(#X, DAK_##CLASS) |
| #include "swift/AST/Attr.def" |
| .Default(DAK_Count); |
| } |
| |
| /// Returns true if this attribute can appear on the specified decl. |
| bool DeclAttribute::canAttributeAppearOnDecl(DeclAttrKind DK, const Decl *D) { |
| return canAttributeAppearOnDeclKind(DK, D->getKind()); |
| } |
| |
| bool DeclAttribute::canAttributeAppearOnDeclKind(DeclAttrKind DAK, DeclKind DK) { |
| auto Options = getOptions(DAK); |
| switch (DK) { |
| #define DECL(Id, Parent) case DeclKind::Id: return (Options & On##Id) != 0; |
| #include "swift/AST/DeclNodes.def" |
| } |
| llvm_unreachable("bad DeclKind"); |
| } |
| |
| bool |
| DeclAttributes::isUnavailableInSwiftVersion( |
| const version::Version &effectiveVersion) const { |
| llvm::VersionTuple vers = effectiveVersion; |
| for (auto attr : *this) { |
| if (auto available = dyn_cast<AvailableAttr>(attr)) { |
| if (available->isInvalid()) |
| continue; |
| |
| if (available->getPlatformAgnosticAvailability() == |
| PlatformAgnosticAvailabilityKind::SwiftVersionSpecific) { |
| if (available->Introduced.hasValue() && |
| available->Introduced.getValue() > vers) |
| return true; |
| if (available->Obsoleted.hasValue() && |
| available->Obsoleted.getValue() <= vers) |
| return true; |
| } |
| } |
| } |
| |
| return false; |
| } |
| |
| const AvailableAttr * |
| DeclAttributes::getPotentiallyUnavailable(const ASTContext &ctx) const { |
| const AvailableAttr *potential = nullptr; |
| const AvailableAttr *conditional = nullptr; |
| |
| for (auto Attr : *this) |
| if (auto AvAttr = dyn_cast<AvailableAttr>(Attr)) { |
| if (AvAttr->isInvalid()) |
| continue; |
| |
| if (!AvAttr->isActivePlatform(ctx) && |
| !AvAttr->isLanguageVersionSpecific() && |
| !AvAttr->isPackageDescriptionVersionSpecific()) |
| continue; |
| |
| // Definitely not available. |
| if (AvAttr->isUnconditionallyUnavailable()) |
| return AvAttr; |
| |
| switch (AvAttr->getVersionAvailability(ctx)) { |
| case AvailableVersionComparison::Available: |
| // Doesn't limit the introduced version. |
| break; |
| |
| case AvailableVersionComparison::PotentiallyUnavailable: |
| // We'll return this if we don't see something that proves it's |
| // not available in this version. |
| potential = AvAttr; |
| break; |
| |
| case AvailableVersionComparison::Unavailable: |
| case AvailableVersionComparison::Obsoleted: |
| conditional = AvAttr; |
| break; |
| } |
| } |
| |
| if (conditional) |
| return conditional; |
| return potential; |
| } |
| |
| const AvailableAttr *DeclAttributes::getUnavailable( |
| const ASTContext &ctx) const { |
| const AvailableAttr *conditional = nullptr; |
| |
| for (auto Attr : *this) |
| if (auto AvAttr = dyn_cast<AvailableAttr>(Attr)) { |
| if (AvAttr->isInvalid()) |
| continue; |
| |
| // If this attribute doesn't apply to the active platform, we're done. |
| if (!AvAttr->isActivePlatform(ctx) && |
| !AvAttr->isLanguageVersionSpecific() && |
| !AvAttr->isPackageDescriptionVersionSpecific()) |
| continue; |
| |
| // Unconditional unavailable. |
| if (AvAttr->isUnconditionallyUnavailable()) |
| return AvAttr; |
| |
| switch (AvAttr->getVersionAvailability(ctx)) { |
| case AvailableVersionComparison::Available: |
| case AvailableVersionComparison::PotentiallyUnavailable: |
| break; |
| |
| case AvailableVersionComparison::Obsoleted: |
| case AvailableVersionComparison::Unavailable: |
| conditional = AvAttr; |
| break; |
| } |
| } |
| return conditional; |
| } |
| |
| const AvailableAttr * |
| DeclAttributes::getDeprecated(const ASTContext &ctx) const { |
| const AvailableAttr *conditional = nullptr; |
| for (auto Attr : *this) { |
| if (auto AvAttr = dyn_cast<AvailableAttr>(Attr)) { |
| if (AvAttr->isInvalid()) |
| continue; |
| |
| if (!AvAttr->isActivePlatform(ctx) && |
| !AvAttr->isLanguageVersionSpecific() && |
| !AvAttr->isPackageDescriptionVersionSpecific()) |
| continue; |
| |
| // Unconditional deprecated. |
| if (AvAttr->isUnconditionallyDeprecated()) |
| return AvAttr; |
| |
| Optional<llvm::VersionTuple> DeprecatedVersion = AvAttr->Deprecated; |
| if (!DeprecatedVersion.hasValue()) |
| continue; |
| |
| llvm::VersionTuple MinVersion = AvAttr->getActiveVersion(ctx); |
| |
| // We treat the declaration as deprecated if it is deprecated on |
| // all deployment targets. |
| // Once availability checking is enabled by default, we should |
| // query the type refinement context hierarchy to determine |
| // whether a declaration is deprecated on all versions |
| // allowed by the context containing the reference. |
| if (DeprecatedVersion.getValue() <= MinVersion) { |
| conditional = AvAttr; |
| } |
| } |
| } |
| return conditional; |
| } |
| |
| void DeclAttributes::dump(const Decl *D) const { |
| StreamPrinter P(llvm::errs()); |
| PrintOptions PO = PrintOptions::printEverything(); |
| print(P, PO, D); |
| } |
| |
| /// Returns true if the attribute can be presented as a short form available |
| /// attribute (e.g., as @available(iOS 8.0, *). The presentation requires an |
| /// introduction version and does not support deprecation, obsoletion, or |
| /// messages. |
| LLVM_READONLY |
| static bool isShortAvailable(const DeclAttribute *DA) { |
| auto *AvailAttr = dyn_cast<AvailableAttr>(DA); |
| if (!AvailAttr) |
| return false; |
| |
| if (!AvailAttr->Introduced.hasValue()) |
| return false; |
| |
| if (AvailAttr->Deprecated.hasValue()) |
| return false; |
| |
| if (AvailAttr->Obsoleted.hasValue()) |
| return false; |
| |
| if (!AvailAttr->Message.empty()) |
| return false; |
| |
| if (!AvailAttr->Rename.empty()) |
| return false; |
| |
| switch (AvailAttr->PlatformAgnostic) { |
| case PlatformAgnosticAvailabilityKind::Deprecated: |
| case PlatformAgnosticAvailabilityKind::Unavailable: |
| case PlatformAgnosticAvailabilityKind::UnavailableInSwift: |
| return false; |
| case PlatformAgnosticAvailabilityKind::None: |
| case PlatformAgnosticAvailabilityKind::SwiftVersionSpecific: |
| case PlatformAgnosticAvailabilityKind::PackageDescriptionVersionSpecific: |
| return true; |
| } |
| |
| return true; |
| } |
| |
| /// Print the short-form @available() attribute for an array of long-form |
| /// AvailableAttrs that can be represented in the short form. |
| /// For example, for: |
| /// @available(OSX, introduced: 10.10) |
| /// @available(iOS, introduced: 8.0) |
| /// this will print: |
| /// @available(OSX 10.10, iOS 8.0, *) |
| static void printShortFormAvailable(ArrayRef<const DeclAttribute *> Attrs, |
| ASTPrinter &Printer, |
| const PrintOptions &Options) { |
| assert(!Attrs.empty()); |
| |
| Printer << "@available("; |
| auto FirstAvail = cast<AvailableAttr>(Attrs.front()); |
| if (Attrs.size() == 1 && |
| FirstAvail->getPlatformAgnosticAvailability() != |
| PlatformAgnosticAvailabilityKind::None) { |
| assert(FirstAvail->Introduced.hasValue()); |
| if (FirstAvail->isLanguageVersionSpecific()) { |
| Printer << "swift "; |
| } else { |
| assert(FirstAvail->isPackageDescriptionVersionSpecific()); |
| Printer << "_PackageDescription "; |
| } |
| Printer << FirstAvail->Introduced.getValue().getAsString() |
| << ")"; |
| } else { |
| for (auto *DA : Attrs) { |
| auto *AvailAttr = cast<AvailableAttr>(DA); |
| assert(AvailAttr->Introduced.hasValue()); |
| Printer << platformString(AvailAttr->Platform) << " " |
| << AvailAttr->Introduced.getValue().getAsString() << ", "; |
| } |
| Printer << "*)"; |
| } |
| Printer.printNewline(); |
| } |
| |
| void DeclAttributes::print(ASTPrinter &Printer, const PrintOptions &Options, |
| const Decl *D) const { |
| if (!DeclAttrs) |
| return; |
| |
| using AttributeVector = SmallVector<const DeclAttribute *, 8>; |
| AttributeVector orderedAttributes(begin(), end()); |
| std::reverse(orderedAttributes.begin(), orderedAttributes.end()); |
| |
| // Process attributes in passes. |
| AttributeVector shortAvailableAttributes; |
| const DeclAttribute *swiftVersionAvailableAttribute = nullptr; |
| const DeclAttribute *packageDescriptionVersionAvailableAttribute = nullptr; |
| AttributeVector longAttributes; |
| AttributeVector attributes; |
| AttributeVector modifiers; |
| |
| for (auto DA : orderedAttributes) { |
| if (!Options.PrintImplicitAttrs && DA->isImplicit()) |
| continue; |
| if (!Options.PrintUserInaccessibleAttrs && |
| DeclAttribute::isUserInaccessible(DA->getKind())) |
| continue; |
| if (Options.excludeAttrKind(DA->getKind())) |
| continue; |
| |
| // Be careful not to coalesce `@available(swift 5)` with other short |
| // `available' attributes. |
| if (auto *availableAttr = dyn_cast<AvailableAttr>(DA)) { |
| if (availableAttr->isLanguageVersionSpecific() && |
| isShortAvailable(availableAttr)) { |
| swiftVersionAvailableAttribute = availableAttr; |
| continue; |
| } |
| if (availableAttr->isPackageDescriptionVersionSpecific() && |
| isShortAvailable(availableAttr)) { |
| packageDescriptionVersionAvailableAttribute = availableAttr; |
| continue; |
| } |
| } |
| |
| AttributeVector &which = DA->isDeclModifier() ? modifiers : |
| isShortAvailable(DA) ? shortAvailableAttributes : |
| DA->isLongAttribute() ? longAttributes : |
| attributes; |
| which.push_back(DA); |
| } |
| |
| if (swiftVersionAvailableAttribute) |
| printShortFormAvailable(swiftVersionAvailableAttribute, Printer, Options); |
| if (packageDescriptionVersionAvailableAttribute) |
| printShortFormAvailable(packageDescriptionVersionAvailableAttribute, Printer, Options); |
| if (!shortAvailableAttributes.empty()) |
| printShortFormAvailable(shortAvailableAttributes, Printer, Options); |
| |
| for (auto DA : longAttributes) |
| DA->print(Printer, Options, D); |
| for (auto DA : attributes) |
| DA->print(Printer, Options, D); |
| for (auto DA : modifiers) |
| DA->print(Printer, Options, D); |
| } |
| |
| SourceLoc DeclAttributes::getStartLoc(bool forModifiers) const { |
| if (isEmpty()) |
| return SourceLoc(); |
| |
| const DeclAttribute *lastAttr = nullptr; |
| for (auto attr : *this) { |
| if (attr->getRangeWithAt().Start.isValid() && |
| (!forModifiers || attr->isDeclModifier())) |
| lastAttr = attr; |
| } |
| |
| return lastAttr ? lastAttr->getRangeWithAt().Start : SourceLoc(); |
| } |
| |
| bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options, |
| const Decl *D) const { |
| |
| // Handle any attributes that are not printed at all before we make printer |
| // callbacks. |
| switch (getKind()) { |
| case DAK_ObjC: |
| if (Options.PrintForSIL && isImplicit()) |
| return false; |
| break; |
| case DAK_RawDocComment: |
| case DAK_ObjCBridged: |
| case DAK_SynthesizedProtocol: |
| case DAK_Rethrows: |
| case DAK_Infix: |
| return false; |
| default: |
| break; |
| } |
| |
| // Handle any decl-modifiers. |
| // FIXME: Ideally we would handle decl modifiers as a special kind of |
| // attribute, but for now it's simpler to treat them as a keyword in the |
| // printer. |
| switch (getKind()) { |
| // Handle all of the SIMPLE_DECL_ATTRs. |
| #define SIMPLE_DECL_ATTR(X, CLASS, ...) case DAK_##CLASS: |
| #include "swift/AST/Attr.def" |
| case DAK_Inline: |
| case DAK_AccessControl: |
| case DAK_ReferenceOwnership: |
| case DAK_Effects: |
| case DAK_Optimize: |
| if (DeclAttribute::isDeclModifier(getKind())) { |
| Printer.printKeyword(getAttrName(), Options); |
| } else { |
| Printer.printSimpleAttr(getAttrName(), /*needAt=*/true); |
| } |
| return true; |
| |
| case DAK_SetterAccess: |
| Printer.printKeyword(getAttrName(), Options, "(set)"); |
| return true; |
| |
| default: |
| break; |
| } |
| |
| Printer.callPrintStructurePre(PrintStructureKind::BuiltinAttribute); |
| SWIFT_DEFER { |
| Printer.printStructurePost(PrintStructureKind::BuiltinAttribute); |
| }; |
| |
| switch (getKind()) { |
| case DAK_Semantics: |
| Printer.printAttrName("@_semantics"); |
| Printer << "(\"" << cast<SemanticsAttr>(this)->Value << "\")"; |
| break; |
| |
| case DAK_Alignment: |
| Printer.printAttrName("@_alignment"); |
| Printer << "(" << cast<AlignmentAttr>(this)->getValue() << ")"; |
| break; |
| |
| case DAK_SILGenName: |
| Printer.printAttrName("@_silgen_name"); |
| Printer << "(\"" << cast<SILGenNameAttr>(this)->Name << "\")"; |
| break; |
| |
| case DAK_Available: { |
| Printer.printAttrName("@available"); |
| Printer << "("; |
| auto Attr = cast<AvailableAttr>(this); |
| if (Attr->isLanguageVersionSpecific()) |
| Printer << "swift"; |
| else if (Attr->isPackageDescriptionVersionSpecific()) |
| Printer << "_PackageDescription"; |
| else |
| Printer << Attr->platformString(); |
| |
| if (Attr->isUnconditionallyUnavailable()) |
| Printer << ", unavailable"; |
| else if (Attr->isUnconditionallyDeprecated()) |
| Printer << ", deprecated"; |
| |
| if (Attr->Introduced) |
| Printer << ", introduced: " << Attr->Introduced.getValue().getAsString(); |
| if (Attr->Deprecated) |
| Printer << ", deprecated: " << Attr->Deprecated.getValue().getAsString(); |
| if (Attr->Obsoleted) |
| Printer << ", obsoleted: " << Attr->Obsoleted.getValue().getAsString(); |
| |
| if (!Attr->Rename.empty()) |
| Printer << ", renamed: \"" << Attr->Rename << "\""; |
| |
| // If there's no message, but this is specifically an imported |
| // "unavailable in Swift" attribute, synthesize a message to look good in |
| // the generated interface. |
| if (!Attr->Message.empty()) { |
| Printer << ", message: "; |
| Printer.printEscapedStringLiteral(Attr->Message); |
| } |
| else if (Attr->getPlatformAgnosticAvailability() |
| == PlatformAgnosticAvailabilityKind::UnavailableInSwift) |
| Printer << ", message: \"Not available in Swift\""; |
| |
| Printer << ")"; |
| break; |
| } |
| |
| case DAK_CDecl: |
| Printer << "@_cdecl(\"" << cast<CDeclAttr>(this)->Name << "\")"; |
| break; |
| |
| case DAK_ObjC: { |
| Printer.printAttrName("@objc"); |
| llvm::SmallString<32> scratch; |
| if (auto Name = cast<ObjCAttr>(this)->getName()) { |
| if (!cast<ObjCAttr>(this)->isNameImplicit()) |
| Printer << "(" << Name->getString(scratch) << ")"; |
| } |
| break; |
| } |
| |
| case DAK_PrivateImport: { |
| Printer.printAttrName("@_private(sourceFile: \""); |
| Printer << cast<PrivateImportAttr>(this)->getSourceFile() << "\")"; |
| break; |
| } |
| |
| case DAK_SwiftNativeObjCRuntimeBase: { |
| auto *attr = cast<SwiftNativeObjCRuntimeBaseAttr>(this); |
| Printer.printAttrName("@_swift_native_objc_runtime_base"); |
| Printer << "(" << attr->BaseClassName.str() << ")"; |
| break; |
| } |
| |
| case DAK_Specialize: { |
| Printer << "@" << getAttrName() << "("; |
| auto *attr = cast<SpecializeAttr>(this); |
| auto exported = attr->isExported() ? "true" : "false"; |
| auto kind = attr->isPartialSpecialization() ? "partial" : "full"; |
| |
| Printer << "exported: "<< exported << ", "; |
| Printer << "kind: " << kind << ", "; |
| |
| if (!attr->getRequirements().empty()) { |
| Printer << "where "; |
| } |
| std::function<Type(Type)> GetInterfaceType; |
| auto *FnDecl = dyn_cast_or_null<AbstractFunctionDecl>(D); |
| if (!FnDecl || !FnDecl->getGenericEnvironment()) |
| GetInterfaceType = [](Type Ty) -> Type { return Ty; }; |
| else { |
| // Use GenericEnvironment to produce user-friendly |
| // names instead of something like t_0_0. |
| auto *GenericEnv = FnDecl->getGenericEnvironment(); |
| assert(GenericEnv); |
| GetInterfaceType = [=](Type Ty) -> Type { |
| return GenericEnv->getSugaredType(Ty); |
| }; |
| } |
| interleave(attr->getRequirements(), |
| [&](Requirement req) { |
| auto FirstTy = GetInterfaceType(req.getFirstType()); |
| if (req.getKind() != RequirementKind::Layout) { |
| auto SecondTy = GetInterfaceType(req.getSecondType()); |
| Requirement ReqWithDecls(req.getKind(), FirstTy, SecondTy); |
| ReqWithDecls.print(Printer, Options); |
| } else { |
| Requirement ReqWithDecls(req.getKind(), FirstTy, |
| req.getLayoutConstraint()); |
| ReqWithDecls.print(Printer, Options); |
| } |
| }, |
| [&] { Printer << ", "; }); |
| |
| Printer << ")"; |
| break; |
| } |
| |
| case DAK_Implements: { |
| Printer.printAttrName("@_implements"); |
| Printer << "("; |
| auto *attr = cast<ImplementsAttr>(this); |
| attr->getProtocolType().getType().print(Printer, Options); |
| Printer << ", " << attr->getMemberName() << ")"; |
| break; |
| } |
| |
| case DAK_ObjCRuntimeName: { |
| Printer.printAttrName("@_objcRuntimeName"); |
| Printer << "("; |
| auto *attr = cast<ObjCRuntimeNameAttr>(this); |
| Printer << attr->Name; |
| Printer << ")"; |
| break; |
| } |
| |
| case DAK_ClangImporterSynthesizedType: { |
| Printer.printAttrName("@_clangImporterSynthesizedType"); |
| auto *attr = cast<ClangImporterSynthesizedTypeAttr>(this); |
| Printer << "(originalTypeName: \"" << attr->originalTypeName |
| << "\", manglingForKind: \"" << attr->getManglingName() << "\")"; |
| break; |
| } |
| |
| case DAK_DynamicReplacement: { |
| Printer.printAttrName("@_dynamicReplacement"); |
| Printer << "(for: \""; |
| auto *attr = cast<DynamicReplacementAttr>(this); |
| Printer << attr->getReplacedFunctionName() << "\")"; |
| break; |
| } |
| |
| case DAK_Custom: { |
| Printer.printAttrName("@"); |
| const TypeLoc &typeLoc = cast<CustomAttr>(this)->getTypeLoc(); |
| if (auto type = typeLoc.getType()) |
| type->print(Printer, Options); |
| else |
| typeLoc.getTypeRepr()->print(Printer, Options); |
| break; |
| } |
| |
| case DAK_Count: |
| llvm_unreachable("exceed declaration attribute kinds"); |
| |
| #define SIMPLE_DECL_ATTR(X, CLASS, ...) case DAK_##CLASS: |
| #include "swift/AST/Attr.def" |
| llvm_unreachable("handled above"); |
| |
| default: |
| assert(DeclAttribute::isDeclModifier(getKind()) && |
| "handled above"); |
| } |
| |
| return true; |
| } |
| |
| void DeclAttribute::print(ASTPrinter &Printer, const PrintOptions &Options, |
| const Decl *D) const { |
| |
| if (!printImpl(Printer, Options, D)) |
| return; // Nothing printed. |
| |
| if (isLongAttribute() && Options.PrintLongAttrsOnSeparateLines) |
| Printer.printNewline(); |
| else |
| Printer << " "; |
| } |
| |
| void DeclAttribute::print(llvm::raw_ostream &OS, const Decl *D) const { |
| StreamPrinter P(OS); |
| print(P, PrintOptions(), D); |
| } |
| |
| uint64_t DeclAttribute::getOptions(DeclAttrKind DK) { |
| switch (DK) { |
| case DAK_Count: |
| llvm_unreachable("getOptions needs a valid attribute"); |
| #define DECL_ATTR(_, CLASS, OPTIONS, ...)\ |
| case DAK_##CLASS: return OPTIONS; |
| #include "swift/AST/Attr.def" |
| } |
| llvm_unreachable("bad DeclAttrKind"); |
| } |
| |
| StringRef DeclAttribute::getAttrName() const { |
| switch (getKind()) { |
| case DAK_Count: |
| llvm_unreachable("getAttrName needs a valid attribute"); |
| #define SIMPLE_DECL_ATTR(NAME, CLASS, ...) \ |
| case DAK_##CLASS: \ |
| return #NAME; |
| #include "swift/AST/Attr.def" |
| case DAK_SILGenName: |
| return "_silgen_name"; |
| case DAK_Alignment: |
| return "_alignment"; |
| case DAK_CDecl: |
| return "_cdecl"; |
| case DAK_SwiftNativeObjCRuntimeBase: |
| return "_swift_native_objc_runtime_base"; |
| case DAK_Semantics: |
| return "_semantics"; |
| case DAK_Available: |
| return "availability"; |
| case DAK_ObjC: |
| case DAK_ObjCRuntimeName: |
| return "objc"; |
| case DAK_DynamicReplacement: |
| return "_dynamicReplacement"; |
| case DAK_PrivateImport: |
| return "_private"; |
| case DAK_RestatedObjCConformance: |
| return "_restatedObjCConformance"; |
| case DAK_Inline: { |
| switch (cast<InlineAttr>(this)->getKind()) { |
| case InlineKind::Never: |
| return "inline(never)"; |
| case InlineKind::Always: |
| return "inline(__always)"; |
| } |
| llvm_unreachable("Invalid inline kind"); |
| } |
| case DAK_Optimize: { |
| switch (cast<OptimizeAttr>(this)->getMode()) { |
| case OptimizationMode::NoOptimization: |
| return "_optimize(none)"; |
| case OptimizationMode::ForSpeed: |
| return "_optimize(speed)"; |
| case OptimizationMode::ForSize: |
| return "_optimize(size)"; |
| default: |
| llvm_unreachable("Invalid optimization kind"); |
| } |
| } |
| case DAK_Effects: |
| switch (cast<EffectsAttr>(this)->getKind()) { |
| case EffectsKind::ReadNone: |
| return "_effects(readnone)"; |
| case EffectsKind::ReadOnly: |
| return "_effects(readonly)"; |
| case EffectsKind::ReleaseNone: |
| return "_effects(releasenone)"; |
| case EffectsKind::ReadWrite: |
| return "_effects(readwrite)"; |
| case EffectsKind::Unspecified: |
| return "_effects(unspecified)"; |
| } |
| case DAK_AccessControl: |
| case DAK_SetterAccess: { |
| AccessLevel access = cast<AbstractAccessControlAttr>(this)->getAccess(); |
| return getAccessLevelSpelling(access); |
| } |
| |
| case DAK_ReferenceOwnership: |
| return keywordOf(cast<ReferenceOwnershipAttr>(this)->get()); |
| case DAK_RawDocComment: |
| return "<<raw doc comment>>"; |
| case DAK_ObjCBridged: |
| return "<<ObjC bridged>>"; |
| case DAK_SynthesizedProtocol: |
| return "<<synthesized protocol>>"; |
| case DAK_Specialize: |
| return "_specialize"; |
| case DAK_Implements: |
| return "_implements"; |
| case DAK_ClangImporterSynthesizedType: |
| return "_clangImporterSynthesizedType"; |
| case DAK_Custom: |
| return "<<custom>>"; |
| } |
| llvm_unreachable("bad DeclAttrKind"); |
| } |
| |
| ObjCAttr::ObjCAttr(SourceLoc atLoc, SourceRange baseRange, |
| Optional<ObjCSelector> name, SourceRange parenRange, |
| ArrayRef<SourceLoc> nameLocs) |
| : DeclAttribute(DAK_ObjC, atLoc, baseRange, /*Implicit=*/false), |
| NameData(nullptr) |
| { |
| if (name) { |
| // Store the name. |
| assert(name->getNumSelectorPieces() == nameLocs.size()); |
| NameData = name->getOpaqueValue(); |
| |
| // Store location information. |
| Bits.ObjCAttr.HasTrailingLocationInfo = true; |
| getTrailingLocations()[0] = parenRange.Start; |
| getTrailingLocations()[1] = parenRange.End; |
| std::memcpy(getTrailingLocations().slice(2).data(), nameLocs.data(), |
| nameLocs.size() * sizeof(SourceLoc)); |
| } else { |
| Bits.ObjCAttr.HasTrailingLocationInfo = false; |
| } |
| |
| Bits.ObjCAttr.ImplicitName = false; |
| Bits.ObjCAttr.Swift3Inferred = false; |
| } |
| |
| ObjCAttr *ObjCAttr::create(ASTContext &Ctx, Optional<ObjCSelector> name, |
| bool isNameImplicit) { |
| return new (Ctx) ObjCAttr(name, isNameImplicit); |
| } |
| |
| ObjCAttr *ObjCAttr::createUnnamed(ASTContext &Ctx, SourceLoc AtLoc, |
| SourceLoc ObjCLoc) { |
| return new (Ctx) ObjCAttr(AtLoc, SourceRange(ObjCLoc), None, |
| SourceRange(), { }); |
| } |
| |
| ObjCAttr *ObjCAttr::createUnnamedImplicit(ASTContext &Ctx) { |
| return new (Ctx) ObjCAttr(None, false); |
| } |
| |
| ObjCAttr *ObjCAttr::createNullary(ASTContext &Ctx, SourceLoc AtLoc, |
| SourceLoc ObjCLoc, SourceLoc LParenLoc, |
| SourceLoc NameLoc, Identifier Name, |
| SourceLoc RParenLoc) { |
| void *mem = Ctx.Allocate(totalSizeToAlloc<SourceLoc>(3), alignof(ObjCAttr)); |
| return new (mem) ObjCAttr(AtLoc, SourceRange(ObjCLoc, RParenLoc), |
| ObjCSelector(Ctx, 0, Name), |
| SourceRange(LParenLoc, RParenLoc), |
| NameLoc); |
| } |
| |
| ObjCAttr *ObjCAttr::createNullary(ASTContext &Ctx, Identifier Name, |
| bool isNameImplicit) { |
| return new (Ctx) ObjCAttr(ObjCSelector(Ctx, 0, Name), isNameImplicit); |
| } |
| |
| ObjCAttr *ObjCAttr::createSelector(ASTContext &Ctx, SourceLoc AtLoc, |
| SourceLoc ObjCLoc, SourceLoc LParenLoc, |
| ArrayRef<SourceLoc> NameLocs, |
| ArrayRef<Identifier> Names, |
| SourceLoc RParenLoc) { |
| assert(NameLocs.size() == Names.size()); |
| void *mem = Ctx.Allocate(totalSizeToAlloc<SourceLoc>(NameLocs.size() + 2), |
| alignof(ObjCAttr)); |
| return new (mem) ObjCAttr(AtLoc, SourceRange(ObjCLoc, RParenLoc), |
| ObjCSelector(Ctx, Names.size(), Names), |
| SourceRange(LParenLoc, RParenLoc), |
| NameLocs); |
| } |
| |
| ObjCAttr *ObjCAttr::createSelector(ASTContext &Ctx, |
| ArrayRef<Identifier> Names, |
| bool isNameImplicit) { |
| return new (Ctx) ObjCAttr(ObjCSelector(Ctx, Names.size(), Names), |
| isNameImplicit); |
| } |
| |
| ArrayRef<SourceLoc> ObjCAttr::getNameLocs() const { |
| if (!hasTrailingLocationInfo()) |
| return { }; |
| |
| return getTrailingLocations().slice(2); |
| } |
| |
| SourceLoc ObjCAttr::getLParenLoc() const { |
| if (!hasTrailingLocationInfo()) |
| return SourceLoc(); |
| |
| return getTrailingLocations()[0]; |
| } |
| |
| SourceLoc ObjCAttr::getRParenLoc() const { |
| if (!hasTrailingLocationInfo()) |
| return SourceLoc(); |
| |
| return getTrailingLocations()[1]; |
| } |
| |
| ObjCAttr *ObjCAttr::clone(ASTContext &context) const { |
| auto attr = new (context) ObjCAttr(getName(), isNameImplicit()); |
| attr->setSwift3Inferred(isSwift3Inferred()); |
| return attr; |
| } |
| |
| PrivateImportAttr::PrivateImportAttr(SourceLoc atLoc, SourceRange baseRange, |
| StringRef sourceFile, |
| SourceRange parenRange) |
| : DeclAttribute(DAK_PrivateImport, atLoc, baseRange, /*Implicit=*/false), |
| SourceFile(sourceFile) {} |
| |
| PrivateImportAttr *PrivateImportAttr::create(ASTContext &Ctxt, SourceLoc AtLoc, |
| SourceLoc PrivateLoc, |
| SourceLoc LParenLoc, |
| StringRef sourceFile, |
| SourceLoc RParenLoc) { |
| return new (Ctxt) |
| PrivateImportAttr(AtLoc, SourceRange(PrivateLoc, RParenLoc), sourceFile, |
| SourceRange(LParenLoc, RParenLoc)); |
| } |
| |
| DynamicReplacementAttr::DynamicReplacementAttr(SourceLoc atLoc, |
| SourceRange baseRange, |
| DeclName name, |
| SourceRange parenRange) |
| : DeclAttribute(DAK_DynamicReplacement, atLoc, baseRange, |
| /*Implicit=*/false), |
| ReplacedFunctionName(name), ReplacedFunction(nullptr) { |
| Bits.DynamicReplacementAttr.HasTrailingLocationInfo = true; |
| getTrailingLocations()[0] = parenRange.Start; |
| getTrailingLocations()[1] = parenRange.End; |
| } |
| |
| DynamicReplacementAttr * |
| DynamicReplacementAttr::create(ASTContext &Ctx, SourceLoc AtLoc, |
| SourceLoc DynReplLoc, SourceLoc LParenLoc, |
| DeclName ReplacedFunction, SourceLoc RParenLoc) { |
| void *mem = Ctx.Allocate(totalSizeToAlloc<SourceLoc>(2), |
| alignof(DynamicReplacementAttr)); |
| return new (mem) DynamicReplacementAttr( |
| AtLoc, SourceRange(DynReplLoc, RParenLoc), ReplacedFunction, |
| SourceRange(LParenLoc, RParenLoc)); |
| } |
| |
| DynamicReplacementAttr *DynamicReplacementAttr::create(ASTContext &Ctx, |
| DeclName name) { |
| return new (Ctx) DynamicReplacementAttr(name); |
| } |
| |
| DynamicReplacementAttr * |
| DynamicReplacementAttr::create(ASTContext &Ctx, DeclName name, |
| AbstractFunctionDecl *f) { |
| auto res = new (Ctx) DynamicReplacementAttr(name); |
| res->setReplacedFunction(f); |
| return res; |
| } |
| |
| SourceLoc DynamicReplacementAttr::getLParenLoc() const { |
| return getTrailingLocations()[0]; |
| } |
| |
| SourceLoc DynamicReplacementAttr::getRParenLoc() const { |
| return getTrailingLocations()[1]; |
| } |
| |
| AvailableAttr * |
| AvailableAttr::createPlatformAgnostic(ASTContext &C, |
| StringRef Message, |
| StringRef Rename, |
| PlatformAgnosticAvailabilityKind Kind, |
| llvm::VersionTuple Obsoleted) { |
| assert(Kind != PlatformAgnosticAvailabilityKind::None); |
| llvm::VersionTuple NoVersion; |
| if (Kind == PlatformAgnosticAvailabilityKind::SwiftVersionSpecific) { |
| assert(!Obsoleted.empty()); |
| } |
| return new (C) AvailableAttr( |
| SourceLoc(), SourceRange(), PlatformKind::none, Message, Rename, |
| NoVersion, SourceRange(), |
| NoVersion, SourceRange(), |
| Obsoleted, SourceRange(), |
| Kind, /* isImplicit */ false); |
| } |
| |
| bool AvailableAttr::isActivePlatform(const ASTContext &ctx) const { |
| return isPlatformActive(Platform, ctx.LangOpts); |
| } |
| |
| bool AvailableAttr::isLanguageVersionSpecific() const { |
| if (PlatformAgnostic == |
| PlatformAgnosticAvailabilityKind::SwiftVersionSpecific) |
| { |
| assert(Platform == PlatformKind::none && |
| (Introduced.hasValue() || |
| Deprecated.hasValue() || |
| Obsoleted.hasValue())); |
| return true; |
| } |
| return false; |
| } |
| |
| bool AvailableAttr::isPackageDescriptionVersionSpecific() const { |
| if (PlatformAgnostic == |
| PlatformAgnosticAvailabilityKind::PackageDescriptionVersionSpecific) |
| { |
| assert(Platform == PlatformKind::none && |
| (Introduced.hasValue() || |
| Deprecated.hasValue() || |
| Obsoleted.hasValue())); |
| return true; |
| } |
| return false; |
| } |
| |
| bool AvailableAttr::isUnconditionallyUnavailable() const { |
| switch (PlatformAgnostic) { |
| case PlatformAgnosticAvailabilityKind::None: |
| case PlatformAgnosticAvailabilityKind::Deprecated: |
| case PlatformAgnosticAvailabilityKind::SwiftVersionSpecific: |
| case PlatformAgnosticAvailabilityKind::PackageDescriptionVersionSpecific: |
| return false; |
| |
| case PlatformAgnosticAvailabilityKind::Unavailable: |
| case PlatformAgnosticAvailabilityKind::UnavailableInSwift: |
| return true; |
| } |
| |
| llvm_unreachable("Unhandled PlatformAgnosticAvailabilityKind in switch."); |
| } |
| |
| bool AvailableAttr::isUnconditionallyDeprecated() const { |
| switch (PlatformAgnostic) { |
| case PlatformAgnosticAvailabilityKind::None: |
| case PlatformAgnosticAvailabilityKind::Unavailable: |
| case PlatformAgnosticAvailabilityKind::UnavailableInSwift: |
| case PlatformAgnosticAvailabilityKind::SwiftVersionSpecific: |
| case PlatformAgnosticAvailabilityKind::PackageDescriptionVersionSpecific: |
| return false; |
| |
| case PlatformAgnosticAvailabilityKind::Deprecated: |
| return true; |
| } |
| |
| llvm_unreachable("Unhandled PlatformAgnosticAvailabilityKind in switch."); |
| } |
| |
| llvm::VersionTuple AvailableAttr::getActiveVersion(const ASTContext &ctx) const { |
| if (isLanguageVersionSpecific()) { |
| return ctx.LangOpts.EffectiveLanguageVersion; |
| } else if (isPackageDescriptionVersionSpecific()) { |
| return ctx.LangOpts.PackageDescriptionVersion; |
| } else { |
| return ctx.LangOpts.getMinPlatformVersion(); |
| } |
| } |
| |
| AvailableVersionComparison AvailableAttr::getVersionAvailability( |
| const ASTContext &ctx) const { |
| |
| // Unconditional unavailability. |
| if (isUnconditionallyUnavailable()) |
| return AvailableVersionComparison::Unavailable; |
| |
| llvm::VersionTuple queryVersion = getActiveVersion(ctx); |
| |
| // If this entity was obsoleted before or at the query platform version, |
| // consider it obsolete. |
| if (Obsoleted && *Obsoleted <= queryVersion) |
| return AvailableVersionComparison::Obsoleted; |
| |
| // If this entity was introduced after the query version and we're doing a |
| // platform comparison, true availability can only be determined dynamically; |
| // if we're doing a _language_ version check, the query version is a |
| // static requirement, so we treat "introduced later" as just plain |
| // unavailable. |
| if (Introduced && *Introduced > queryVersion) { |
| if (isLanguageVersionSpecific() || isPackageDescriptionVersionSpecific()) |
| return AvailableVersionComparison::Unavailable; |
| else |
| return AvailableVersionComparison::PotentiallyUnavailable; |
| } |
| |
| // The entity is available. |
| return AvailableVersionComparison::Available; |
| } |
| |
| const AvailableAttr *AvailableAttr::isUnavailable(const Decl *D) { |
| ASTContext &ctx = D->getASTContext(); |
| return D->getAttrs().getUnavailable(ctx); |
| } |
| |
| SpecializeAttr::SpecializeAttr(SourceLoc atLoc, SourceRange range, |
| TrailingWhereClause *clause, |
| bool exported, |
| SpecializationKind kind) |
| : DeclAttribute(DAK_Specialize, atLoc, range, /*Implicit=*/false), |
| trailingWhereClause(clause) { |
| Bits.SpecializeAttr.exported = exported; |
| Bits.SpecializeAttr.kind = unsigned(kind); |
| Bits.SpecializeAttr.numRequirements = 0; |
| } |
| |
| SpecializeAttr::SpecializeAttr(SourceLoc atLoc, SourceRange range, |
| ArrayRef<Requirement> requirements, |
| bool exported, |
| SpecializationKind kind) |
| : DeclAttribute(DAK_Specialize, atLoc, range, /*Implicit=*/false) { |
| Bits.SpecializeAttr.exported = exported; |
| Bits.SpecializeAttr.kind = unsigned(kind); |
| Bits.SpecializeAttr.numRequirements = requirements.size(); |
| std::copy(requirements.begin(), requirements.end(), getRequirementsData()); |
| } |
| |
| void SpecializeAttr::setRequirements(ASTContext &Ctx, |
| ArrayRef<Requirement> requirements) { |
| unsigned numClauseRequirements = |
| (trailingWhereClause) ? trailingWhereClause->getRequirements().size() : 0; |
| assert(requirements.size() <= numClauseRequirements); |
| if (!numClauseRequirements) |
| return; |
| Bits.SpecializeAttr.numRequirements = requirements.size(); |
| std::copy(requirements.begin(), requirements.end(), getRequirementsData()); |
| } |
| |
| ArrayRef<Requirement> SpecializeAttr::getRequirements() const { |
| return const_cast<SpecializeAttr*>(this)->getRequirements(); |
| } |
| |
| TrailingWhereClause *SpecializeAttr::getTrailingWhereClause() const { |
| return trailingWhereClause; |
| } |
| |
| SpecializeAttr *SpecializeAttr::create(ASTContext &Ctx, SourceLoc atLoc, |
| SourceRange range, |
| TrailingWhereClause *clause, |
| bool exported, |
| SpecializationKind kind) { |
| unsigned numRequirements = (clause) ? clause->getRequirements().size() : 0; |
| unsigned size = |
| sizeof(SpecializeAttr) + (numRequirements * sizeof(Requirement)); |
| void *mem = Ctx.Allocate(size, alignof(SpecializeAttr)); |
| return new (mem) |
| SpecializeAttr(atLoc, range, clause, exported, kind); |
| } |
| |
| SpecializeAttr *SpecializeAttr::create(ASTContext &Ctx, SourceLoc atLoc, |
| SourceRange range, |
| ArrayRef<Requirement> requirements, |
| bool exported, |
| SpecializationKind kind) { |
| unsigned numRequirements = requirements.size(); |
| unsigned size = |
| sizeof(SpecializeAttr) + (numRequirements * sizeof(Requirement)); |
| void *mem = Ctx.Allocate(size, alignof(SpecializeAttr)); |
| return new (mem) |
| SpecializeAttr(atLoc, range, requirements, exported, kind); |
| } |
| |
| |
| ImplementsAttr::ImplementsAttr(SourceLoc atLoc, SourceRange range, |
| TypeLoc ProtocolType, |
| DeclName MemberName, |
| DeclNameLoc MemberNameLoc) |
| : DeclAttribute(DAK_Implements, atLoc, range, /*Implicit=*/false), |
| ProtocolType(ProtocolType), |
| MemberName(MemberName), |
| MemberNameLoc(MemberNameLoc) { |
| } |
| |
| |
| ImplementsAttr *ImplementsAttr::create(ASTContext &Ctx, SourceLoc atLoc, |
| SourceRange range, |
| TypeLoc ProtocolType, |
| DeclName MemberName, |
| DeclNameLoc MemberNameLoc) { |
| void *mem = Ctx.Allocate(sizeof(ImplementsAttr), alignof(ImplementsAttr)); |
| return new (mem) ImplementsAttr(atLoc, range, ProtocolType, |
| MemberName, MemberNameLoc); |
| } |
| |
| TypeLoc ImplementsAttr::getProtocolType() const { |
| return ProtocolType; |
| } |
| |
| TypeLoc &ImplementsAttr::getProtocolType() { |
| return ProtocolType; |
| } |
| |
| CustomAttr::CustomAttr(SourceLoc atLoc, SourceRange range, TypeLoc type, |
| PatternBindingInitializer *initContext, Expr *arg, |
| ArrayRef<Identifier> argLabels, |
| ArrayRef<SourceLoc> argLabelLocs, bool implicit) |
| : DeclAttribute(DAK_Custom, atLoc, range, implicit), |
| type(type), |
| arg(arg), |
| initContext(initContext) { |
| hasArgLabelLocs = !argLabelLocs.empty(); |
| numArgLabels = argLabels.size(); |
| initializeCallArguments(argLabels, argLabelLocs, |
| /*hasTrailingClosure=*/false); |
| } |
| |
| CustomAttr *CustomAttr::create(ASTContext &ctx, SourceLoc atLoc, TypeLoc type, |
| bool hasInitializer, |
| PatternBindingInitializer *initContext, |
| SourceLoc lParenLoc, |
| ArrayRef<Expr *> args, |
| ArrayRef<Identifier> argLabels, |
| ArrayRef<SourceLoc> argLabelLocs, |
| SourceLoc rParenLoc, |
| bool implicit) { |
| SmallVector<Identifier, 2> argLabelsScratch; |
| SmallVector<SourceLoc, 2> argLabelLocsScratch; |
| Expr *arg = nullptr; |
| if (hasInitializer) { |
| arg = packSingleArgument(ctx, lParenLoc, args, argLabels, argLabelLocs, |
| rParenLoc, nullptr, implicit, argLabelsScratch, |
| argLabelLocsScratch); |
| } |
| |
| SourceRange range(atLoc, type.getSourceRange().End); |
| if (arg) |
| range.End = arg->getEndLoc(); |
| |
| size_t size = totalSizeToAlloc(argLabels, argLabelLocs, |
| /*hasTrailingClosure=*/false); |
| void *mem = ctx.Allocate(size, alignof(CustomAttr)); |
| return new (mem) CustomAttr(atLoc, range, type, initContext, arg, argLabels, |
| argLabelLocs, implicit); |
| } |
| |
| void swift::simple_display(llvm::raw_ostream &out, const DeclAttribute *attr) { |
| if (attr) |
| attr->print(out); |
| } |