mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
should be shown in the interface. Also switch the option and hide all underscored protocols by default, unless they are marked with the new attribute.
719 lines
22 KiB
C++
719 lines
22 KiB
C++
//===--- Attr.cpp - Swift Language Attr ASTs ------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://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/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/ADT/StringSwitch.h"
|
|
using namespace swift;
|
|
|
|
|
|
// 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);
|
|
}
|
|
|
|
/// 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);
|
|
}
|
|
|
|
|
|
/// 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) {
|
|
unsigned 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");
|
|
}
|
|
|
|
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))
|
|
continue;
|
|
|
|
// Unconditional unavailable.
|
|
if (AvAttr->isUnconditionallyUnavailable())
|
|
return AvAttr;
|
|
|
|
auto MinVersion = ctx.LangOpts.getMinPlatformVersion();
|
|
switch (AvAttr->getMinVersionAvailability(MinVersion)) {
|
|
case MinVersionComparison::Available:
|
|
case MinVersionComparison::PotentiallyUnavailable:
|
|
break;
|
|
|
|
case MinVersionComparison::Obsoleted:
|
|
case MinVersionComparison::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))
|
|
continue;
|
|
|
|
// Unconditional deprecated.
|
|
if (AvAttr->isUnconditionallyDeprecated())
|
|
return AvAttr;
|
|
|
|
Optional<clang::VersionTuple> DeprecatedVersion = AvAttr->Deprecated;
|
|
if (!DeprecatedVersion.hasValue())
|
|
continue;
|
|
|
|
auto MinVersion = ctx.LangOpts.getMinPlatformVersion();
|
|
|
|
// 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 {
|
|
StreamPrinter P(llvm::errs());
|
|
PrintOptions PO = PrintOptions::printEverything();
|
|
print(P, PO);
|
|
}
|
|
|
|
/// 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.
|
|
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;
|
|
|
|
if (AvailAttr->Unconditional != UnconditionalAvailabilityKind::None)
|
|
return false;
|
|
|
|
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(";
|
|
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 {
|
|
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;
|
|
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 (std::find(Options.ExcludeAttrList.begin(),
|
|
Options.ExcludeAttrList.end(),
|
|
DA->getKind()) != Options.ExcludeAttrList.end())
|
|
continue;
|
|
if (!Options.ExclusiveAttrList.empty()) {
|
|
if (std::find(Options.ExclusiveAttrList.begin(),
|
|
Options.ExclusiveAttrList.end(),
|
|
DA->getKind()) == Options.ExclusiveAttrList.end())
|
|
continue;
|
|
}
|
|
|
|
AttributeVector &which = DA->isDeclModifier() ? modifiers :
|
|
isShortAvailable(DA) ? shortAvailableAttributes :
|
|
DA->isLongAttribute() ? longAttributes :
|
|
attributes;
|
|
which.push_back(DA);
|
|
}
|
|
|
|
if (!shortAvailableAttributes.empty()) {
|
|
printShortFormAvailable(shortAvailableAttributes, Printer, Options);
|
|
}
|
|
|
|
for (auto DA : longAttributes)
|
|
DA->print(Printer, Options);
|
|
for (auto DA : attributes)
|
|
DA->print(Printer, Options);
|
|
for (auto DA : modifiers)
|
|
DA->print(Printer, Options);
|
|
}
|
|
|
|
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 {
|
|
|
|
// 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_ShowInInterface:
|
|
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_Accessibility:
|
|
case DAK_Ownership:
|
|
case DAK_Effects:
|
|
if (DeclAttribute::isDeclModifier(getKind())) {
|
|
Printer.printKeyword(getAttrName());
|
|
} else {
|
|
Printer.callPrintStructurePre(PrintStructureKind::BuiltinAttribute);
|
|
Printer.printAttrName(getAttrName(), /*needAt=*/true);
|
|
Printer.printStructurePost(PrintStructureKind::BuiltinAttribute);
|
|
}
|
|
return true;
|
|
|
|
case DAK_SetterAccessibility:
|
|
Printer.printKeyword(getAttrName());
|
|
Printer << "(set)";
|
|
return true;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
Printer.callPrintStructurePre(PrintStructureKind::BuiltinAttribute);
|
|
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)->Value << ")";
|
|
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);
|
|
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=\"" << Attr->Message << "\"";
|
|
else if (Attr->getUnconditionalAvailability()
|
|
== UnconditionalAvailabilityKind::UnavailableInSwift)
|
|
Printer << ", message=\"Not available in Swift\"";
|
|
|
|
Printer << ")";
|
|
break;
|
|
}
|
|
case DAK_AutoClosure:
|
|
Printer.printAttrName("@autoclosure");
|
|
if (cast<AutoClosureAttr>(this)->isEscaping())
|
|
Printer << "(escaping)";
|
|
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_SwiftNativeObjCRuntimeBase: {
|
|
auto *attr = cast<SwiftNativeObjCRuntimeBaseAttr>(this);
|
|
Printer.printAttrName("@_swift_native_objc_runtime_base");
|
|
Printer << "(" << attr->BaseClassName.str() << ")";
|
|
break;
|
|
}
|
|
|
|
case DAK_Swift3Migration: {
|
|
auto attr = cast<Swift3MigrationAttr>(this);
|
|
Printer.printAttrName("@swift3_migration");
|
|
Printer << "(";
|
|
|
|
bool printedAny = false;
|
|
auto printSeparator = [&] {
|
|
if (printedAny) Printer << ", ";
|
|
else printedAny = true;
|
|
};
|
|
|
|
if (attr->getRenamed()) {
|
|
printSeparator();
|
|
Printer << "renamed=\"" << attr->getRenamed() << "\"";
|
|
}
|
|
|
|
if (!attr->getMessage().empty()) {
|
|
printSeparator();
|
|
Printer << "message=\"";
|
|
Printer << attr->getMessage();
|
|
Printer << "\"";
|
|
}
|
|
|
|
Printer << ")";
|
|
break;
|
|
}
|
|
|
|
case DAK_WarnUnusedResult: {
|
|
Printer.printAttrName("@warn_unused_result");
|
|
auto *attr = cast<WarnUnusedResultAttr>(this);
|
|
bool printedParens = false;
|
|
if (!attr->getMessage().empty()) {
|
|
Printer << "(message=\"" << attr->getMessage() << "\"";
|
|
printedParens = true;
|
|
}
|
|
if (!attr->getMutableVariant().empty()) {
|
|
if (printedParens)
|
|
Printer << ", ";
|
|
else
|
|
Printer << "(";
|
|
Printer << "mutable_variant=\"" << attr->getMutableVariant() << "\"";
|
|
printedParens = true;
|
|
}
|
|
if (printedParens)
|
|
Printer << ")";
|
|
break;
|
|
}
|
|
|
|
default:
|
|
llvm_unreachable("handled before this switch");
|
|
|
|
case DAK_Count:
|
|
llvm_unreachable("exceed declaration attribute kinds");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void DeclAttribute::print(ASTPrinter &Printer,
|
|
const PrintOptions &Options) const {
|
|
|
|
if (!printImpl(Printer, Options))
|
|
return; // Nothing printed.
|
|
|
|
if (isLongAttribute() && Options.PrintLongAttrsOnSeparateLines)
|
|
Printer.printNewline();
|
|
else
|
|
Printer << " ";
|
|
}
|
|
|
|
void DeclAttribute::print(llvm::raw_ostream &OS) const {
|
|
StreamPrinter P(OS);
|
|
print(P, PrintOptions());
|
|
}
|
|
|
|
unsigned 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_SwiftNativeObjCRuntimeBase:
|
|
return "_swift_native_objc_runtime_base";
|
|
case DAK_Semantics:
|
|
return "_semantics";
|
|
case DAK_Available:
|
|
return "availability";
|
|
case DAK_AutoClosure:
|
|
return "autoclosure";
|
|
case DAK_ObjC:
|
|
return "objc";
|
|
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_Effects:
|
|
switch (cast<EffectsAttr>(this)->getKind()) {
|
|
case EffectsKind::ReadNone:
|
|
return "effects(readnone)";
|
|
case EffectsKind::ReadOnly:
|
|
return "effects(readonly)";
|
|
case EffectsKind::ReadWrite:
|
|
return "effects(readwrite)";
|
|
case EffectsKind::Unspecified:
|
|
return "effects(unspecified)";
|
|
}
|
|
case DAK_Accessibility:
|
|
case DAK_SetterAccessibility:
|
|
switch (cast<AbstractAccessibilityAttr>(this)->getAccess()) {
|
|
case Accessibility::Private:
|
|
return "private";
|
|
case Accessibility::Internal:
|
|
return "internal";
|
|
case Accessibility::Public:
|
|
return "public";
|
|
}
|
|
|
|
case DAK_Ownership:
|
|
switch (cast<OwnershipAttr>(this)->get()) {
|
|
case Ownership::Strong: llvm_unreachable("Never present in the attribute");
|
|
case Ownership::Weak: return "weak";
|
|
case Ownership::Unowned: return "unowned";
|
|
case Ownership::Unmanaged: return "unowned(unsafe)";
|
|
}
|
|
case DAK_RawDocComment:
|
|
return "<<raw doc comment>>";
|
|
case DAK_ObjCBridged:
|
|
return "<<ObjC bridged>>";
|
|
case DAK_SynthesizedProtocol:
|
|
return "<<synthesized protocol>>";
|
|
case DAK_Swift3Migration:
|
|
return "swift3_migration";
|
|
case DAK_WarnUnusedResult:
|
|
return "warn_unused_result";
|
|
}
|
|
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.
|
|
ObjCAttrBits.HasTrailingLocationInfo = true;
|
|
getTrailingLocations()[0] = parenRange.Start;
|
|
getTrailingLocations()[1] = parenRange.End;
|
|
std::memcpy(getTrailingLocations().slice(2).data(), nameLocs.data(),
|
|
nameLocs.size() * sizeof(SourceLoc));
|
|
} else {
|
|
ObjCAttrBits.HasTrailingLocationInfo = false;
|
|
}
|
|
|
|
ObjCAttrBits.ImplicitName = 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),
|
|
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),
|
|
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 {
|
|
return new (context) ObjCAttr(getName(), isNameImplicit());
|
|
}
|
|
|
|
AvailableAttr *
|
|
AvailableAttr::createUnconditional(ASTContext &C,
|
|
StringRef Message,
|
|
StringRef Rename,
|
|
UnconditionalAvailabilityKind Reason) {
|
|
assert(Reason != UnconditionalAvailabilityKind::None);
|
|
clang::VersionTuple NoVersion;
|
|
return new (C) AvailableAttr(
|
|
SourceLoc(), SourceRange(), PlatformKind::none, Message, Rename,
|
|
NoVersion, NoVersion, NoVersion, Reason, /* isImplicit */ false);
|
|
}
|
|
|
|
bool AvailableAttr::isActivePlatform(const ASTContext &ctx) const {
|
|
return isPlatformActive(Platform, ctx.LangOpts);
|
|
}
|
|
|
|
bool AvailableAttr::isUnconditionallyUnavailable() const {
|
|
switch (Unconditional) {
|
|
case UnconditionalAvailabilityKind::None:
|
|
case UnconditionalAvailabilityKind::Deprecated:
|
|
return false;
|
|
|
|
case UnconditionalAvailabilityKind::Unavailable:
|
|
case UnconditionalAvailabilityKind::UnavailableInSwift:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool AvailableAttr::isUnconditionallyDeprecated() const {
|
|
switch (Unconditional) {
|
|
case UnconditionalAvailabilityKind::None:
|
|
case UnconditionalAvailabilityKind::Unavailable:
|
|
case UnconditionalAvailabilityKind::UnavailableInSwift:
|
|
return false;
|
|
|
|
case UnconditionalAvailabilityKind::Deprecated:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
MinVersionComparison AvailableAttr::getMinVersionAvailability(
|
|
clang::VersionTuple minVersion) const {
|
|
// Unconditional unavailability.
|
|
if (isUnconditionallyUnavailable())
|
|
return MinVersionComparison::Unavailable;
|
|
|
|
// If this entity was obsoleted before or at the minimum platform version,
|
|
// consider it obsolete.
|
|
if (Obsoleted && *Obsoleted <= minVersion)
|
|
return MinVersionComparison::Obsoleted;
|
|
|
|
// If this entity was introduced after the minimum platform version, it's
|
|
// availability can only be determined dynamically.
|
|
if (Introduced && *Introduced > minVersion)
|
|
return MinVersionComparison::PotentiallyUnavailable;
|
|
|
|
// The entity is available.
|
|
return MinVersionComparison::Available;
|
|
}
|
|
|
|
const AvailableAttr *AvailableAttr::isUnavailable(const Decl *D) {
|
|
ASTContext &ctx = D->getASTContext();
|
|
return D->getAttrs().getUnavailable(ctx);
|
|
}
|
|
|
|
|