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-exception 6 // 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 19 namespace { 20 21 /// Represents the availability of a symbol across platforms. 22 struct 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 else 31 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 42 private: 43 llvm::SmallVector<clang::AvailabilityInfo> Availabilities; 44 }; 45 46 static 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 } // namespace 67 68 namespace clang { 69 70 void 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 the 84 // smallest version number, otherwise select the one that is non-zero if there 85 // is one. 86 if (!Deprecated.empty() && !Other.Deprecated.empty()) 87 Deprecated = std::min(Deprecated, Other.Deprecated); 88 else 89 Deprecated = std::max(Deprecated, Other.Deprecated); 90 91 if (!Obsoleted.empty() && !Other.Obsoleted.empty()) 92 Obsoleted = std::min(Obsoleted, Other.Obsoleted); 93 else 94 Obsoleted = std::max(Obsoleted, Other.Obsoleted); 95 } 96 97 AvailabilityInfo AvailabilityInfo::createFromDecl(const Decl *D) { 98 AvailabilitySet Availabilities; 99 // Walk DeclContexts upwards starting from D to find the combined availability 100 // 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 clang 120