120 lines · cpp
1//===- Availability.cpp --------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the Availability information for Decls.10//11//===----------------------------------------------------------------------===//12 13#include "clang/AST/Availability.h"14#include "clang/AST/ASTContext.h"15#include "clang/AST/Attr.h"16#include "clang/AST/Decl.h"17#include "clang/Basic/TargetInfo.h"18 19namespace {20 21/// Represents the availability of a symbol across platforms.22struct AvailabilitySet {23 bool UnconditionallyDeprecated = false;24 bool UnconditionallyUnavailable = false;25 26 void insert(clang::AvailabilityInfo &&Availability) {27 auto *Found = getForPlatform(Availability.Domain);28 if (Found)29 Found->mergeWith(std::move(Availability));30 else31 Availabilities.emplace_back(std::move(Availability));32 }33 34 clang::AvailabilityInfo *getForPlatform(llvm::StringRef Domain) {35 auto *It = llvm::find_if(Availabilities,36 [Domain](const clang::AvailabilityInfo &Info) {37 return Domain.compare(Info.Domain) == 0;38 });39 return It == Availabilities.end() ? nullptr : It;40 }41 42private:43 llvm::SmallVector<clang::AvailabilityInfo> Availabilities;44};45 46static void createInfoForDecl(const clang::Decl *Decl,47 AvailabilitySet &Availabilities) {48 // Collect availability attributes from all redeclarations.49 for (const auto *RD : Decl->redecls()) {50 for (const auto *A : RD->specific_attrs<clang::AvailabilityAttr>()) {51 Availabilities.insert(clang::AvailabilityInfo(52 A->getPlatform()->getName(), A->getIntroduced(), A->getDeprecated(),53 A->getObsoleted(), A->getUnavailable(), false, false));54 }55 56 if (const auto *A = RD->getAttr<clang::UnavailableAttr>())57 if (!A->isImplicit())58 Availabilities.UnconditionallyUnavailable = true;59 60 if (const auto *A = RD->getAttr<clang::DeprecatedAttr>())61 if (!A->isImplicit())62 Availabilities.UnconditionallyDeprecated = true;63 }64}65 66} // namespace67 68namespace clang {69 70void AvailabilityInfo::mergeWith(AvailabilityInfo Other) {71 if (isDefault() && Other.isDefault())72 return;73 74 if (Domain.empty())75 Domain = Other.Domain;76 77 UnconditionallyUnavailable |= Other.UnconditionallyUnavailable;78 UnconditionallyDeprecated |= Other.UnconditionallyDeprecated;79 Unavailable |= Other.Unavailable;80 81 Introduced = std::max(Introduced, Other.Introduced);82 83 // Default VersionTuple is 0.0.0 so if both are non default let's pick the84 // smallest version number, otherwise select the one that is non-zero if there85 // is one.86 if (!Deprecated.empty() && !Other.Deprecated.empty())87 Deprecated = std::min(Deprecated, Other.Deprecated);88 else89 Deprecated = std::max(Deprecated, Other.Deprecated);90 91 if (!Obsoleted.empty() && !Other.Obsoleted.empty())92 Obsoleted = std::min(Obsoleted, Other.Obsoleted);93 else94 Obsoleted = std::max(Obsoleted, Other.Obsoleted);95}96 97AvailabilityInfo AvailabilityInfo::createFromDecl(const Decl *D) {98 AvailabilitySet Availabilities;99 // Walk DeclContexts upwards starting from D to find the combined availability100 // of the symbol.101 for (const auto *Ctx = D; Ctx;102 Ctx = llvm::cast_or_null<Decl>(Ctx->getDeclContext()))103 createInfoForDecl(Ctx, Availabilities);104 105 if (auto *Avail = Availabilities.getForPlatform(106 D->getASTContext().getTargetInfo().getPlatformName())) {107 Avail->UnconditionallyDeprecated = Availabilities.UnconditionallyDeprecated;108 Avail->UnconditionallyUnavailable =109 Availabilities.UnconditionallyUnavailable;110 return std::move(*Avail);111 }112 113 AvailabilityInfo Avail;114 Avail.UnconditionallyDeprecated = Availabilities.UnconditionallyDeprecated;115 Avail.UnconditionallyUnavailable = Availabilities.UnconditionallyUnavailable;116 return Avail;117}118 119} // namespace clang120