| //===- 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<clang::AvailabilityInfo> 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<clang::AvailabilityAttr>()) { |
| Availabilities.insert(clang::AvailabilityInfo( |
| A->getPlatform()->getName(), A->getIntroduced(), A->getDeprecated(), |
| A->getObsoleted(), A->getUnavailable(), false, false)); |
| } |
| |
| if (const auto *A = RD->getAttr<clang::UnavailableAttr>()) |
| if (!A->isImplicit()) |
| Availabilities.UnconditionallyUnavailable = true; |
| |
| if (const auto *A = RD->getAttr<clang::DeprecatedAttr>()) |
| 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<Decl>(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 |