Path: blob/main/contrib/llvm-project/clang/lib/Sema/SemaAPINotes.cpp
35234 views
//===--- SemaAPINotes.cpp - API Notes Handling ----------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements the mapping from API notes to declaration attributes.9//10//===----------------------------------------------------------------------===//1112#include "clang/APINotes/APINotesReader.h"13#include "clang/AST/Decl.h"14#include "clang/AST/DeclObjC.h"15#include "clang/Basic/SourceLocation.h"16#include "clang/Lex/Lexer.h"17#include "clang/Sema/SemaInternal.h"18#include "clang/Sema/SemaObjC.h"19#include "clang/Sema/SemaSwift.h"20#include <stack>2122using namespace clang;2324namespace {25enum class IsActive_t : bool { Inactive, Active };26enum class IsSubstitution_t : bool { Original, Replacement };2728struct VersionedInfoMetadata {29/// An empty version refers to unversioned metadata.30VersionTuple Version;31unsigned IsActive : 1;32unsigned IsReplacement : 1;3334VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,35IsSubstitution_t Replacement)36: Version(Version), IsActive(Active == IsActive_t::Active),37IsReplacement(Replacement == IsSubstitution_t::Replacement) {}38};39} // end anonymous namespace4041/// Determine whether this is a multi-level pointer type.42static bool isIndirectPointerType(QualType Type) {43QualType Pointee = Type->getPointeeType();44if (Pointee.isNull())45return false;4647return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||48Pointee->isMemberPointerType();49}5051/// Apply nullability to the given declaration.52static void applyNullability(Sema &S, Decl *D, NullabilityKind Nullability,53VersionedInfoMetadata Metadata) {54if (!Metadata.IsActive)55return;5657auto GetModified =58[&](Decl *D, QualType QT,59NullabilityKind Nullability) -> std::optional<QualType> {60QualType Original = QT;61S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(),62isa<ParmVarDecl>(D),63/*OverrideExisting=*/true);64return (QT.getTypePtr() != Original.getTypePtr()) ? std::optional(QT)65: std::nullopt;66};6768if (auto Function = dyn_cast<FunctionDecl>(D)) {69if (auto Modified =70GetModified(D, Function->getReturnType(), Nullability)) {71const FunctionType *FnType = Function->getType()->castAs<FunctionType>();72if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(FnType))73Function->setType(S.Context.getFunctionType(74*Modified, proto->getParamTypes(), proto->getExtProtoInfo()));75else76Function->setType(77S.Context.getFunctionNoProtoType(*Modified, FnType->getExtInfo()));78}79} else if (auto Method = dyn_cast<ObjCMethodDecl>(D)) {80if (auto Modified = GetModified(D, Method->getReturnType(), Nullability)) {81Method->setReturnType(*Modified);8283// Make it a context-sensitive keyword if we can.84if (!isIndirectPointerType(*Modified))85Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(86Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));87}88} else if (auto Value = dyn_cast<ValueDecl>(D)) {89if (auto Modified = GetModified(D, Value->getType(), Nullability)) {90Value->setType(*Modified);9192// Make it a context-sensitive keyword if we can.93if (auto Parm = dyn_cast<ParmVarDecl>(D)) {94if (Parm->isObjCMethodParameter() && !isIndirectPointerType(*Modified))95Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(96Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));97}98}99} else if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) {100if (auto Modified = GetModified(D, Property->getType(), Nullability)) {101Property->setType(*Modified, Property->getTypeSourceInfo());102103// Make it a property attribute if we can.104if (!isIndirectPointerType(*Modified))105Property->setPropertyAttributes(106ObjCPropertyAttribute::kind_null_resettable);107}108}109}110111/// Copy a string into ASTContext-allocated memory.112static StringRef ASTAllocateString(ASTContext &Ctx, StringRef String) {113void *mem = Ctx.Allocate(String.size(), alignof(char *));114memcpy(mem, String.data(), String.size());115return StringRef(static_cast<char *>(mem), String.size());116}117118static AttributeCommonInfo getPlaceholderAttrInfo() {119return AttributeCommonInfo(SourceRange(),120AttributeCommonInfo::UnknownAttribute,121{AttributeCommonInfo::AS_GNU,122/*Spelling*/ 0, /*IsAlignas*/ false,123/*IsRegularKeywordAttribute*/ false});124}125126namespace {127template <typename A> struct AttrKindFor {};128129#define ATTR(X) \130template <> struct AttrKindFor<X##Attr> { \131static const attr::Kind value = attr::X; \132};133#include "clang/Basic/AttrList.inc"134135/// Handle an attribute introduced by API notes.136///137/// \param IsAddition Whether we should add a new attribute138/// (otherwise, we might remove an existing attribute).139/// \param CreateAttr Create the new attribute to be added.140template <typename A>141void handleAPINotedAttribute(142Sema &S, Decl *D, bool IsAddition, VersionedInfoMetadata Metadata,143llvm::function_ref<A *()> CreateAttr,144llvm::function_ref<Decl::attr_iterator(const Decl *)> GetExistingAttr) {145if (Metadata.IsActive) {146auto Existing = GetExistingAttr(D);147if (Existing != D->attr_end()) {148// Remove the existing attribute, and treat it as a superseded149// non-versioned attribute.150auto *Versioned = SwiftVersionedAdditionAttr::CreateImplicit(151S.Context, Metadata.Version, *Existing, /*IsReplacedByActive*/ true);152153D->getAttrs().erase(Existing);154D->addAttr(Versioned);155}156157// If we're supposed to add a new attribute, do so.158if (IsAddition) {159if (auto Attr = CreateAttr())160D->addAttr(Attr);161}162163return;164}165if (IsAddition) {166if (auto Attr = CreateAttr()) {167auto *Versioned = SwiftVersionedAdditionAttr::CreateImplicit(168S.Context, Metadata.Version, Attr,169/*IsReplacedByActive*/ Metadata.IsReplacement);170D->addAttr(Versioned);171}172} else {173// FIXME: This isn't preserving enough information for things like174// availability, where we're trying to remove a /specific/ kind of175// attribute.176auto *Versioned = SwiftVersionedRemovalAttr::CreateImplicit(177S.Context, Metadata.Version, AttrKindFor<A>::value,178/*IsReplacedByActive*/ Metadata.IsReplacement);179D->addAttr(Versioned);180}181}182183template <typename A>184void handleAPINotedAttribute(Sema &S, Decl *D, bool ShouldAddAttribute,185VersionedInfoMetadata Metadata,186llvm::function_ref<A *()> CreateAttr) {187handleAPINotedAttribute<A>(188S, D, ShouldAddAttribute, Metadata, CreateAttr, [](const Decl *D) {189return llvm::find_if(D->attrs(),190[](const Attr *Next) { return isa<A>(Next); });191});192}193} // namespace194195template <typename A>196static void handleAPINotedRetainCountAttribute(Sema &S, Decl *D,197bool ShouldAddAttribute,198VersionedInfoMetadata Metadata) {199// The template argument has a default to make the "removal" case more200// concise; it doesn't matter /which/ attribute is being removed.201handleAPINotedAttribute<A>(202S, D, ShouldAddAttribute, Metadata,203[&] { return new (S.Context) A(S.Context, getPlaceholderAttrInfo()); },204[](const Decl *D) -> Decl::attr_iterator {205return llvm::find_if(D->attrs(), [](const Attr *Next) -> bool {206return isa<CFReturnsRetainedAttr>(Next) ||207isa<CFReturnsNotRetainedAttr>(Next) ||208isa<NSReturnsRetainedAttr>(Next) ||209isa<NSReturnsNotRetainedAttr>(Next) ||210isa<CFAuditedTransferAttr>(Next);211});212});213}214215static void handleAPINotedRetainCountConvention(216Sema &S, Decl *D, VersionedInfoMetadata Metadata,217std::optional<api_notes::RetainCountConventionKind> Convention) {218if (!Convention)219return;220switch (*Convention) {221case api_notes::RetainCountConventionKind::None:222if (isa<FunctionDecl>(D)) {223handleAPINotedRetainCountAttribute<CFUnknownTransferAttr>(224S, D, /*shouldAddAttribute*/ true, Metadata);225} else {226handleAPINotedRetainCountAttribute<CFReturnsRetainedAttr>(227S, D, /*shouldAddAttribute*/ false, Metadata);228}229break;230case api_notes::RetainCountConventionKind::CFReturnsRetained:231handleAPINotedRetainCountAttribute<CFReturnsRetainedAttr>(232S, D, /*shouldAddAttribute*/ true, Metadata);233break;234case api_notes::RetainCountConventionKind::CFReturnsNotRetained:235handleAPINotedRetainCountAttribute<CFReturnsNotRetainedAttr>(236S, D, /*shouldAddAttribute*/ true, Metadata);237break;238case api_notes::RetainCountConventionKind::NSReturnsRetained:239handleAPINotedRetainCountAttribute<NSReturnsRetainedAttr>(240S, D, /*shouldAddAttribute*/ true, Metadata);241break;242case api_notes::RetainCountConventionKind::NSReturnsNotRetained:243handleAPINotedRetainCountAttribute<NSReturnsNotRetainedAttr>(244S, D, /*shouldAddAttribute*/ true, Metadata);245break;246}247}248249static void ProcessAPINotes(Sema &S, Decl *D,250const api_notes::CommonEntityInfo &Info,251VersionedInfoMetadata Metadata) {252// Availability253if (Info.Unavailable) {254handleAPINotedAttribute<UnavailableAttr>(S, D, true, Metadata, [&] {255return new (S.Context)256UnavailableAttr(S.Context, getPlaceholderAttrInfo(),257ASTAllocateString(S.Context, Info.UnavailableMsg));258});259}260261if (Info.UnavailableInSwift) {262handleAPINotedAttribute<AvailabilityAttr>(263S, D, true, Metadata,264[&] {265return new (S.Context) AvailabilityAttr(266S.Context, getPlaceholderAttrInfo(),267&S.Context.Idents.get("swift"), VersionTuple(), VersionTuple(),268VersionTuple(),269/*Unavailable=*/true,270ASTAllocateString(S.Context, Info.UnavailableMsg),271/*Strict=*/false,272/*Replacement=*/StringRef(),273/*Priority=*/Sema::AP_Explicit,274/*Environment=*/nullptr);275},276[](const Decl *D) {277return llvm::find_if(D->attrs(), [](const Attr *next) -> bool {278if (const auto *AA = dyn_cast<AvailabilityAttr>(next))279if (const auto *II = AA->getPlatform())280return II->isStr("swift");281return false;282});283});284}285286// swift_private287if (auto SwiftPrivate = Info.isSwiftPrivate()) {288handleAPINotedAttribute<SwiftPrivateAttr>(289S, D, *SwiftPrivate, Metadata, [&] {290return new (S.Context)291SwiftPrivateAttr(S.Context, getPlaceholderAttrInfo());292});293}294295// swift_name296if (!Info.SwiftName.empty()) {297handleAPINotedAttribute<SwiftNameAttr>(298S, D, true, Metadata, [&]() -> SwiftNameAttr * {299AttributeFactory AF{};300AttributePool AP{AF};301auto &C = S.getASTContext();302ParsedAttr *SNA =303AP.create(&C.Idents.get("swift_name"), SourceRange(), nullptr,304SourceLocation(), nullptr, nullptr, nullptr,305ParsedAttr::Form::GNU());306307if (!S.Swift().DiagnoseName(D, Info.SwiftName, D->getLocation(), *SNA,308/*IsAsync=*/false))309return nullptr;310311return new (S.Context)312SwiftNameAttr(S.Context, getPlaceholderAttrInfo(),313ASTAllocateString(S.Context, Info.SwiftName));314});315}316}317318static void ProcessAPINotes(Sema &S, Decl *D,319const api_notes::CommonTypeInfo &Info,320VersionedInfoMetadata Metadata) {321// swift_bridge322if (auto SwiftBridge = Info.getSwiftBridge()) {323handleAPINotedAttribute<SwiftBridgeAttr>(324S, D, !SwiftBridge->empty(), Metadata, [&] {325return new (S.Context)326SwiftBridgeAttr(S.Context, getPlaceholderAttrInfo(),327ASTAllocateString(S.Context, *SwiftBridge));328});329}330331// ns_error_domain332if (auto NSErrorDomain = Info.getNSErrorDomain()) {333handleAPINotedAttribute<NSErrorDomainAttr>(334S, D, !NSErrorDomain->empty(), Metadata, [&] {335return new (S.Context)336NSErrorDomainAttr(S.Context, getPlaceholderAttrInfo(),337&S.Context.Idents.get(*NSErrorDomain));338});339}340341ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info),342Metadata);343}344345/// Check that the replacement type provided by API notes is reasonable.346///347/// This is a very weak form of ABI check.348static bool checkAPINotesReplacementType(Sema &S, SourceLocation Loc,349QualType OrigType,350QualType ReplacementType) {351if (S.Context.getTypeSize(OrigType) !=352S.Context.getTypeSize(ReplacementType)) {353S.Diag(Loc, diag::err_incompatible_replacement_type)354<< ReplacementType << OrigType;355return true;356}357358return false;359}360361/// Process API notes for a variable or property.362static void ProcessAPINotes(Sema &S, Decl *D,363const api_notes::VariableInfo &Info,364VersionedInfoMetadata Metadata) {365// Type override.366if (Metadata.IsActive && !Info.getType().empty() &&367S.ParseTypeFromStringCallback) {368auto ParsedType = S.ParseTypeFromStringCallback(369Info.getType(), "<API Notes>", D->getLocation());370if (ParsedType.isUsable()) {371QualType Type = Sema::GetTypeFromParser(ParsedType.get());372auto TypeInfo =373S.Context.getTrivialTypeSourceInfo(Type, D->getLocation());374375if (auto Var = dyn_cast<VarDecl>(D)) {376// Make adjustments to parameter types.377if (isa<ParmVarDecl>(Var)) {378Type = S.ObjC().AdjustParameterTypeForObjCAutoRefCount(379Type, D->getLocation(), TypeInfo);380Type = S.Context.getAdjustedParameterType(Type);381}382383if (!checkAPINotesReplacementType(S, Var->getLocation(), Var->getType(),384Type)) {385Var->setType(Type);386Var->setTypeSourceInfo(TypeInfo);387}388} else if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) {389if (!checkAPINotesReplacementType(S, Property->getLocation(),390Property->getType(), Type))391Property->setType(Type, TypeInfo);392393} else394llvm_unreachable("API notes allowed a type on an unknown declaration");395}396}397398// Nullability.399if (auto Nullability = Info.getNullability())400applyNullability(S, D, *Nullability, Metadata);401402// Handle common entity information.403ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info),404Metadata);405}406407/// Process API notes for a parameter.408static void ProcessAPINotes(Sema &S, ParmVarDecl *D,409const api_notes::ParamInfo &Info,410VersionedInfoMetadata Metadata) {411// noescape412if (auto NoEscape = Info.isNoEscape())413handleAPINotedAttribute<NoEscapeAttr>(S, D, *NoEscape, Metadata, [&] {414return new (S.Context) NoEscapeAttr(S.Context, getPlaceholderAttrInfo());415});416417// Retain count convention418handleAPINotedRetainCountConvention(S, D, Metadata,419Info.getRetainCountConvention());420421// Handle common entity information.422ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info),423Metadata);424}425426/// Process API notes for a global variable.427static void ProcessAPINotes(Sema &S, VarDecl *D,428const api_notes::GlobalVariableInfo &Info,429VersionedInfoMetadata metadata) {430// Handle common entity information.431ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info),432metadata);433}434435/// Process API notes for an Objective-C property.436static void ProcessAPINotes(Sema &S, ObjCPropertyDecl *D,437const api_notes::ObjCPropertyInfo &Info,438VersionedInfoMetadata Metadata) {439// Handle common entity information.440ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info),441Metadata);442443if (auto AsAccessors = Info.getSwiftImportAsAccessors()) {444handleAPINotedAttribute<SwiftImportPropertyAsAccessorsAttr>(445S, D, *AsAccessors, Metadata, [&] {446return new (S.Context) SwiftImportPropertyAsAccessorsAttr(447S.Context, getPlaceholderAttrInfo());448});449}450}451452namespace {453typedef llvm::PointerUnion<FunctionDecl *, ObjCMethodDecl *> FunctionOrMethod;454}455456/// Process API notes for a function or method.457static void ProcessAPINotes(Sema &S, FunctionOrMethod AnyFunc,458const api_notes::FunctionInfo &Info,459VersionedInfoMetadata Metadata) {460// Find the declaration itself.461FunctionDecl *FD = AnyFunc.dyn_cast<FunctionDecl *>();462Decl *D = FD;463ObjCMethodDecl *MD = nullptr;464if (!D) {465MD = AnyFunc.get<ObjCMethodDecl *>();466D = MD;467}468469assert((FD || MD) && "Expecting Function or ObjCMethod");470471// Nullability of return type.472if (Info.NullabilityAudited)473applyNullability(S, D, Info.getReturnTypeInfo(), Metadata);474475// Parameters.476unsigned NumParams = FD ? FD->getNumParams() : MD->param_size();477478bool AnyTypeChanged = false;479for (unsigned I = 0; I != NumParams; ++I) {480ParmVarDecl *Param = FD ? FD->getParamDecl(I) : MD->param_begin()[I];481QualType ParamTypeBefore = Param->getType();482483if (I < Info.Params.size())484ProcessAPINotes(S, Param, Info.Params[I], Metadata);485486// Nullability.487if (Info.NullabilityAudited)488applyNullability(S, Param, Info.getParamTypeInfo(I), Metadata);489490if (ParamTypeBefore.getAsOpaquePtr() != Param->getType().getAsOpaquePtr())491AnyTypeChanged = true;492}493494// Result type override.495QualType OverriddenResultType;496if (Metadata.IsActive && !Info.ResultType.empty() &&497S.ParseTypeFromStringCallback) {498auto ParsedType = S.ParseTypeFromStringCallback(499Info.ResultType, "<API Notes>", D->getLocation());500if (ParsedType.isUsable()) {501QualType ResultType = Sema::GetTypeFromParser(ParsedType.get());502503if (MD) {504if (!checkAPINotesReplacementType(S, D->getLocation(),505MD->getReturnType(), ResultType)) {506auto ResultTypeInfo =507S.Context.getTrivialTypeSourceInfo(ResultType, D->getLocation());508MD->setReturnType(ResultType);509MD->setReturnTypeSourceInfo(ResultTypeInfo);510}511} else if (!checkAPINotesReplacementType(512S, FD->getLocation(), FD->getReturnType(), ResultType)) {513OverriddenResultType = ResultType;514AnyTypeChanged = true;515}516}517}518519// If the result type or any of the parameter types changed for a function520// declaration, we have to rebuild the type.521if (FD && AnyTypeChanged) {522if (const auto *fnProtoType = FD->getType()->getAs<FunctionProtoType>()) {523if (OverriddenResultType.isNull())524OverriddenResultType = fnProtoType->getReturnType();525526SmallVector<QualType, 4> ParamTypes;527for (auto Param : FD->parameters())528ParamTypes.push_back(Param->getType());529530FD->setType(S.Context.getFunctionType(OverriddenResultType, ParamTypes,531fnProtoType->getExtProtoInfo()));532} else if (!OverriddenResultType.isNull()) {533const auto *FnNoProtoType = FD->getType()->castAs<FunctionNoProtoType>();534FD->setType(S.Context.getFunctionNoProtoType(535OverriddenResultType, FnNoProtoType->getExtInfo()));536}537}538539// Retain count convention540handleAPINotedRetainCountConvention(S, D, Metadata,541Info.getRetainCountConvention());542543// Handle common entity information.544ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info),545Metadata);546}547548/// Process API notes for a C++ method.549static void ProcessAPINotes(Sema &S, CXXMethodDecl *Method,550const api_notes::CXXMethodInfo &Info,551VersionedInfoMetadata Metadata) {552ProcessAPINotes(S, (FunctionOrMethod)Method, Info, Metadata);553}554555/// Process API notes for a global function.556static void ProcessAPINotes(Sema &S, FunctionDecl *D,557const api_notes::GlobalFunctionInfo &Info,558VersionedInfoMetadata Metadata) {559// Handle common function information.560ProcessAPINotes(S, FunctionOrMethod(D),561static_cast<const api_notes::FunctionInfo &>(Info), Metadata);562}563564/// Process API notes for an enumerator.565static void ProcessAPINotes(Sema &S, EnumConstantDecl *D,566const api_notes::EnumConstantInfo &Info,567VersionedInfoMetadata Metadata) {568// Handle common information.569ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info),570Metadata);571}572573/// Process API notes for an Objective-C method.574static void ProcessAPINotes(Sema &S, ObjCMethodDecl *D,575const api_notes::ObjCMethodInfo &Info,576VersionedInfoMetadata Metadata) {577// Designated initializers.578if (Info.DesignatedInit) {579handleAPINotedAttribute<ObjCDesignatedInitializerAttr>(580S, D, true, Metadata, [&] {581if (ObjCInterfaceDecl *IFace = D->getClassInterface())582IFace->setHasDesignatedInitializers();583584return new (S.Context) ObjCDesignatedInitializerAttr(585S.Context, getPlaceholderAttrInfo());586});587}588589// Handle common function information.590ProcessAPINotes(S, FunctionOrMethod(D),591static_cast<const api_notes::FunctionInfo &>(Info), Metadata);592}593594/// Process API notes for a tag.595static void ProcessAPINotes(Sema &S, TagDecl *D, const api_notes::TagInfo &Info,596VersionedInfoMetadata Metadata) {597if (auto ImportAs = Info.SwiftImportAs)598D->addAttr(SwiftAttrAttr::Create(S.Context, "import_" + ImportAs.value()));599600if (auto RetainOp = Info.SwiftRetainOp)601D->addAttr(SwiftAttrAttr::Create(S.Context, "retain:" + RetainOp.value()));602603if (auto ReleaseOp = Info.SwiftReleaseOp)604D->addAttr(605SwiftAttrAttr::Create(S.Context, "release:" + ReleaseOp.value()));606607if (auto Copyable = Info.isSwiftCopyable()) {608if (!*Copyable)609D->addAttr(SwiftAttrAttr::Create(S.Context, "~Copyable"));610}611612if (auto Extensibility = Info.EnumExtensibility) {613using api_notes::EnumExtensibilityKind;614bool ShouldAddAttribute = (*Extensibility != EnumExtensibilityKind::None);615handleAPINotedAttribute<EnumExtensibilityAttr>(616S, D, ShouldAddAttribute, Metadata, [&] {617EnumExtensibilityAttr::Kind kind;618switch (*Extensibility) {619case EnumExtensibilityKind::None:620llvm_unreachable("remove only");621case EnumExtensibilityKind::Open:622kind = EnumExtensibilityAttr::Open;623break;624case EnumExtensibilityKind::Closed:625kind = EnumExtensibilityAttr::Closed;626break;627}628return new (S.Context)629EnumExtensibilityAttr(S.Context, getPlaceholderAttrInfo(), kind);630});631}632633if (auto FlagEnum = Info.isFlagEnum()) {634handleAPINotedAttribute<FlagEnumAttr>(S, D, *FlagEnum, Metadata, [&] {635return new (S.Context) FlagEnumAttr(S.Context, getPlaceholderAttrInfo());636});637}638639// Handle common type information.640ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info),641Metadata);642}643644/// Process API notes for a typedef.645static void ProcessAPINotes(Sema &S, TypedefNameDecl *D,646const api_notes::TypedefInfo &Info,647VersionedInfoMetadata Metadata) {648// swift_wrapper649using SwiftWrapperKind = api_notes::SwiftNewTypeKind;650651if (auto SwiftWrapper = Info.SwiftWrapper) {652handleAPINotedAttribute<SwiftNewTypeAttr>(653S, D, *SwiftWrapper != SwiftWrapperKind::None, Metadata, [&] {654SwiftNewTypeAttr::NewtypeKind Kind;655switch (*SwiftWrapper) {656case SwiftWrapperKind::None:657llvm_unreachable("Shouldn't build an attribute");658659case SwiftWrapperKind::Struct:660Kind = SwiftNewTypeAttr::NK_Struct;661break;662663case SwiftWrapperKind::Enum:664Kind = SwiftNewTypeAttr::NK_Enum;665break;666}667AttributeCommonInfo SyntaxInfo{668SourceRange(),669AttributeCommonInfo::AT_SwiftNewType,670{AttributeCommonInfo::AS_GNU, SwiftNewTypeAttr::GNU_swift_wrapper,671/*IsAlignas*/ false, /*IsRegularKeywordAttribute*/ false}};672return new (S.Context) SwiftNewTypeAttr(S.Context, SyntaxInfo, Kind);673});674}675676// Handle common type information.677ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info),678Metadata);679}680681/// Process API notes for an Objective-C class or protocol.682static void ProcessAPINotes(Sema &S, ObjCContainerDecl *D,683const api_notes::ContextInfo &Info,684VersionedInfoMetadata Metadata) {685// Handle common type information.686ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info),687Metadata);688}689690/// Process API notes for an Objective-C class.691static void ProcessAPINotes(Sema &S, ObjCInterfaceDecl *D,692const api_notes::ContextInfo &Info,693VersionedInfoMetadata Metadata) {694if (auto AsNonGeneric = Info.getSwiftImportAsNonGeneric()) {695handleAPINotedAttribute<SwiftImportAsNonGenericAttr>(696S, D, *AsNonGeneric, Metadata, [&] {697return new (S.Context)698SwiftImportAsNonGenericAttr(S.Context, getPlaceholderAttrInfo());699});700}701702if (auto ObjcMembers = Info.getSwiftObjCMembers()) {703handleAPINotedAttribute<SwiftObjCMembersAttr>(704S, D, *ObjcMembers, Metadata, [&] {705return new (S.Context)706SwiftObjCMembersAttr(S.Context, getPlaceholderAttrInfo());707});708}709710// Handle information common to Objective-C classes and protocols.711ProcessAPINotes(S, static_cast<clang::ObjCContainerDecl *>(D), Info,712Metadata);713}714715/// If we're applying API notes with an active, non-default version, and the716/// versioned API notes have a SwiftName but the declaration normally wouldn't717/// have one, add a removal attribute to make it clear that the new SwiftName718/// attribute only applies to the active version of \p D, not to all versions.719///720/// This must be run \em before processing API notes for \p D, because otherwise721/// any existing SwiftName attribute will have been packaged up in a722/// SwiftVersionedAdditionAttr.723template <typename SpecificInfo>724static void maybeAttachUnversionedSwiftName(725Sema &S, Decl *D,726const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info) {727if (D->hasAttr<SwiftNameAttr>())728return;729if (!Info.getSelected())730return;731732// Is the active slice versioned, and does it set a Swift name?733VersionTuple SelectedVersion;734SpecificInfo SelectedInfoSlice;735std::tie(SelectedVersion, SelectedInfoSlice) = Info[*Info.getSelected()];736if (SelectedVersion.empty())737return;738if (SelectedInfoSlice.SwiftName.empty())739return;740741// Does the unversioned slice /not/ set a Swift name?742for (const auto &VersionAndInfoSlice : Info) {743if (!VersionAndInfoSlice.first.empty())744continue;745if (!VersionAndInfoSlice.second.SwiftName.empty())746return;747}748749// Then explicitly call that out with a removal attribute.750VersionedInfoMetadata DummyFutureMetadata(751SelectedVersion, IsActive_t::Inactive, IsSubstitution_t::Replacement);752handleAPINotedAttribute<SwiftNameAttr>(753S, D, /*add*/ false, DummyFutureMetadata, []() -> SwiftNameAttr * {754llvm_unreachable("should not try to add an attribute here");755});756}757758/// Processes all versions of versioned API notes.759///760/// Just dispatches to the various ProcessAPINotes functions in this file.761template <typename SpecificDecl, typename SpecificInfo>762static void ProcessVersionedAPINotes(763Sema &S, SpecificDecl *D,764const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info) {765766maybeAttachUnversionedSwiftName(S, D, Info);767768unsigned Selected = Info.getSelected().value_or(Info.size());769770VersionTuple Version;771SpecificInfo InfoSlice;772for (unsigned i = 0, e = Info.size(); i != e; ++i) {773std::tie(Version, InfoSlice) = Info[i];774auto Active = (i == Selected) ? IsActive_t::Active : IsActive_t::Inactive;775auto Replacement = IsSubstitution_t::Original;776if (Active == IsActive_t::Inactive && Version.empty()) {777Replacement = IsSubstitution_t::Replacement;778Version = Info[Selected].first;779}780ProcessAPINotes(S, D, InfoSlice,781VersionedInfoMetadata(Version, Active, Replacement));782}783}784785/// Process API notes that are associated with this declaration, mapping them786/// to attributes as appropriate.787void Sema::ProcessAPINotes(Decl *D) {788if (!D)789return;790791auto GetNamespaceContext =792[&](DeclContext *DC) -> std::optional<api_notes::Context> {793if (auto NamespaceContext = dyn_cast<NamespaceDecl>(DC)) {794for (auto Reader :795APINotes.findAPINotes(NamespaceContext->getLocation())) {796// Retrieve the context ID for the parent namespace of the decl.797std::stack<NamespaceDecl *> NamespaceStack;798{799for (auto CurrentNamespace = NamespaceContext; CurrentNamespace;800CurrentNamespace =801dyn_cast<NamespaceDecl>(CurrentNamespace->getParent())) {802if (!CurrentNamespace->isInlineNamespace())803NamespaceStack.push(CurrentNamespace);804}805}806std::optional<api_notes::ContextID> NamespaceID;807while (!NamespaceStack.empty()) {808auto CurrentNamespace = NamespaceStack.top();809NamespaceStack.pop();810NamespaceID = Reader->lookupNamespaceID(CurrentNamespace->getName(),811NamespaceID);812if (!NamespaceID)813break;814}815if (NamespaceID)816return api_notes::Context(*NamespaceID,817api_notes::ContextKind::Namespace);818}819}820return std::nullopt;821};822823// Globals.824if (D->getDeclContext()->isFileContext() ||825D->getDeclContext()->isNamespace() ||826D->getDeclContext()->isExternCContext() ||827D->getDeclContext()->isExternCXXContext()) {828std::optional<api_notes::Context> APINotesContext =829GetNamespaceContext(D->getDeclContext());830// Global variables.831if (auto VD = dyn_cast<VarDecl>(D)) {832for (auto Reader : APINotes.findAPINotes(D->getLocation())) {833auto Info =834Reader->lookupGlobalVariable(VD->getName(), APINotesContext);835ProcessVersionedAPINotes(*this, VD, Info);836}837838return;839}840841// Global functions.842if (auto FD = dyn_cast<FunctionDecl>(D)) {843if (FD->getDeclName().isIdentifier()) {844for (auto Reader : APINotes.findAPINotes(D->getLocation())) {845auto Info =846Reader->lookupGlobalFunction(FD->getName(), APINotesContext);847ProcessVersionedAPINotes(*this, FD, Info);848}849}850851return;852}853854// Objective-C classes.855if (auto Class = dyn_cast<ObjCInterfaceDecl>(D)) {856for (auto Reader : APINotes.findAPINotes(D->getLocation())) {857auto Info = Reader->lookupObjCClassInfo(Class->getName());858ProcessVersionedAPINotes(*this, Class, Info);859}860861return;862}863864// Objective-C protocols.865if (auto Protocol = dyn_cast<ObjCProtocolDecl>(D)) {866for (auto Reader : APINotes.findAPINotes(D->getLocation())) {867auto Info = Reader->lookupObjCProtocolInfo(Protocol->getName());868ProcessVersionedAPINotes(*this, Protocol, Info);869}870871return;872}873874// Tags875if (auto Tag = dyn_cast<TagDecl>(D)) {876std::string LookupName = Tag->getName().str();877878// Use the source location to discern if this Tag is an OPTIONS macro.879// For now we would like to limit this trick of looking up the APINote tag880// using the EnumDecl's QualType in the case where the enum is anonymous.881// This is only being used to support APINotes lookup for C++882// NS/CF_OPTIONS when C++-Interop is enabled.883std::string MacroName =884LookupName.empty() && Tag->getOuterLocStart().isMacroID()885? clang::Lexer::getImmediateMacroName(886Tag->getOuterLocStart(),887Tag->getASTContext().getSourceManager(), LangOpts)888.str()889: "";890891if (LookupName.empty() && isa<clang::EnumDecl>(Tag) &&892(MacroName == "CF_OPTIONS" || MacroName == "NS_OPTIONS" ||893MacroName == "OBJC_OPTIONS" || MacroName == "SWIFT_OPTIONS")) {894895clang::QualType T = llvm::cast<clang::EnumDecl>(Tag)->getIntegerType();896LookupName = clang::QualType::getAsString(897T.split(), getASTContext().getPrintingPolicy());898}899900for (auto Reader : APINotes.findAPINotes(D->getLocation())) {901auto Info = Reader->lookupTag(LookupName, APINotesContext);902ProcessVersionedAPINotes(*this, Tag, Info);903}904905return;906}907908// Typedefs909if (auto Typedef = dyn_cast<TypedefNameDecl>(D)) {910for (auto Reader : APINotes.findAPINotes(D->getLocation())) {911auto Info = Reader->lookupTypedef(Typedef->getName(), APINotesContext);912ProcessVersionedAPINotes(*this, Typedef, Info);913}914915return;916}917}918919// Enumerators.920if (D->getDeclContext()->getRedeclContext()->isFileContext() ||921D->getDeclContext()->getRedeclContext()->isExternCContext()) {922if (auto EnumConstant = dyn_cast<EnumConstantDecl>(D)) {923for (auto Reader : APINotes.findAPINotes(D->getLocation())) {924auto Info = Reader->lookupEnumConstant(EnumConstant->getName());925ProcessVersionedAPINotes(*this, EnumConstant, Info);926}927928return;929}930}931932if (auto ObjCContainer = dyn_cast<ObjCContainerDecl>(D->getDeclContext())) {933// Location function that looks up an Objective-C context.934auto GetContext = [&](api_notes::APINotesReader *Reader)935-> std::optional<api_notes::ContextID> {936if (auto Protocol = dyn_cast<ObjCProtocolDecl>(ObjCContainer)) {937if (auto Found = Reader->lookupObjCProtocolID(Protocol->getName()))938return *Found;939940return std::nullopt;941}942943if (auto Impl = dyn_cast<ObjCCategoryImplDecl>(ObjCContainer)) {944if (auto Cat = Impl->getCategoryDecl())945ObjCContainer = Cat->getClassInterface();946else947return std::nullopt;948}949950if (auto Category = dyn_cast<ObjCCategoryDecl>(ObjCContainer)) {951if (Category->getClassInterface())952ObjCContainer = Category->getClassInterface();953else954return std::nullopt;955}956957if (auto Impl = dyn_cast<ObjCImplDecl>(ObjCContainer)) {958if (Impl->getClassInterface())959ObjCContainer = Impl->getClassInterface();960else961return std::nullopt;962}963964if (auto Class = dyn_cast<ObjCInterfaceDecl>(ObjCContainer)) {965if (auto Found = Reader->lookupObjCClassID(Class->getName()))966return *Found;967968return std::nullopt;969}970971return std::nullopt;972};973974// Objective-C methods.975if (auto Method = dyn_cast<ObjCMethodDecl>(D)) {976for (auto Reader : APINotes.findAPINotes(D->getLocation())) {977if (auto Context = GetContext(Reader)) {978// Map the selector.979Selector Sel = Method->getSelector();980SmallVector<StringRef, 2> SelPieces;981if (Sel.isUnarySelector()) {982SelPieces.push_back(Sel.getNameForSlot(0));983} else {984for (unsigned i = 0, n = Sel.getNumArgs(); i != n; ++i)985SelPieces.push_back(Sel.getNameForSlot(i));986}987988api_notes::ObjCSelectorRef SelectorRef;989SelectorRef.NumArgs = Sel.getNumArgs();990SelectorRef.Identifiers = SelPieces;991992auto Info = Reader->lookupObjCMethod(*Context, SelectorRef,993Method->isInstanceMethod());994ProcessVersionedAPINotes(*this, Method, Info);995}996}997}998999// Objective-C properties.1000if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) {1001for (auto Reader : APINotes.findAPINotes(D->getLocation())) {1002if (auto Context = GetContext(Reader)) {1003bool isInstanceProperty =1004(Property->getPropertyAttributesAsWritten() &1005ObjCPropertyAttribute::kind_class) == 0;1006auto Info = Reader->lookupObjCProperty(*Context, Property->getName(),1007isInstanceProperty);1008ProcessVersionedAPINotes(*this, Property, Info);1009}1010}10111012return;1013}1014}10151016if (auto CXXRecord = dyn_cast<CXXRecordDecl>(D->getDeclContext())) {1017auto GetRecordContext = [&](api_notes::APINotesReader *Reader)1018-> std::optional<api_notes::ContextID> {1019auto ParentContext = GetNamespaceContext(CXXRecord->getDeclContext());1020if (auto Found = Reader->lookupTagID(CXXRecord->getName(), ParentContext))1021return *Found;10221023return std::nullopt;1024};10251026if (auto CXXMethod = dyn_cast<CXXMethodDecl>(D)) {1027for (auto Reader : APINotes.findAPINotes(D->getLocation())) {1028if (auto Context = GetRecordContext(Reader)) {1029auto Info = Reader->lookupCXXMethod(*Context, CXXMethod->getName());1030ProcessVersionedAPINotes(*this, CXXMethod, Info);1031}1032}1033}1034}1035}103610371038