|
22 | 22 | #include "swift/AST/AvailabilityInference.h"
|
23 | 23 | #include "swift/AST/AvailabilityRange.h"
|
24 | 24 | #include "swift/AST/Decl.h"
|
| 25 | +// FIXME: [availability] Remove this when possible |
| 26 | +#include "swift/AST/DiagnosticsParse.h" |
| 27 | +#include "swift/AST/DiagnosticsSema.h" |
25 | 28 | #include "swift/AST/PlatformKind.h"
|
26 | 29 | #include "swift/AST/TypeCheckRequests.h"
|
27 | 30 | #include "swift/AST/TypeWalker.h"
|
@@ -794,6 +797,143 @@ bool AvailabilityInference::isAvailableAsSPI(const Decl *D) {
|
794 | 797 | return false;
|
795 | 798 | }
|
796 | 799 |
|
| 800 | +static std::optional<AvailabilityDomain> |
| 801 | +getAvailabilityDomainForName(Identifier identifier, |
| 802 | + const DeclContext *declContext) { |
| 803 | + if (auto builtinDomain = AvailabilityDomain::builtinDomainForString( |
| 804 | + identifier.str(), declContext)) |
| 805 | + return builtinDomain; |
| 806 | + |
| 807 | + auto &ctx = declContext->getASTContext(); |
| 808 | + if (auto customDomain = |
| 809 | + ctx.MainModule->getAvailabilityDomainForIdentifier(identifier)) |
| 810 | + return customDomain; |
| 811 | + |
| 812 | + return std::nullopt; |
| 813 | +} |
| 814 | + |
| 815 | +std::optional<SemanticAvailableAttr> |
| 816 | +SemanticAvailableAttrRequest::evaluate(swift::Evaluator &evaluator, |
| 817 | + const AvailableAttr *attr, |
| 818 | + const Decl *decl) const { |
| 819 | + if (attr->hasCachedDomain()) |
| 820 | + return SemanticAvailableAttr(attr); |
| 821 | + |
| 822 | + auto &ctx = decl->getASTContext(); |
| 823 | + auto &diags = ctx.Diags; |
| 824 | + auto attrLoc = attr->getLocation(); |
| 825 | + auto attrName = attr->getAttrName(); |
| 826 | + auto domainLoc = attr->getDomainLoc(); |
| 827 | + auto introducedVersion = attr->getRawIntroduced(); |
| 828 | + auto deprecatedVersion = attr->getRawDeprecated(); |
| 829 | + auto obsoletedVersion = attr->getRawObsoleted(); |
| 830 | + auto mutableAttr = const_cast<AvailableAttr *>(attr); |
| 831 | + auto domain = attr->getCachedDomain(); |
| 832 | + |
| 833 | + if (!domain) { |
| 834 | + auto domainIdentifier = attr->getDomainIdentifier(); |
| 835 | + ASSERT(domainIdentifier); |
| 836 | + |
| 837 | + // Attempt to resolve the domain specified for the attribute and diagnose |
| 838 | + // if no domain is found. |
| 839 | + auto declContext = decl->getInnermostDeclContext(); |
| 840 | + domain = getAvailabilityDomainForName(*domainIdentifier, declContext); |
| 841 | + if (!domain) { |
| 842 | + auto domainString = domainIdentifier->str(); |
| 843 | + if (auto suggestion = closestCorrectedPlatformString(domainString)) { |
| 844 | + diags |
| 845 | + .diagnose(domainLoc, diag::attr_availability_suggest_platform, |
| 846 | + domainString, attrName, *suggestion) |
| 847 | + .fixItReplace(SourceRange(domainLoc), *suggestion); |
| 848 | + } else { |
| 849 | + diags.diagnose(attrLoc, diag::attr_availability_unknown_platform, |
| 850 | + domainString, attrName); |
| 851 | + } |
| 852 | + return std::nullopt; |
| 853 | + } |
| 854 | + |
| 855 | + if (domain->isCustom() && |
| 856 | + !ctx.LangOpts.hasFeature(Feature::CustomAvailability) && |
| 857 | + !declContext->isInSwiftinterface()) { |
| 858 | + diags.diagnose(domainLoc, |
| 859 | + diag::attr_availability_requires_custom_availability, |
| 860 | + domain->getNameForAttributePrinting(), attr); |
| 861 | + return std::nullopt; |
| 862 | + } |
| 863 | + |
| 864 | + mutableAttr->setCachedDomain(*domain); |
| 865 | + } |
| 866 | + |
| 867 | + auto domainName = domain->getNameForAttributePrinting(); |
| 868 | + auto semanticAttr = SemanticAvailableAttr(attr); |
| 869 | + |
| 870 | + bool hasVersionSpec = |
| 871 | + (introducedVersion || deprecatedVersion || obsoletedVersion); |
| 872 | + |
| 873 | + if (!domain->isVersioned() && hasVersionSpec) { |
| 874 | + SourceRange versionSourceRange; |
| 875 | + if (introducedVersion) |
| 876 | + versionSourceRange = semanticAttr.getIntroducedSourceRange(); |
| 877 | + else if (deprecatedVersion) |
| 878 | + versionSourceRange = semanticAttr.getDeprecatedSourceRange(); |
| 879 | + else if (obsoletedVersion) |
| 880 | + versionSourceRange = semanticAttr.getObsoletedSourceRange(); |
| 881 | + |
| 882 | + diags |
| 883 | + .diagnose(attrLoc, diag::attr_availability_unexpected_version, attr, |
| 884 | + domainName) |
| 885 | + .highlight(versionSourceRange); |
| 886 | + return std::nullopt; |
| 887 | + } |
| 888 | + |
| 889 | + if (domain->isSwiftLanguage() || domain->isPackageDescription()) { |
| 890 | + switch (attr->getKind()) { |
| 891 | + case AvailableAttr::Kind::Deprecated: |
| 892 | + diags.diagnose(attrLoc, |
| 893 | + diag::attr_availability_expected_deprecated_version, |
| 894 | + attrName, domainName); |
| 895 | + return std::nullopt; |
| 896 | + |
| 897 | + case AvailableAttr::Kind::Unavailable: |
| 898 | + diags.diagnose(attrLoc, diag::attr_availability_cannot_be_used_for_domain, |
| 899 | + "unavailable", attrName, domainName); |
| 900 | + return std::nullopt; |
| 901 | + |
| 902 | + case AvailableAttr::Kind::NoAsync: |
| 903 | + diags.diagnose(attrLoc, diag::attr_availability_cannot_be_used_for_domain, |
| 904 | + "noasync", attrName, domainName); |
| 905 | + return std::nullopt; |
| 906 | + |
| 907 | + case AvailableAttr::Kind::Default: |
| 908 | + break; |
| 909 | + } |
| 910 | + |
| 911 | + if (!hasVersionSpec) { |
| 912 | + diags.diagnose(attrLoc, diag::attr_availability_expected_version_spec, |
| 913 | + attrName, domainName); |
| 914 | + return std::nullopt; |
| 915 | + } |
| 916 | + } |
| 917 | + |
| 918 | + // Canonicalize platform versions. |
| 919 | + // FIXME: [availability] This should be done when remapping versions instead. |
| 920 | + if (domain->isPlatform()) { |
| 921 | + auto canonicalizeVersion = [&](llvm::VersionTuple version) { |
| 922 | + return canonicalizePlatformVersion(domain->getPlatformKind(), version); |
| 923 | + }; |
| 924 | + if (introducedVersion) |
| 925 | + mutableAttr->setRawIntroduced(canonicalizeVersion(*introducedVersion)); |
| 926 | + |
| 927 | + if (deprecatedVersion) |
| 928 | + mutableAttr->setRawDeprecated(canonicalizeVersion(*deprecatedVersion)); |
| 929 | + |
| 930 | + if (obsoletedVersion) |
| 931 | + mutableAttr->setRawObsoleted(canonicalizeVersion(*obsoletedVersion)); |
| 932 | + } |
| 933 | + |
| 934 | + return semanticAttr; |
| 935 | +} |
| 936 | + |
797 | 937 | AvailabilityRange
|
798 | 938 | SemanticAvailableAttr::getIntroducedRange(const ASTContext &Ctx) const {
|
799 | 939 | assert(getDomain().isActive(Ctx));
|
|
0 commit comments