//===- Availability.cpp --------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file implements the Availability information for Decls. // //===----------------------------------------------------------------------===// #include "clang/AST/Availability.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/Basic/TargetInfo.h" namespace { /// Represents the availability of a symbol across platforms. struct AvailabilitySet { bool UnconditionallyDeprecated = false; bool UnconditionallyUnavailable = false; void insert(clang::AvailabilityInfo &&Availability) { auto *Found = getForPlatform(Availability.Domain); if (Found) Found->mergeWith(std::move(Availability)); else Availabilities.emplace_back(std::move(Availability)); } clang::AvailabilityInfo *getForPlatform(llvm::StringRef Domain) { auto *It = llvm::find_if(Availabilities, [Domain](const clang::AvailabilityInfo &Info) { return Domain.compare(Info.Domain) == 0; }); return It == Availabilities.end() ? nullptr : It; } private: llvm::SmallVector Availabilities; }; static void createInfoForDecl(const clang::Decl *Decl, AvailabilitySet &Availabilities) { // Collect availability attributes from all redeclarations. for (const auto *RD : Decl->redecls()) { for (const auto *A : RD->specific_attrs()) { Availabilities.insert(clang::AvailabilityInfo( A->getPlatform()->getName(), A->getIntroduced(), A->getDeprecated(), A->getObsoleted(), A->getUnavailable(), false, false)); } if (const auto *A = RD->getAttr()) if (!A->isImplicit()) Availabilities.UnconditionallyUnavailable = true; if (const auto *A = RD->getAttr()) if (!A->isImplicit()) Availabilities.UnconditionallyDeprecated = true; } } } // namespace namespace clang { void AvailabilityInfo::mergeWith(AvailabilityInfo Other) { if (isDefault() && Other.isDefault()) return; if (Domain.empty()) Domain = Other.Domain; UnconditionallyUnavailable |= Other.UnconditionallyUnavailable; UnconditionallyDeprecated |= Other.UnconditionallyDeprecated; Unavailable |= Other.Unavailable; Introduced = std::max(Introduced, Other.Introduced); // Default VersionTuple is 0.0.0 so if both are non default let's pick the // smallest version number, otherwise select the one that is non-zero if there // is one. if (!Deprecated.empty() && !Other.Deprecated.empty()) Deprecated = std::min(Deprecated, Other.Deprecated); else Deprecated = std::max(Deprecated, Other.Deprecated); if (!Obsoleted.empty() && !Other.Obsoleted.empty()) Obsoleted = std::min(Obsoleted, Other.Obsoleted); else Obsoleted = std::max(Obsoleted, Other.Obsoleted); } AvailabilityInfo AvailabilityInfo::createFromDecl(const Decl *D) { AvailabilitySet Availabilities; // Walk DeclContexts upwards starting from D to find the combined availability // of the symbol. for (const auto *Ctx = D; Ctx; Ctx = llvm::cast_or_null(Ctx->getDeclContext())) createInfoForDecl(Ctx, Availabilities); if (auto *Avail = Availabilities.getForPlatform( D->getASTContext().getTargetInfo().getPlatformName())) { Avail->UnconditionallyDeprecated = Availabilities.UnconditionallyDeprecated; Avail->UnconditionallyUnavailable = Availabilities.UnconditionallyUnavailable; return std::move(*Avail); } AvailabilityInfo Avail; Avail.UnconditionallyDeprecated = Availabilities.UnconditionallyDeprecated; Avail.UnconditionallyUnavailable = Availabilities.UnconditionallyUnavailable; return Avail; } } // namespace clang