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