diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index 2526c006a76f2..18260e30bdecd 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -33,6 +33,7 @@ template class ArrayRef; } namespace swift { +class AvailabilityDomain; class Argument; class ASTContext; struct ASTNode; @@ -65,6 +66,23 @@ class BridgedCanType; class BridgedASTContext; struct BridgedSubstitutionMap; class BridgedParameterList; +enum BridgedPlatformKind : size_t; + +// Forward declare the underlying AST node type for each wrapper. +namespace swift { +#define AST_BRIDGING_WRAPPER(Name) class Name; +#include "swift/AST/ASTBridgingWrappers.def" +} // end namespace swift + +// Define the bridging wrappers for each AST node. +#define AST_BRIDGING_WRAPPER(Name) BRIDGING_WRAPPER_NONNULL(swift::Name, Name) +#include "swift/AST/ASTBridgingWrappers.def" + +// For nullable nodes, also define a nullable variant. +#define AST_BRIDGING_WRAPPER_NULLABLE(Name) \ + BRIDGING_WRAPPER_NULLABLE(swift::Name, Name) +#define AST_BRIDGING_WRAPPER_NONNULL(Name) +#include "swift/AST/ASTBridgingWrappers.def" //===----------------------------------------------------------------------===// // MARK: Identifier @@ -282,6 +300,10 @@ SWIFT_NAME("BridgedASTContext.langOptsGetCompilerVersion(self:_:)") SwiftInt BridgedASTContext_langOptsGetCompilerVersion(BridgedASTContext cContext, SwiftInt* _Nullable * _Nonnull cComponents); +SWIFT_NAME("getter:BridgedASTContext.availabilityMacroMap(self:)") +BridgedAvailabilityMacroMap +BridgedASTContext_getAvailabilityMacroMap(BridgedASTContext cContext); + /* Deallocate an array of Swift int values that was allocated in C++. */ void deallocateIntBuffer(SwiftInt * _Nullable cComponents); @@ -354,22 +376,6 @@ struct BridgedASTNode { BRIDGED_INLINE swift::ASTNode unbridged() const; }; -// Forward declare the underlying AST node type for each wrapper. -namespace swift { -#define AST_BRIDGING_WRAPPER(Name) class Name; -#include "swift/AST/ASTBridgingWrappers.def" -} // end namespace swift - -// Define the bridging wrappers for each AST node. -#define AST_BRIDGING_WRAPPER(Name) BRIDGING_WRAPPER_NONNULL(swift::Name, Name) -#include "swift/AST/ASTBridgingWrappers.def" - -// For nullable nodes, also define a nullable variant. -#define AST_BRIDGING_WRAPPER_NULLABLE(Name) \ - BRIDGING_WRAPPER_NULLABLE(swift::Name, Name) -#define AST_BRIDGING_WRAPPER_NONNULL(Name) -#include "swift/AST/ASTBridgingWrappers.def" - // Declare `.asDecl` on each BridgedXXXDecl type, which upcasts a wrapper for // a Decl subclass to a BridgedDecl. #define DECL(Id, Parent) \ @@ -565,6 +571,120 @@ SWIFT_NAME("getter:BridgedClosureExpr.asDeclContext(self:)") BridgedDeclContext BridgedClosureExpr_asDeclContext(BridgedClosureExpr cClosure); +//===----------------------------------------------------------------------===// +// MARK: Availability +//===----------------------------------------------------------------------===// + +enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedPlatformKind : size_t { + BridgedPlatformKind_None, +#define AVAILABILITY_PLATFORM(X, PrettyName) BridgedPlatformKind_##X, +#include "swift/AST/PlatformKinds.def" +}; + +SWIFT_NAME("BridgedPlatformKind.init(from:)") +BridgedPlatformKind BridgedPlatformKind_fromString(BridgedStringRef cStr); + +SWIFT_NAME("BridgedAvailabilityMacroMap.has(self:name:)") +bool BridgedAvailabilityMacroMap_hasName(BridgedAvailabilityMacroMap map, + BridgedStringRef name); + +SWIFT_NAME("BridgedAvailabilityMacroMap.has(self:name:version:)") +bool BridgedAvailabilityMacroMap_hasNameAndVersion( + BridgedAvailabilityMacroMap map, BridgedStringRef name, + BridgedVersionTuple version); + +SWIFT_NAME("BridgedAvailabilityMacroMap.get(self:name:version:)") +BridgedArrayRef +BridgedAvailabilityMacroMap_getSpecs(BridgedAvailabilityMacroMap map, + BridgedStringRef name, + BridgedVersionTuple version); + +struct BridgedAvailabilityMacroDefinition { + BridgedStringRef name; + BridgedVersionTuple version; + BridgedArrayRef specs; +}; + +enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedAvailabilitySpecKind { + BridgedAvailabilitySpecKindPlatformVersionConstraint, + BridgedAvailabilitySpecKindOtherPlatform, + BridgedAvailabilitySpecKindLanguageVersionConstraint, + BridgedAvailabilitySpecKindPackageDescriptionVersionConstraint, +}; + +struct BridgedAvailabilityDomain; + +SWIFT_NAME("getter:BridgedAvailabilitySpec.sourceRange(self:)") +BridgedSourceRange +BridgedAvailabilitySpec_getSourceRange(BridgedAvailabilitySpec spec); + +SWIFT_NAME("getter:BridgedAvailabilitySpec.domain(self:)") +BridgedAvailabilityDomain +BridgedAvailabilitySpec_getDomain(BridgedAvailabilitySpec spec); + +SWIFT_NAME("getter:BridgedAvailabilitySpec.version(self:)") +BridgedVersionTuple +BridgedAvailabilitySpec_getVersion(BridgedAvailabilitySpec spec); + +SWIFT_NAME("getter:BridgedAvailabilitySpec.versionRange(self:)") +BridgedSourceRange +BridgedAvailabilitySpec_getVersionRange(BridgedAvailabilitySpec spec); + +SWIFT_NAME("BridgedPlatformVersionConstraintAvailabilitySpec.createParsed(_:" + "platform:platformLoc:version:runtimeVersion:versionRange:)") +BridgedPlatformVersionConstraintAvailabilitySpec +BridgedPlatformVersionConstraintAvailabilitySpec_createParsed( + BridgedASTContext cContext, BridgedPlatformKind cPlatform, + BridgedSourceLoc cPlatformLoc, BridgedVersionTuple cVersion, + BridgedVersionTuple cRuntimeVersion, BridgedSourceRange cVersionSrcRange); + +SWIFT_NAME("BridgedPlatformAgnosticVersionConstraintAvailabilitySpec." + "createParsed(_:kind:nameLoc:version:versionRange:)") +BridgedPlatformAgnosticVersionConstraintAvailabilitySpec +BridgedPlatformAgnosticVersionConstraintAvailabilitySpec_createParsed( + BridgedASTContext cContext, BridgedAvailabilitySpecKind cKind, + BridgedSourceLoc cNameLoc, BridgedVersionTuple cVersion, + BridgedSourceRange cVersionSrcRange); + +SWIFT_NAME("BridgedOtherPlatformAvailabilitySpec.createParsed(_:loc:)") +BridgedOtherPlatformAvailabilitySpec +BridgedOtherPlatformAvailabilitySpec_createParsed(BridgedASTContext cContext, + BridgedSourceLoc cLoc); + +SWIFT_NAME("getter:BridgedPlatformVersionConstraintAvailabilitySpec." + "asAvailabilitySpec(self:)") +BridgedAvailabilitySpec +BridgedPlatformVersionConstraintAvailabilitySpec_asAvailabilitySpec( + BridgedPlatformVersionConstraintAvailabilitySpec spec); + +SWIFT_NAME("getter:BridgedPlatformAgnosticVersionConstraintAvailabilitySpec." + "asAvailabilitySpec(self:)") +BridgedAvailabilitySpec +BridgedPlatformAgnosticVersionConstraintAvailabilitySpec_asAvailabilitySpec( + BridgedPlatformAgnosticVersionConstraintAvailabilitySpec spec); + +SWIFT_NAME( + "getter:BridgedOtherPlatformAvailabilitySpec.asAvailabilitySpec(self:)") +BridgedAvailabilitySpec BridgedOtherPlatformAvailabilitySpec_asAvailabilitySpec( + BridgedOtherPlatformAvailabilitySpec spec); + +struct BridgedAvailabilityDomain { + void *_Nullable opaque; + + BridgedAvailabilityDomain() : opaque(nullptr) {}; + BRIDGED_INLINE BridgedAvailabilityDomain(swift::AvailabilityDomain domain); + BRIDGED_INLINE swift::AvailabilityDomain unbridged() const; + + BRIDGED_INLINE static BridgedAvailabilityDomain forUniversal(); + BRIDGED_INLINE static BridgedAvailabilityDomain + forPlatform(BridgedPlatformKind platformKind); + BRIDGED_INLINE static BridgedAvailabilityDomain forSwiftLanguage(); + BRIDGED_INLINE static BridgedAvailabilityDomain forPackageDescription(); + BRIDGED_INLINE static BridgedAvailabilityDomain forEmbedded(); + + bool isNull() const { return opaque == nullptr; }; +}; + //===----------------------------------------------------------------------===// // MARK: DeclAttributes //===----------------------------------------------------------------------===// @@ -581,7 +701,7 @@ BridgedDeclAttrKind BridgedDeclAttrKind_fromString(BridgedStringRef cStr); struct BridgedDeclAttributes { BridgedNullableDeclAttribute chain; - BridgedDeclAttributes() : chain(nullptr){}; + BridgedDeclAttributes() : chain(nullptr) {}; BRIDGED_INLINE BridgedDeclAttributes(swift::DeclAttributes attrs); @@ -598,9 +718,43 @@ BridgedDeclAttribute BridgedDeclAttribute_createSimple( BridgedSourceLoc cAtLoc, BridgedSourceLoc cNameLoc); SWIFT_NAME("BridgedABIAttr.createParsed(_:atLoc:range:abiDecl:)") -BridgedABIAttr BridgedABIAttr_createParsed( - BridgedASTContext cContext, BridgedSourceLoc atLoc, - BridgedSourceRange range, BridgedNullableDecl abiDecl); +BridgedABIAttr BridgedABIAttr_createParsed(BridgedASTContext cContext, + BridgedSourceLoc atLoc, + BridgedSourceRange range, + BridgedNullableDecl abiDecl); + +enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedAvailableAttrKind { + BridgedAvailableAttrKindDefault, + BridgedAvailableAttrKindDeprecated, + BridgedAvailableAttrKindUnavailable, + BridgedAvailableAttrKindNoAsync, +}; + +SWIFT_NAME( + "BridgedAvailableAttr.createParsed(_:atLoc:range:domain:domainLoc:kind:message:" + "renamed:introduced:introducedRange:deprecated:deprecatedRange:" + "obsoleted:obsoletedRange:)") +BridgedAvailableAttr BridgedAvailableAttr_createParsed( + BridgedASTContext cContext, BridgedSourceLoc cAtLoc, + BridgedSourceRange cRange, BridgedAvailabilityDomain cDomain, BridgedSourceLoc cDomainLoc, + BridgedAvailableAttrKind cKind, BridgedStringRef cMessage, + BridgedStringRef cRenamed, BridgedVersionTuple cIntroduced, + BridgedSourceRange cIntroducedRange, BridgedVersionTuple cDeprecated, + BridgedSourceRange cDeprecatedRange, BridgedVersionTuple cObsoleted, + BridgedSourceRange cObsoletedRange); + +SWIFT_NAME( + "BridgedAvailableAttr.createParsed(_:atLoc:range:domainString:domainLoc:kind:message:" + "renamed:introduced:introducedRange:deprecated:deprecatedRange:" + "obsoleted:obsoletedRange:)") +BridgedAvailableAttr BridgedAvailableAttr_createParsedStr( + BridgedASTContext cContext, BridgedSourceLoc cAtLoc, + BridgedSourceRange cRange, BridgedStringRef cDomainString, BridgedSourceLoc cDomainLoc, + BridgedAvailableAttrKind cKind, BridgedStringRef cMessage, + BridgedStringRef cRenamed, BridgedVersionTuple cIntroduced, + BridgedSourceRange cIntroducedRange, BridgedVersionTuple cDeprecated, + BridgedSourceRange cDeprecatedRange, BridgedVersionTuple cObsoleted, + BridgedSourceRange cObsoletedRange); enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedExecutionKind { BridgedExecutionKindConcurrent, diff --git a/include/swift/AST/ASTBridgingImpl.h b/include/swift/AST/ASTBridgingImpl.h index 51e989c1f80a9..337c1be509f97 100644 --- a/include/swift/AST/ASTBridgingImpl.h +++ b/include/swift/AST/ASTBridgingImpl.h @@ -15,6 +15,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/ArgumentList.h" +#include "swift/AST/AvailabilityDomain.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" #include "swift/AST/IfConfigClauseRangeInfo.h" @@ -236,6 +237,14 @@ swift::DeclAttributes BridgedDeclAttributes::unbridged() const { return attrs; } +BridgedAvailabilityDomain::BridgedAvailabilityDomain( + swift::AvailabilityDomain domain) + : opaque(domain.getOpaqueValue()) {} + +swift::AvailabilityDomain BridgedAvailabilityDomain::unbridged() const { + return swift::AvailabilityDomain::fromOpaque(opaque); +} + //===----------------------------------------------------------------------===// // MARK: BridgedParamDecl //===----------------------------------------------------------------------===// diff --git a/include/swift/AST/ASTBridgingWrappers.def b/include/swift/AST/ASTBridgingWrappers.def index 7057a75d47eb2..c2fc6c7d24c70 100644 --- a/include/swift/AST/ASTBridgingWrappers.def +++ b/include/swift/AST/ASTBridgingWrappers.def @@ -87,6 +87,11 @@ AST_BRIDGING_WRAPPER_NULLABLE(CustomAttributeInitializer) AST_BRIDGING_WRAPPER_NONNULL(TypeAttributes) AST_BRIDGING_WRAPPER_NONNULL(CustomAttribute) AST_BRIDGING_WRAPPER_NULLABLE(ArgumentList) +AST_BRIDGING_WRAPPER_NULLABLE(AvailabilitySpec) +AST_BRIDGING_WRAPPER_NULLABLE(PlatformVersionConstraintAvailabilitySpec) +AST_BRIDGING_WRAPPER_NULLABLE(PlatformAgnosticVersionConstraintAvailabilitySpec) +AST_BRIDGING_WRAPPER_NULLABLE(OtherPlatformAvailabilitySpec) +AST_BRIDGING_WRAPPER_NONNULL(AvailabilityMacroMap) // Non-AST types to generate wrappers for. AST_BRIDGING_WRAPPER_NULLABLE(DiagnosticEngine) diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index f440dd7760248..97b9a7b1a5ed9 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -996,11 +996,8 @@ class ASTContext final { return getMultiPayloadEnumTagSinglePayloadAvailability(); } - /// Cache of the availability macros parsed from the command line arguments. - /// - /// This is an implementation detail, access via - /// \c Parser::parseAllAvailabilityMacroArguments. - AvailabilityMacroMap &getAvailabilityMacroCache() const; + /// Availability macros parsed from the command line arguments. + const AvailabilityMacroMap &getAvailabilityMacroMap() const; /// Test support utility for loading a platform remap file /// in case an SDK is not specified to the compilation. diff --git a/include/swift/AST/AvailabilityDomain.h b/include/swift/AST/AvailabilityDomain.h index 5043b36afe66a..bc276414c55a3 100644 --- a/include/swift/AST/AvailabilityDomain.h +++ b/include/swift/AST/AvailabilityDomain.h @@ -112,12 +112,6 @@ class AvailabilityDomain final { AvailabilityDomain(Storage storage) : storage(storage) {}; - static AvailabilityDomain fromOpaque(void *opaque) { - return AvailabilityDomain(Storage::getFromOpaqueValue(opaque)); - } - - void *getOpaqueValue() const { return storage.getOpaqueValue(); } - std::optional getInlineDomain() const { return storage.is() ? static_cast>( @@ -161,6 +155,12 @@ class AvailabilityDomain final { static std::optional builtinDomainForString(StringRef string, const DeclContext *declContext); + static AvailabilityDomain fromOpaque(void *opaque) { + return AvailabilityDomain(Storage::getFromOpaqueValue(opaque)); + } + + void *getOpaqueValue() const { return storage.getOpaqueValue(); } + Kind getKind() const { if (auto inlineDomain = getInlineDomain()) return inlineDomain->getKind(); diff --git a/include/swift/AST/AvailabilitySpec.h b/include/swift/AST/AvailabilitySpec.h index 1a50d9eb3258d..7ccbf52bd0e2a 100644 --- a/include/swift/AST/AvailabilitySpec.h +++ b/include/swift/AST/AvailabilitySpec.h @@ -17,14 +17,17 @@ #ifndef SWIFT_AST_AVAILABILITY_SPEC_H #define SWIFT_AST_AVAILABILITY_SPEC_H +#include "swift/AST/ASTAllocated.h" #include "swift/AST/Identifier.h" #include "swift/AST/PlatformKind.h" #include "swift/Basic/SourceLoc.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringMap.h" #include "llvm/Support/VersionTuple.h" namespace swift { class ASTContext; +class AvailabilityDomain; enum class VersionComparison { GreaterThanEqual }; @@ -54,6 +57,12 @@ class AvailabilitySpec : public ASTAllocated { AvailabilitySpecKind getKind() const { return Kind; } SourceRange getSourceRange() const; + + std::optional getDomain() const; + + llvm::VersionTuple getVersion() const; + + SourceRange getVersionSrcRange() const; }; /// An availability specification that guards execution based on the @@ -222,11 +231,40 @@ class OtherPlatformAvailabilitySpec : public AvailabilitySpec { /// parsing a version tuple. class AvailabilityMacroMap { public: - typedef llvm::DenseMap> VersionEntry; + typedef llvm::DenseMap> + VersionEntry; + llvm::StringMap Impl; + + bool hasMacroName(StringRef name) const { + return Impl.find(name) != Impl.end(); + } - bool WasParsed = false; - llvm::DenseMap Impl; + bool hasMacroNameVersion(StringRef name, llvm::VersionTuple version) const { + auto entry = Impl.find(name); + if (entry == Impl.end()) { + return false; + } + return entry->second.find(version) != entry->second.end(); + } + + void addEntry(StringRef name, llvm::VersionTuple version, + ArrayRef specs) { + assert(!hasMacroNameVersion(name, version)); + Impl[name][version].assign(specs.begin(), specs.end()); + } + + ArrayRef getEntry(StringRef name, + llvm::VersionTuple version) { + auto versions = Impl.find(name); + if (versions == Impl.end()) { + return {}; + } + auto entry = versions->second.find(version); + if (entry == versions->second.end()) { + return {}; + } + return entry->second; + } }; } // end namespace swift diff --git a/include/swift/AST/ParseRequests.h b/include/swift/AST/ParseRequests.h index 696caf9567678..fa34438fdf85f 100644 --- a/include/swift/AST/ParseRequests.h +++ b/include/swift/AST/ParseRequests.h @@ -25,6 +25,7 @@ namespace swift { struct ASTNode; +class AvailabilityMacroMap; /// Report that a request of the given kind is being evaluated, so it /// can be recorded by the stats reporter. @@ -192,6 +193,30 @@ class EvaluateIfConditionRequest bool shouldEvaluate) const; }; +/// Parse the '-define-availability' arguments. +class AvailabilityMacroArgumentsRequest + : public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + AvailabilityMacroMap *evaluate(Evaluator &evaluator, ASTContext *ctx) const; + +public: + // Caching. + bool isCached() const { return true; } + + // Source location. + SourceLoc getNearestLoc() const { return SourceLoc(); }; +}; + +void simple_display(llvm::raw_ostream &out, const ASTContext *state); + /// The zone number for the parser. #define SWIFT_TYPEID_ZONE Parse #define SWIFT_TYPEID_HEADER "swift/AST/ParseTypeIDZone.def" diff --git a/include/swift/AST/ParseTypeIDZone.def b/include/swift/AST/ParseTypeIDZone.def index 210c4bd42345c..12a63f6df4513 100644 --- a/include/swift/AST/ParseTypeIDZone.def +++ b/include/swift/AST/ParseTypeIDZone.def @@ -34,3 +34,6 @@ SWIFT_REQUEST(Parse, ExportedSourceFileRequest, SWIFT_REQUEST(Parse, EvaluateIfConditionRequest, (std::pair)(SourceFile *, SourceRange, bool), Uncached, NoLocationInfo) +SWIFT_REQUEST(Parse, AvailabilityMacroArgumentsRequest, + (AvailabilityMacroMap *)(ASTContext *), Cached, + NoLocationInfo) diff --git a/include/swift/Basic/BasicBridging.h b/include/swift/Basic/BasicBridging.h index 207ccc218e200..1f1885dd024a7 100644 --- a/include/swift/Basic/BasicBridging.h +++ b/include/swift/Basic/BasicBridging.h @@ -78,6 +78,7 @@ namespace llvm { class raw_ostream; class StringRef; +class VersionTuple; } // end namespace llvm namespace swift { @@ -163,10 +164,13 @@ class BridgedArrayRef { SWIFT_NAME("getter:BridgedArrayRef.data(self:)") BRIDGED_INLINE -const void *_Nullable BridgedArrayRef_data(BridgedArrayRef arr); +const void *_Nullable BridgedArrayRef_data(const BridgedArrayRef arr); SWIFT_NAME("getter:BridgedArrayRef.count(self:)") -BRIDGED_INLINE SwiftInt BridgedArrayRef_count(BridgedArrayRef arr); +BRIDGED_INLINE SwiftInt BridgedArrayRef_count(const BridgedArrayRef arr); + +SWIFT_NAME("getter:BridgedArrayRef.isEmpty(self:)") +BRIDGED_INLINE bool BridgedArrayRef_isEmpty(const BridgedArrayRef arr); //===----------------------------------------------------------------------===// // MARK: Data @@ -462,6 +466,44 @@ struct BridgedVirtualFile { size_t NamePosition; }; +//===----------------------------------------------------------------------===// +// MARK: VersionTuple +//===----------------------------------------------------------------------===// + +struct BridgedVersionTuple { + unsigned Major : 32; + + unsigned Minor : 31; + unsigned HasMinor : 1; + + unsigned Subminor : 31; + unsigned HasSubminor : 1; + + unsigned Build : 31; + unsigned HasBuild : 1; + + BridgedVersionTuple() + : Major(0), Minor(0), HasMinor(false), Subminor(0), HasSubminor(false), + Build(0), HasBuild(false) {} + BridgedVersionTuple(unsigned Major) + : Major(Major), Minor(0), HasMinor(false), Subminor(0), + HasSubminor(false), Build(0), HasBuild(false) {} + BridgedVersionTuple(unsigned Major, unsigned Minor) + : Major(Major), Minor(Minor), HasMinor(true), Subminor(0), + HasSubminor(false), Build(0), HasBuild(false) {} + BridgedVersionTuple(unsigned Major, unsigned Minor, unsigned Subminor) + : Major(Major), Minor(Minor), HasMinor(true), Subminor(Subminor), + HasSubminor(true), Build(0), HasBuild(false) {} + BridgedVersionTuple(unsigned Major, unsigned Minor, unsigned Subminor, + unsigned Build) + : Major(Major), Minor(Minor), HasMinor(true), Subminor(Subminor), + HasSubminor(true), Build(Build), HasBuild(true) {} + + BridgedVersionTuple(llvm::VersionTuple); + + llvm::VersionTuple unbridged() const; +}; + SWIFT_END_NULLABILITY_ANNOTATIONS #ifndef PURE_BRIDGING_MODE diff --git a/include/swift/Basic/BasicBridgingImpl.h b/include/swift/Basic/BasicBridgingImpl.h index b25d694fb05e2..b627d3bbf5f20 100644 --- a/include/swift/Basic/BasicBridgingImpl.h +++ b/include/swift/Basic/BasicBridgingImpl.h @@ -14,6 +14,8 @@ #define SWIFT_BASIC_BASICBRIDGINGIMPL_H #include "swift/Basic/Assertions.h" +#include "swift/Basic/SourceLoc.h" +#include "llvm/ADT/StringRef.h" SWIFT_BEGIN_NULLABILITY_ANNOTATIONS @@ -21,14 +23,18 @@ SWIFT_BEGIN_NULLABILITY_ANNOTATIONS // MARK: BridgedArrayRef //===----------------------------------------------------------------------===// -const void *_Nullable BridgedArrayRef_data(BridgedArrayRef arr) { +const void *_Nullable BridgedArrayRef_data(const BridgedArrayRef arr) { return arr.Data; } -SwiftInt BridgedArrayRef_count(BridgedArrayRef arr) { +SwiftInt BridgedArrayRef_count(const BridgedArrayRef arr) { return static_cast(arr.Length); } +bool BridgedArrayRef_isEmpty(const BridgedArrayRef arr) { + return arr.Length == 0; +} + //===----------------------------------------------------------------------===// // MARK: BridgedData //===----------------------------------------------------------------------===// diff --git a/include/swift/Bridging/ASTGen.h b/include/swift/Bridging/ASTGen.h index 50f4c8e310b5f..5524c8949ae2e 100644 --- a/include/swift/Bridging/ASTGen.h +++ b/include/swift/Bridging/ASTGen.h @@ -111,6 +111,14 @@ swift_ASTGen_virtualFiles(void *_Nonnull sourceFile, void swift_ASTGen_freeBridgedVirtualFiles( BridgedVirtualFile *_Nullable virtualFiles, size_t numFiles); +bool swift_ASTGen_parseAvailabilityMacroDefinition( + BridgedASTContext ctx, BridgedDeclContext dc, BridgedDiagnosticEngine diags, + BridgedStringRef buffer, + BridgedAvailabilityMacroDefinition *_Nonnull outPtr); + +void swift_ASTGen_freeAvailabilityMacroDefinition( + BridgedAvailabilityMacroDefinition *_Nonnull definition); + #ifdef __cplusplus } #endif diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 28e9e8764024f..1496f843b057f 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -2047,21 +2047,13 @@ class Parser { ParserStatus parseAvailabilityMacro(SmallVectorImpl &Specs); - /// Parse the availability macros definitions passed as arguments. - AvailabilityMacroMap &parseAllAvailabilityMacroArguments(); - - /// Result of parsing an availability macro definition. - struct AvailabilityMacroDefinition { - StringRef Name; - llvm::VersionTuple Version; - SmallVector Specs; - }; - /// Parse an availability macro definition from a command line argument. - /// This function should be called on a Parser set up on the command line + /// This function should only be called on a Parser set up on the command line /// argument code. ParserStatus - parseAvailabilityMacroDefinition(AvailabilityMacroDefinition &Result); + parseAvailabilityMacroDefinition(std::string &Name, + llvm::VersionTuple &Version, + SmallVectorImpl &Specs); ParserResult parseAvailabilitySpec(); ParserResult diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index d087174ccd522..170c8eba89a70 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -427,9 +427,6 @@ struct ASTContext::Implementation { /// Singleton used to cache the import graph. swift::namelookup::ImportCache TheImportCache; - /// Cache of availability macros parsed from the command line. - AvailabilityMacroMap TheAvailabilityMacroCache; - /// The module loader used to load Clang modules. ClangModuleLoader *TheClangModuleLoader = nullptr; @@ -2297,8 +2294,10 @@ swift::namelookup::ImportCache &ASTContext::getImportCache() const { return getImpl().TheImportCache; } -AvailabilityMacroMap &ASTContext::getAvailabilityMacroCache() const { - return getImpl().TheAvailabilityMacroCache; +const AvailabilityMacroMap &ASTContext::getAvailabilityMacroMap() const { + auto *ctx = const_cast(this); + return *evaluateOrFatal(ctx->evaluator, + AvailabilityMacroArgumentsRequest{ctx}); } ClangModuleLoader *ASTContext::getClangModuleLoader() const { diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 6341a144cfde7..29576e6ac5601 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -4885,8 +4885,12 @@ class PrintAttribute : public AttributeVisitor, void visitAvailableAttr(AvailableAttr *Attr, Label label) { printCommon(Attr, "available_attr", label); - if (auto domain = Attr->getCachedDomain()) - printField(domain->getNameForAttributePrinting(), Label::always("platform")); + if (auto domain = Attr->getCachedDomain()) { + printField(domain->getNameForAttributePrinting(), + Label::always("domain")); + } else { + printField(*Attr->getDomainString(), Label::always("domainString")); + } switch (Attr->getKind()) { case swift::AvailableAttr::Kind::Default: diff --git a/lib/AST/AvailabilitySpec.cpp b/lib/AST/AvailabilitySpec.cpp index 4a555a59d848f..9887e61adbe2c 100644 --- a/lib/AST/AvailabilitySpec.cpp +++ b/lib/AST/AvailabilitySpec.cpp @@ -14,8 +14,9 @@ // //===----------------------------------------------------------------------===// -#include "swift/AST/ASTContext.h" #include "swift/AST/AvailabilitySpec.h" +#include "swift/AST/ASTContext.h" +#include "swift/AST/AvailabilityDomain.h" #include "llvm/Support/raw_ostream.h" using namespace swift; @@ -35,6 +36,56 @@ SourceRange AvailabilitySpec::getSourceRange() const { llvm_unreachable("bad AvailabilitySpecKind"); } +std::optional AvailabilitySpec::getDomain() const { + switch (getKind()) { + case AvailabilitySpecKind::PlatformVersionConstraint: { + auto spec = cast(this); + return AvailabilityDomain::forPlatform(spec->getPlatform()); + } + case AvailabilitySpecKind::LanguageVersionConstraint: + return AvailabilityDomain::forSwiftLanguage(); + case AvailabilitySpecKind::PackageDescriptionVersionConstraint: + return AvailabilityDomain::forPackageDescription(); + case AvailabilitySpecKind::OtherPlatform: + return std::nullopt; + } + llvm_unreachable("bad AvailabilitySpecKind"); +} + +llvm::VersionTuple AvailabilitySpec::getVersion() const { + switch (getKind()) { + case AvailabilitySpecKind::PlatformVersionConstraint: { + auto spec = cast(this); + return spec->getVersion(); + } + case AvailabilitySpecKind::LanguageVersionConstraint: + case AvailabilitySpecKind::PackageDescriptionVersionConstraint: { + auto spec = cast(this); + return spec->getVersion(); + } + case AvailabilitySpecKind::OtherPlatform: + return llvm::VersionTuple(); + } + llvm_unreachable("bad AvailabilitySpecKind"); +} + +SourceRange AvailabilitySpec::getVersionSrcRange() const { + switch (getKind()) { + case AvailabilitySpecKind::PlatformVersionConstraint: { + auto spec = cast(this); + return spec->getVersionSrcRange(); + } + case AvailabilitySpecKind::LanguageVersionConstraint: + case AvailabilitySpecKind::PackageDescriptionVersionConstraint: { + auto spec = cast(this); + return spec->getVersionSrcRange(); + } + case AvailabilitySpecKind::OtherPlatform: + return SourceRange(); + } + llvm_unreachable("bad AvailabilitySpecKind"); +} + SourceRange PlatformVersionConstraintAvailabilitySpec::getSourceRange() const { return SourceRange(PlatformLoc, VersionSrcRange.End); } diff --git a/lib/AST/Bridging/ASTContextBridging.cpp b/lib/AST/Bridging/ASTContextBridging.cpp index 9cd8859c713fd..bb45053b0c209 100644 --- a/lib/AST/Bridging/ASTContextBridging.cpp +++ b/lib/AST/Bridging/ASTContextBridging.cpp @@ -13,6 +13,7 @@ #include "swift/AST/ASTBridging.h" #include "swift/AST/ASTContext.h" +#include "swift/AST/AvailabilitySpec.h" using namespace swift; @@ -167,3 +168,9 @@ bool BridgedASTContext_canImport(BridgedASTContext cContext, builder.get(), canImportLoc.unbridged(), version, versionKind == CanImportUnderlyingVersion); } + +BridgedAvailabilityMacroMap +BridgedASTContext_getAvailabilityMacroMap(BridgedASTContext cContext) { + return const_cast( + &cContext.unbridged().getAvailabilityMacroMap()); +} diff --git a/lib/AST/Bridging/AvailabilityBridging.cpp b/lib/AST/Bridging/AvailabilityBridging.cpp new file mode 100644 index 0000000000000..b5a3f3de0cd30 --- /dev/null +++ b/lib/AST/Bridging/AvailabilityBridging.cpp @@ -0,0 +1,178 @@ +//===--- Bridging/AvailabilityBridging.cpp --------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "swift/AST/ASTBridging.h" +#include "swift/AST/AvailabilitySpec.h" +#include "swift/AST/PlatformKind.h" + +using namespace swift; + +//===----------------------------------------------------------------------===// +// MARK: BridgedAvailabilityMacroMap +//===----------------------------------------------------------------------===// + +bool BridgedAvailabilityMacroMap_hasName(BridgedAvailabilityMacroMap map, + BridgedStringRef name) { + return map.unbridged()->hasMacroName(name.unbridged()); +} + +bool BridgedAvailabilityMacroMap_hasNameAndVersion( + BridgedAvailabilityMacroMap map, BridgedStringRef name, + BridgedVersionTuple version) { + return map.unbridged()->hasMacroNameVersion(name.unbridged(), + version.unbridged()); +} + +BridgedArrayRef +BridgedAvailabilityMacroMap_getSpecs(BridgedAvailabilityMacroMap map, + BridgedStringRef name, + BridgedVersionTuple version) { + return map.unbridged()->getEntry(name.unbridged(), version.unbridged()); +} + +//===----------------------------------------------------------------------===// +// MARK: PlatformKind +//===----------------------------------------------------------------------===// + +BridgedPlatformKind BridgedPlatformKind_fromString(BridgedStringRef cStr) { + auto optKind = platformFromString(cStr.unbridged()); + if (!optKind) + return BridgedPlatformKind_None; + + switch (*optKind) { + case PlatformKind::none: + return BridgedPlatformKind_None; +#define AVAILABILITY_PLATFORM(X, PrettyName) \ + case PlatformKind::X: \ + return BridgedPlatformKind_##X; +#include "swift/AST/PlatformKinds.def" + } +} + +static PlatformKind unbridge(BridgedPlatformKind platform) { + switch (platform) { + case BridgedPlatformKind_None: + return PlatformKind::none; +#define AVAILABILITY_PLATFORM(X, PrettyName) \ + case BridgedPlatformKind_##X: \ + return PlatformKind::X; +#include "swift/AST/PlatformKinds.def" + } + llvm_unreachable("unhandled enum value"); +} + +//===----------------------------------------------------------------------===// +// MARK: AvailabilitySpec +//===----------------------------------------------------------------------===// + +BridgedSourceRange +BridgedAvailabilitySpec_getSourceRange(BridgedAvailabilitySpec spec) { + return spec.unbridged()->getSourceRange(); +} + +BridgedAvailabilityDomain +BridgedAvailabilitySpec_getDomain(BridgedAvailabilitySpec spec) { + auto domain = spec.unbridged()->getDomain(); + if (domain) + return *domain; + return BridgedAvailabilityDomain(); +} + +BridgedVersionTuple +BridgedAvailabilitySpec_getVersion(BridgedAvailabilitySpec spec) { + return spec.unbridged()->getVersion(); +} + +BridgedSourceRange +BridgedAvailabilitySpec_getVersionRange(BridgedAvailabilitySpec spec) { + return spec.unbridged()->getVersionSrcRange(); +} + +static AvailabilitySpecKind unbridge(BridgedAvailabilitySpecKind kind) { + switch (kind) { + case BridgedAvailabilitySpecKindPlatformVersionConstraint: + return AvailabilitySpecKind::PlatformVersionConstraint; + case BridgedAvailabilitySpecKindOtherPlatform: + return AvailabilitySpecKind::OtherPlatform; + case BridgedAvailabilitySpecKindLanguageVersionConstraint: + return AvailabilitySpecKind::LanguageVersionConstraint; + case BridgedAvailabilitySpecKindPackageDescriptionVersionConstraint: + return AvailabilitySpecKind::PackageDescriptionVersionConstraint; + } + llvm_unreachable("unhandled enum value"); +} + +BridgedPlatformVersionConstraintAvailabilitySpec +BridgedPlatformVersionConstraintAvailabilitySpec_createParsed( + BridgedASTContext cContext, BridgedPlatformKind cPlatform, + BridgedSourceLoc cPlatformLoc, BridgedVersionTuple cVersion, + BridgedVersionTuple cRuntimeVersion, BridgedSourceRange cVersionSrcRange) { + return new (cContext.unbridged()) PlatformVersionConstraintAvailabilitySpec( + unbridge(cPlatform), cPlatformLoc.unbridged(), cVersion.unbridged(), + cRuntimeVersion.unbridged(), cVersionSrcRange.unbridged()); +} + +BridgedPlatformAgnosticVersionConstraintAvailabilitySpec +BridgedPlatformAgnosticVersionConstraintAvailabilitySpec_createParsed( + BridgedASTContext cContext, BridgedAvailabilitySpecKind cKind, + BridgedSourceLoc cNameLoc, BridgedVersionTuple cVersion, + BridgedSourceRange cVersionSrcRange) { + return new (cContext.unbridged()) + PlatformAgnosticVersionConstraintAvailabilitySpec( + unbridge(cKind), cNameLoc.unbridged(), cVersion.unbridged(), + cVersionSrcRange.unbridged()); +} + +BridgedOtherPlatformAvailabilitySpec +BridgedOtherPlatformAvailabilitySpec_createParsed(BridgedASTContext cContext, + BridgedSourceLoc cLoc) { + return new (cContext.unbridged()) + OtherPlatformAvailabilitySpec(cLoc.unbridged()); +} + +BridgedAvailabilitySpec +BridgedPlatformVersionConstraintAvailabilitySpec_asAvailabilitySpec( + BridgedPlatformVersionConstraintAvailabilitySpec spec) { + return static_cast(spec.unbridged()); +} + +BridgedAvailabilitySpec +BridgedPlatformAgnosticVersionConstraintAvailabilitySpec_asAvailabilitySpec( + BridgedPlatformAgnosticVersionConstraintAvailabilitySpec spec) { + return static_cast(spec.unbridged()); +} + +BridgedAvailabilitySpec BridgedOtherPlatformAvailabilitySpec_asAvailabilitySpec( + BridgedOtherPlatformAvailabilitySpec spec) { + return static_cast(spec.unbridged()); +} + +//===----------------------------------------------------------------------===// +// MARK: AvailabilityDomain +//===----------------------------------------------------------------------===// + +BridgedAvailabilityDomain BridgedAvailabilityDomain::forUniversal() { + return swift::AvailabilityDomain::forUniversal(); +} +BridgedAvailabilityDomain +BridgedAvailabilityDomain::forPlatform(BridgedPlatformKind platformKind) { + return swift::AvailabilityDomain::forPlatform(unbridge(platformKind)); +} +BridgedAvailabilityDomain BridgedAvailabilityDomain::forSwiftLanguage() { + return swift::AvailabilityDomain::forSwiftLanguage(); +} +BridgedAvailabilityDomain BridgedAvailabilityDomain::forPackageDescription() { + return swift::AvailabilityDomain::forPackageDescription(); +} +BridgedAvailabilityDomain BridgedAvailabilityDomain::forEmbedded() { + return swift::AvailabilityDomain::forEmbedded(); +} diff --git a/lib/AST/Bridging/CMakeLists.txt b/lib/AST/Bridging/CMakeLists.txt index 63a5c94170521..277fdaca350a7 100644 --- a/lib/AST/Bridging/CMakeLists.txt +++ b/lib/AST/Bridging/CMakeLists.txt @@ -1,5 +1,6 @@ target_sources(swiftAST PRIVATE ASTContextBridging.cpp + AvailabilityBridging.cpp DeclAttributeBridging.cpp DeclBridging.cpp DeclContextBridging.cpp diff --git a/lib/AST/Bridging/DeclAttributeBridging.cpp b/lib/AST/Bridging/DeclAttributeBridging.cpp index fbabc25f4c7e5..8c0f2d579e915 100644 --- a/lib/AST/Bridging/DeclAttributeBridging.cpp +++ b/lib/AST/Bridging/DeclAttributeBridging.cpp @@ -73,6 +73,58 @@ void BridgedDeclAttributes_add(BridgedDeclAttributes *cAttrs, *cAttrs = attrs; } +static AvailableAttr::Kind unbridge(BridgedAvailableAttrKind value) { + switch (value) { + case BridgedAvailableAttrKindDefault: + return AvailableAttr::Kind::Default; + case BridgedAvailableAttrKindDeprecated: + return AvailableAttr::Kind::Deprecated; + case BridgedAvailableAttrKindUnavailable: + return AvailableAttr::Kind::Unavailable; + case BridgedAvailableAttrKindNoAsync: + return AvailableAttr::Kind::NoAsync; + } + llvm_unreachable("unhandled enum value"); +} + +BridgedAvailableAttr BridgedAvailableAttr_createParsed( + BridgedASTContext cContext, BridgedSourceLoc cAtLoc, + BridgedSourceRange cRange, BridgedAvailabilityDomain cDomain, + BridgedSourceLoc cDomainLoc, BridgedAvailableAttrKind cKind, + BridgedStringRef cMessage, BridgedStringRef cRenamed, + BridgedVersionTuple cIntroduced, BridgedSourceRange cIntroducedRange, + BridgedVersionTuple cDeprecated, BridgedSourceRange cDeprecatedRange, + BridgedVersionTuple cObsoleted, BridgedSourceRange cObsoletedRange) { + return new (cContext.unbridged()) + AvailableAttr(cAtLoc.unbridged(), cRange.unbridged(), cDomain.unbridged(), + cDomainLoc.unbridged(), unbridge(cKind), + cMessage.unbridged(), cRenamed.unbridged(), + cIntroduced.unbridged(), cIntroducedRange.unbridged(), + cDeprecated.unbridged(), cDeprecatedRange.unbridged(), + cObsoleted.unbridged(), cObsoletedRange.unbridged(), + /*Implicit=*/false, + /*IsSPI=*/false); +} + +BridgedAvailableAttr BridgedAvailableAttr_createParsedStr( + BridgedASTContext cContext, BridgedSourceLoc cAtLoc, + BridgedSourceRange cRange, BridgedStringRef cDomainString, + BridgedSourceLoc cDomainLoc, BridgedAvailableAttrKind cKind, + BridgedStringRef cMessage, BridgedStringRef cRenamed, + BridgedVersionTuple cIntroduced, BridgedSourceRange cIntroducedRange, + BridgedVersionTuple cDeprecated, BridgedSourceRange cDeprecatedRange, + BridgedVersionTuple cObsoleted, BridgedSourceRange cObsoletedRange) { + return new (cContext.unbridged()) + AvailableAttr(cAtLoc.unbridged(), cRange.unbridged(), + cDomainString.unbridged(), cDomainLoc.unbridged(), + unbridge(cKind), cMessage.unbridged(), cRenamed.unbridged(), + cIntroduced.unbridged(), cIntroducedRange.unbridged(), + cDeprecated.unbridged(), cDeprecatedRange.unbridged(), + cObsoleted.unbridged(), cObsoletedRange.unbridged(), + /*Implicit=*/false, + /*IsSPI=*/false); +} + static std::optional unbridge(BridgedAccessLevel level) { switch (level) { case BridgedAccessLevelPrivate: @@ -602,4 +654,4 @@ BridgedExecutionAttr BridgedExecutionAttr_createParsed( return new (cContext.unbridged()) ExecutionAttr(atLoc.unbridged(), range.unbridged(), unbridged(behavior), /*implicit=*/false); -} \ No newline at end of file +} diff --git a/lib/AST/Bridging/MiscBridging.cpp b/lib/AST/Bridging/MiscBridging.cpp index 11bf6ab5d4925..0f86071efe221 100644 --- a/lib/AST/Bridging/MiscBridging.cpp +++ b/lib/AST/Bridging/MiscBridging.cpp @@ -121,4 +121,3 @@ BridgedOwnedString BridgedSubstitutionMap::getDebugDescription() const { unbridged().dump(os); return BridgedOwnedString(str); } - diff --git a/lib/ASTGen/Sources/ASTGen/ASTGen.swift b/lib/ASTGen/Sources/ASTGen/ASTGen.swift index 09b0ffcece465..dab2ebf81ce48 100644 --- a/lib/ASTGen/Sources/ASTGen/ASTGen.swift +++ b/lib/ASTGen/Sources/ASTGen/ASTGen.swift @@ -244,6 +244,15 @@ extension ASTGenVisitor { return generateSourceRange(start: start, end: node.lastToken(viewMode: .sourceAccurate)!) } + /// Obtains bridged token source range of a syntax node. + @inline(__always) + func generateSourceRange(_ node: (some SyntaxProtocol)?) -> BridgedSourceRange { + guard let node = node else { + return BridgedSourceRange(start: nil, end: nil) + } + return generateSourceRange(node) + } + /// Obtains bridged character source range. @inline(__always) func generateCharSourceRange(start: AbsolutePosition, length: SourceLength) -> BridgedCharSourceRange { diff --git a/lib/ASTGen/Sources/ASTGen/Availability.swift b/lib/ASTGen/Sources/ASTGen/Availability.swift new file mode 100644 index 0000000000000..5e4a8f49008e2 --- /dev/null +++ b/lib/ASTGen/Sources/ASTGen/Availability.swift @@ -0,0 +1,426 @@ +//===--- Attrs.swift ------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import ASTBridging +import BasicBridging +import SwiftDiagnostics +import SwiftParserDiagnostics +import SwiftIfConfig +@_spi(Compiler) import SwiftParser +@_spi(RawSyntax) @_spi(Compiler) import SwiftSyntax + +extension ASTGenVisitor { + /// E.g.: + /// ``` + /// @available(macOS 10.12, iOS 13, *) + /// @available(macOS, introduced: 10.12) + /// ``` + func generateAvailableAttr(attribute node: AttributeSyntax) -> [BridgedAvailableAttr] { + guard let args = node.arguments else { + self.diagnose(.expectedArgumentsInAttribute(node)) + return [] + } + guard let args = args.as(AvailabilityArgumentListSyntax.self) else { + // TODO: Diagnose. + return [] + } + + // Check if this is "shorthand" syntax. + if let firstArg = args.first?.argument { + // We need to check availability macros specified by '-define-availability'. + let isShorthand: Bool + if let firstToken = firstArg.as(TokenSyntax.self), firstToken.rawTokenKind == .identifier, peekAvailabilityMacroName(firstToken.rawText) { + // @available(myFeature, *) + isShorthand = true + } else if firstArg.is(PlatformVersionSyntax.self) { + // @available(myPlatform 2.7, *) + isShorthand = true + } else { + isShorthand = false + } + if isShorthand { + return self.generateAvailableAttrShorthand(attribute: node) + } + } + + // E.g. + // @available(macOS, introduced: 10.12, deprecated: 11.2) + // @available(*, unavailable, message: "out of service") + if let generated = self.generateAvailableAttrExtended(attribute: node) { + return [generated] + } + return [] + } + + func generate(versionTuple node: VersionTupleSyntax?) -> VersionTuple? { + guard let node, let tuple = VersionTuple(parsing: node.trimmedDescription) else { + return nil + } + return tuple + } + + func generateAvailableAttrShorthand(attribute node: AttributeSyntax) -> [BridgedAvailableAttr] { + let atLoc = self.generateSourceLoc(node.atSign) + let range = self.generateAttrSourceRange(node) + let specs = self.generateAvailabilitySpecList( + args: node.arguments!.cast(AvailabilityArgumentListSyntax.self), + context: .availableAttr + ) + + var result: [BridgedAvailableAttr] = [] + for spec in specs { + let domain = spec.domain + guard !domain.isNull() else { + continue + } + let attr = BridgedAvailableAttr.createParsed( + self.ctx, + atLoc: atLoc, + range: range, + domain: domain, + domainLoc: spec.sourceRange.start, + kind: .default, + message: BridgedStringRef(), + renamed: BridgedStringRef(), + introduced: spec.version, + introducedRange: spec.versionRange, + deprecated: BridgedVersionTuple(), + deprecatedRange: BridgedSourceRange(), + obsoleted: BridgedVersionTuple(), + obsoletedRange: BridgedSourceRange() + ) + result.append(attr) + } + return result + } + + func generateAvailableAttrExtended(attribute node: AttributeSyntax) -> BridgedAvailableAttr? { + var args = node.arguments!.cast(AvailabilityArgumentListSyntax.self)[...] + + // The platfrom. + guard let platformToken = args.popFirst()?.argument.as(TokenSyntax.self) else { + // TODO: Diangose + fatalError("missing first arg") + } + let platformStr = platformToken.rawText + let platformLoc = self.generateSourceLoc(platformToken) + + // Other arguments can be shuffled. + enum Argument: UInt8 { + case message + case renamed + case introduced + case deprecated + case obsoleted + case invalid + } + var argState = AttrArgumentState(.invalid) + var attrKind: BridgedAvailableAttrKind = .default { + willSet { + if attrKind != .default { + fatalError("resetting attribute kind") + } + } + } + + struct VersionAndRange { + let version: VersionTuple + let range: BridgedSourceRange + } + + var introduced: VersionAndRange? = nil + var deprecated: VersionAndRange? = nil + var obsoleted: VersionAndRange? = nil + var message: BridgedStringRef? = nil + var renamed: BridgedStringRef? = nil + + func generateVersion(arg: AvailabilityLabeledArgumentSyntax, into target: inout VersionAndRange?) { + guard let versionSytnax = arg.value.as(VersionTupleSyntax.self) else { + // TODO: Diagnose + fatalError("expected version after introduced, deprecated, or obsoleted") + } + guard let version = VersionTuple(parsing: versionSytnax.trimmedDescription) else { + // TODO: Diagnose + fatalError("invalid version string") + } + if target != nil { + // TODO: Diagnose duplicated. + } + + target = .init(version: version, range: self.generateSourceRange(versionSytnax)) + } + + while let arg = args.popFirst() { + switch arg.argument { + case .availabilityVersionRestriction(_): + fatalError("platformVersion in extended args") + + case .token(let arg): + // 'deprecated', 'unavailable, 'noasync' changes the mode. + switch arg.rawText { + case "deprecated": + attrKind = .deprecated + case "unavailable": + attrKind = .unavailable + case "noasync": + attrKind = .noAsync + default: + // TODO: Diagnose + continue + } + + case .availabilityLabeledArgument(let arg): + switch arg.label.rawText { + case "message": + argState.current = .message + case "renamed": + argState.current = .renamed + case "introduced": + argState.current = .introduced + case "deprecated": + argState.current = .deprecated + case "obsoleted": + argState.current = .obsoleted + default: + argState.current = .invalid + } + + switch argState.current { + case .introduced: + generateVersion(arg: arg, into: &introduced) + case .deprecated: + generateVersion(arg: arg, into: &deprecated) + case .obsoleted: + generateVersion(arg: arg, into: &obsoleted) + case .message: + guard let literal = arg.value.as(SimpleStringLiteralExprSyntax.self) else { + // TODO: Diagnose. + fatalError("invalid argument type for 'message:'") + } + guard let _message = self.generateStringLiteralTextIfNotInterpolated(expr: literal) else { + fatalError("invalid literal value") + } + guard message == nil else { + fatalError("duplicated 'message' argument") + } + message = _message + case .renamed: + guard let literal = arg.value.as(SimpleStringLiteralExprSyntax.self) else { + // TODO: Diagnose. + fatalError("invalid argument type for 'renamed:'") + } + guard let _renamed = self.generateStringLiteralTextIfNotInterpolated(expr: literal) else { + fatalError("invalid literal value") + } + guard renamed == nil else { + fatalError("duplicated 'message' argument") + } + renamed = _renamed + case .invalid: + // TODO: Diagnose + fatalError("invalid labeled argument") + } + } + } + + return BridgedAvailableAttr.createParsed( + self.ctx, + atLoc: self.generateSourceLoc(node.atSign), + range: self.generateAttrSourceRange(node), + domainString: platformStr.bridged, + domainLoc: platformLoc, + kind: attrKind, + message: message ?? BridgedStringRef(), + renamed: renamed ?? BridgedStringRef(), + introduced: introduced?.version.bridged ?? BridgedVersionTuple(), + introducedRange: introduced?.range ?? BridgedSourceRange(), + deprecated: deprecated?.version.bridged ?? BridgedVersionTuple(), + deprecatedRange: deprecated?.range ?? BridgedSourceRange(), + obsoleted: obsoleted?.version.bridged ?? BridgedVersionTuple(), + obsoletedRange: obsoleted?.range ?? BridgedSourceRange() + ) + } + + /// Return true if 'name' is an availability macro name. + func peekAvailabilityMacroName(_ name: SyntaxText) -> Bool { + let map = ctx.availabilityMacroMap + return map.has(name: name.bridged) + } + + func generate(availabilityMacroDefinition node: AvailabilityMacroDefinitionSyntax) -> BridgedAvailabilityMacroDefinition { + + let name = allocateBridgedString(node.platformVersion.platform.text) + let version = self.generate(versionTuple: node.platformVersion.version) + let specs = self.generateAvailabilitySpecList(args: node.specs, context: .macro) + + let specsBuffer = UnsafeMutableBufferPointer.allocate(capacity: specs.count) + _ = specsBuffer.initialize(from: specs) + + return BridgedAvailabilityMacroDefinition( + name: name, + version: version?.bridged ?? BridgedVersionTuple(), + specs: BridgedArrayRef(data: UnsafeRawPointer(specsBuffer.baseAddress), count: specsBuffer.count) + ) + } + + enum AvailabilitySpecListContext { + case availableAttr + case macro + } + + func generateAvailabilitySpecList(args node: AvailabilityArgumentListSyntax, context: AvailabilitySpecListContext) -> [BridgedAvailabilitySpec] { + var result: [BridgedAvailabilitySpec] = [] + + func handle(domainNode: TokenSyntax, versionNode: VersionTupleSyntax?) { + let nameLoc = self.generateSourceLoc(domainNode) + let version = self.generate(versionTuple: versionNode) + let versionRange = self.generateSourceRange(versionNode) + + switch domainNode.rawText { + case "swift", "_PackageVersion": + let kind: BridgedAvailabilitySpecKind = domainNode.rawText == "swift" + ? .languageVersionConstraint + : .packageDescriptionVersionConstraint + + let spec = BridgedPlatformAgnosticVersionConstraintAvailabilitySpec.createParsed( + self.ctx, + kind: kind, + nameLoc: nameLoc, + version: version?.bridged ?? BridgedVersionTuple(), + versionRange: versionRange + ) + result.append(spec.asAvailabilitySpec) + + case let name: + var macroMatched = false; + if context != .macro { + // Try expand macro first. + let expanded = ctx.availabilityMacroMap.get( + name: name.bridged, + version: version?.bridged ?? BridgedVersionTuple() + ) + if !expanded.isEmpty { + expanded.withElements(ofType: UnsafeRawPointer.self) { buffer in + for ptr in buffer { + result.append(BridgedAvailabilitySpec(raw: UnsafeMutableRawPointer(mutating: ptr))) + } + } + macroMatched = true + } + } + + // Was not a macro, it should be a valid platform name. + if !macroMatched { + let platform = BridgedPlatformKind(from: name.bridged) + guard platform != .none else { + // TODO: Diagnostics. + fatalError("invalid platform kind") + } + guard let version = version else { + // TODO: Diagnostics. + fatalError("expected version") + } + let spec = BridgedPlatformVersionConstraintAvailabilitySpec.createParsed( + self.ctx, + platform: platform, + platformLoc: nameLoc, + version: version.bridged, + runtimeVersion: version.bridged, + versionRange: versionRange + ) + result.append(spec.asAvailabilitySpec) + } + } + } + + for parsed in node { + switch parsed.argument { + case .token(let tok) where tok.rawText == "*": + let spec = BridgedOtherPlatformAvailabilitySpec.createParsed( + self.ctx, + loc: self.generateSourceLoc(tok) + ) + result.append(spec.asAvailabilitySpec) + case .token(let tok): + handle(domainNode: tok, versionNode: nil) + case .availabilityVersionRestriction(let platformVersion): + handle(domainNode: platformVersion.platform, versionNode: platformVersion.version) + default: + // TODO: Diagnostics. + fatalError("invalid argument kind for availability spec") + } + } + + return result + } +} + +/// Parse an argument for '-define-availability' compiler option. +@_cdecl("swift_ASTGen_parseAvailabilityMacroDefinition") +func parseAvailabilityMacroDefinition( + ctx: BridgedASTContext, + dc: BridgedDeclContext, + diagEngine: BridgedDiagnosticEngine, + buffer: BridgedStringRef, + outPtr: UnsafeMutablePointer +) -> Bool { + let buffer = UnsafeBufferPointer(start: buffer.data, count: buffer.count) + + // Parse. + var parser = Parser(buffer) + let parsed = AvailabilityMacroDefinitionSyntax.parse(from: &parser) + + // Emit diagnostics. + let diagnostics = ParseDiagnosticsGenerator.diagnostics(for: parsed) + for diagnostic in diagnostics { + emitDiagnostic( + diagnosticEngine: diagEngine, + sourceFileBuffer: buffer, + diagnostic: diagnostic, + diagnosticSeverity: diagnostic.diagMessage.severity + ) + } + if parsed.hasError { + return true + } + + // Generate. + let config = CompilerBuildConfiguration(ctx: ctx, sourceBuffer: buffer) + let configuredRegions = parsed.configuredRegions(in: config) + + // FIXME: 'declContext' and 'configuredRegions' are never used. + let generator = ASTGenVisitor( + diagnosticEngine: diagEngine, + sourceBuffer: buffer, + declContext: dc, + astContext: ctx, + configuredRegions: configuredRegions + ) + let generated = generator.generate(availabilityMacroDefinition: parsed) + outPtr.pointee = generated + return false +} + +@_cdecl("swift_ASTGen_freeAvailabilityMacroDefinition") +func freeAvailabilityMacroDefinition( + defintion: UnsafeMutablePointer +) { + freeBridgedString(bridged: defintion.pointee.name) + + let specs = defintion.pointee.specs + let specsBuffer = UnsafeMutableBufferPointer( + start: UnsafeMutablePointer(mutating: specs.data?.assumingMemoryBound(to: BridgedAvailabilitySpec.self)), + count: specs.count + ) + specsBuffer.deinitialize() + specsBuffer.deallocate() +} diff --git a/lib/ASTGen/Sources/ASTGen/Bridge.swift b/lib/ASTGen/Sources/ASTGen/Bridge.swift index 89b1a3654983c..379481ae330cf 100644 --- a/lib/ASTGen/Sources/ASTGen/Bridge.swift +++ b/lib/ASTGen/Sources/ASTGen/Bridge.swift @@ -12,6 +12,7 @@ import ASTBridging import BasicBridging +import SwiftIfConfig @_spi(RawSyntax) import SwiftSyntax public protocol BridgedNullable: ExpressibleByNilLiteral { @@ -161,6 +162,25 @@ extension BridgedStringRef: /*@retroactive*/ Swift.ExpressibleByStringLiteral { } } +extension VersionTuple { + var bridged: BridgedVersionTuple { + switch self.components.count { + case 4: + return BridgedVersionTuple(CUnsignedInt(components[0]), CUnsignedInt(components[1]), CUnsignedInt(components[2]), CUnsignedInt(components[3])) + case 3: + return BridgedVersionTuple(CUnsignedInt(components[0]), CUnsignedInt(components[1]), CUnsignedInt(components[2])) + case 2: + return BridgedVersionTuple(CUnsignedInt(components[0]), CUnsignedInt(components[1])) + case 1: + return BridgedVersionTuple(CUnsignedInt(components[0])) + case 0: + return BridgedVersionTuple() + default: + fatalError("unsuported version form") + } + } +} + extension SyntaxProtocol { /// Obtains the bridged start location of the node excluding leading trivia in the source buffer provided by `astgen` /// @@ -290,3 +310,11 @@ extension ConcatCollection: LazyCollectionProtocol { } } } + +extension BridgedArrayRef { + public func withElements(ofType ty: T.Type, _ c: (UnsafeBufferPointer) -> R) -> R { + let start = data?.bindMemory(to: ty, capacity: count) + let buffer = UnsafeBufferPointer(start: start, count: count) + return c(buffer) + } +} diff --git a/lib/ASTGen/Sources/ASTGen/CMakeLists.txt b/lib/ASTGen/Sources/ASTGen/CMakeLists.txt index 45fd9b7701a12..96bea9440d2a7 100644 --- a/lib/ASTGen/Sources/ASTGen/CMakeLists.txt +++ b/lib/ASTGen/Sources/ASTGen/CMakeLists.txt @@ -1,6 +1,7 @@ add_pure_swift_host_library(swiftASTGen STATIC CXX_INTEROP ASTGen.swift ASTGen+CompilerBuildConfiguration.swift + Availability.swift Bridge.swift CompilerBuildConfiguration.swift DeclAttrs.swift diff --git a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift index 5790912df2a00..8b2e5c6a4c5ee 100644 --- a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift +++ b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift @@ -497,24 +497,6 @@ extension ASTGenVisitor { ) } - /// E.g.: - /// ``` - /// @available(macOS 10.12, iOS: 13, *) - /// @available(macOS, introduced: 10.12) - /// ``` - func generateAvailableAttr(attribute node: AttributeSyntax) -> [BridgedAvailableAttr] { - guard - // `@available` has special argument list syntax. - let args = node.arguments?.as(AvailabilityArgumentListSyntax.self) - else { - // TODO: Diagnose. - return [] - } - - _ = args - fatalError("unimplemented") - } - /// E.g: /// ``` /// @_dynamicReplacement(for: member) @@ -1859,7 +1841,7 @@ extension ASTGenVisitor { } /// Simpler helper for handling attribute arguments in "generate" functions. -private struct AttrArgumentState where Flag.RawValue: FixedWidthInteger { +struct AttrArgumentState where Flag.RawValue: FixedWidthInteger { private var seen: SeenStorage = 0 var current: Flag { diff --git a/lib/Basic/BasicBridging.cpp b/lib/Basic/BasicBridging.cpp index 99f97be199055..3432f11a1f70c 100644 --- a/lib/Basic/BasicBridging.cpp +++ b/lib/Basic/BasicBridging.cpp @@ -10,9 +10,10 @@ // //===----------------------------------------------------------------------===// -#include "swift/Basic/Assertions.h" #include "swift/Basic/BasicBridging.h" +#include "swift/Basic/Assertions.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/VersionTuple.h" #include "llvm/Support/raw_ostream.h" #ifdef PURE_BRIDGING_MODE @@ -94,3 +95,30 @@ void BridgedCharSourceRangeVector::push_back(BridgedCharSourceRange range) { static_cast *>(vector)->push_back( range.unbridged()); } + +//===----------------------------------------------------------------------===// +// MARK: BridgedVersionTuple +//===----------------------------------------------------------------------===// + +BridgedVersionTuple::BridgedVersionTuple(llvm::VersionTuple version) { + if (version.getBuild()) + *this = BridgedVersionTuple(version.getMajor(), *version.getMinor(), + *version.getSubminor(), *version.getBuild()); + else if (version.getSubminor()) + *this = BridgedVersionTuple(version.getMajor(), *version.getMinor(), + *version.getSubminor()); + else if (version.getMinor()) + *this = BridgedVersionTuple(version.getMajor(), *version.getMinor()); + else + *this = BridgedVersionTuple(version.getMajor()); +} + +llvm::VersionTuple BridgedVersionTuple::unbridged() const { + if (HasBuild) + return llvm::VersionTuple(Major, Minor, Subminor, Build); + if (HasSubminor) + return llvm::VersionTuple(Major, Minor, Subminor); + if (HasMinor) + return llvm::VersionTuple(Major, Minor); + return llvm::VersionTuple(Major); +} diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 65ef704bb2002..6bd93152c41de 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -789,37 +789,18 @@ bool Parser::parseAvailability( // @available(_PackageDescription, introduced: 4.2) for (auto *Spec : Specs) { - AvailabilityDomain Domain; - llvm::VersionTuple Version; - SourceRange VersionRange; - // FIXME: [availability] Allow arbitrary availability domains. - if (auto *PlatformVersionSpec = - dyn_cast(Spec)) { - Domain = - AvailabilityDomain::forPlatform(PlatformVersionSpec->getPlatform()); - Version = PlatformVersionSpec->getVersion(); - VersionRange = PlatformVersionSpec->getVersionSrcRange(); - - } else if (auto *PlatformAgnosticVersionSpec = dyn_cast< - PlatformAgnosticVersionConstraintAvailabilitySpec>(Spec)) { - Domain = PlatformAgnosticVersionSpec->isLanguageVersionSpecific() - ? AvailabilityDomain::forSwiftLanguage() - : AvailabilityDomain::forPackageDescription(); - Version = PlatformAgnosticVersionSpec->getVersion(); - VersionRange = PlatformAgnosticVersionSpec->getVersionSrcRange(); - - } else { + std::optional Domain = Spec->getDomain(); + if (!Domain) continue; - } addAttribute(new (Context) AvailableAttr( - AtLoc, attrRange, Domain, Spec->getSourceRange().Start, + AtLoc, attrRange, *Domain, Spec->getSourceRange().Start, AvailableAttr::Kind::Default, /*Message=*/StringRef(), /*Rename=*/StringRef(), - /*Introduced=*/Version, - /*IntroducedRange=*/VersionRange, + /*Introduced=*/Spec->getVersion(), + /*IntroducedRange=*/Spec->getVersionSrcRange(), /*Deprecated=*/llvm::VersionTuple(), /*DeprecatedRange=*/SourceRange(), /*Obsoleted=*/llvm::VersionTuple(), @@ -1835,16 +1816,13 @@ void Parser::parseObjCSelector(SmallVector &Names, } bool Parser::peekAvailabilityMacroName() { - AvailabilityMacroMap &Map = parseAllAvailabilityMacroArguments(); - - StringRef MacroName = Tok.getText(); - return Map.Impl.find(MacroName) != Map.Impl.end(); + return Context.getAvailabilityMacroMap().hasMacroName(Tok.getText()); } ParserStatus Parser::parseAvailabilityMacro(SmallVectorImpl &Specs) { // Get the macros from the compiler arguments. - AvailabilityMacroMap &Map = parseAllAvailabilityMacroArguments(); + const AvailabilityMacroMap &Map = Context.getAvailabilityMacroMap(); StringRef MacroName = Tok.getText(); auto NameMatch = Map.Impl.find(MacroName); @@ -1861,8 +1839,8 @@ Parser::parseAvailabilityMacro(SmallVectorImpl &Specs) { return makeParserError(); } - auto VersionMatch = NameMatch->getSecond().find(Version); - if (VersionMatch == NameMatch->getSecond().end()) { + auto VersionMatch = NameMatch->second.find(Version); + if (VersionMatch == NameMatch->second.end()) { diagnose(PreviousLoc, diag::attr_availability_unknown_version, Version.getAsString(), MacroName); return makeParserError(); // Failed to match the version, that's an error. @@ -1884,77 +1862,6 @@ Parser::parseAvailabilityMacro(SmallVectorImpl &Specs) { return makeParserSuccess(); } -AvailabilityMacroMap &Parser::parseAllAvailabilityMacroArguments() { - AvailabilityMacroMap &Map = Context.getAvailabilityMacroCache(); - if (Map.WasParsed) - return Map; - - SourceManager &SM = Context.SourceMgr; - LangOptions LangOpts = Context.LangOpts; - - // Allocate all buffers in one go to avoid repeating the sorting in - // findBufferContainingLocInternal. - llvm::SmallVector bufferIDs; - for (StringRef macro: LangOpts.AvailabilityMacros) { - unsigned bufferID = SM.addMemBufferCopy(macro, - "-define-availability argument"); - bufferIDs.push_back(bufferID); - } - - // Parse each macro definition. - for (unsigned bufferID: bufferIDs) { - // Create temporary parser. - swift::ParserUnit PU(SM, SourceFileKind::Main, bufferID, LangOpts, - "unknown"); - - ForwardingDiagnosticConsumer PDC(Context.Diags); - PU.getDiagnosticEngine().addConsumer(PDC); - - // Parse the argument. - AvailabilityMacroDefinition ParsedMacro; - ParserStatus Status = - PU.getParser().parseAvailabilityMacroDefinition(ParsedMacro); - if (Status.isError()) - continue; - - // Copy the Specs to the requesting ASTContext from the temporary context - // that parsed the argument. - auto SpecsCopy = SmallVector(); - for (auto *Spec : ParsedMacro.Specs) - if (auto *PlatformVersionSpec = - dyn_cast(Spec)) { - auto SpecCopy = - new (Context) PlatformVersionConstraintAvailabilitySpec( - *PlatformVersionSpec); - SpecsCopy.push_back(SpecCopy); - } - - ParsedMacro.Specs = SpecsCopy; - - // Find the macro info by name. - AvailabilityMacroMap::VersionEntry MacroDefinition; - auto NameMatch = Map.Impl.find(ParsedMacro.Name); - if (NameMatch != Map.Impl.end()) { - MacroDefinition = NameMatch->getSecond(); - } - - // Set the macro info by version. - auto PreviousEntry = - MacroDefinition.insert({ParsedMacro.Version, ParsedMacro.Specs}); - if (!PreviousEntry.second) { - diagnose(PU.getParser().PreviousLoc, diag::attr_availability_duplicate, - ParsedMacro.Name, ParsedMacro.Version.getAsString()); - } - - // Save back the macro spec. - Map.Impl.erase(ParsedMacro.Name); - Map.Impl.insert({ParsedMacro.Name, MacroDefinition}); - } - - Map.WasParsed = true; - return Map; -} - ParserStatus Parser::parsePlatformVersionInList(StringRef AttrName, llvm::SmallVector &PlatformAndVersions, bool &ParsedUnrecognizedPlatformName) { diff --git a/lib/Parse/ParseRequests.cpp b/lib/Parse/ParseRequests.cpp index 4fe54c5890f87..788aaecb36b59 100644 --- a/lib/Parse/ParseRequests.cpp +++ b/lib/Parse/ParseRequests.cpp @@ -251,8 +251,9 @@ bool shouldParseViaASTGen(SourceFile &SF) { return true; } -void appendToVector(BridgedASTNode cNode, void *vecPtr) { - auto vec = static_cast *>(vecPtr); +template +void appendToVector(Bridged cNode, void *vecPtr) { + auto vec = static_cast *>(vecPtr); vec->push_back(cNode.unbridged()); } @@ -300,7 +301,8 @@ SourceFileParsingResult parseSourceFileViaASTGen(SourceFile &SF) { SmallVector items; swift_ASTGen_buildTopLevelASTNodes( &Diags, exportedSourceFile, declContext, Ctx, - static_cast *>(&items), appendToVector); + static_cast *>(&items), + appendToVector); // Fingerprint. // FIXME: Split request (SourceFileFingerprintRequest). @@ -510,9 +512,126 @@ ArrayRef ParseTopLevelDeclsRequest::evaluate( } //----------------------------------------------------------------------------// -// IDEInspectionSecondPassRequest computation. +// AvailabilityMacroArgumentsRequest computation. //----------------------------------------------------------------------------// +namespace { +bool parseAvailabilityMacroDefinitionViaASTGen( + unsigned bufferID, ASTContext &ctx, std::string &name, + llvm::VersionTuple &version, SmallVectorImpl &specs) { + StringRef buffer = ctx.SourceMgr.getEntireTextForBuffer(bufferID); + DeclContext *dc = ctx.MainModule; + + BridgedAvailabilityMacroDefinition parsed; + bool hadError = swift_ASTGen_parseAvailabilityMacroDefinition(ctx, dc, &ctx.Diags, buffer, + &parsed); + if (hadError) + return true; + SWIFT_DEFER { swift_ASTGen_freeAvailabilityMacroDefinition(&parsed); }; + + name = parsed.name.unbridged(); + version = parsed.version.unbridged(); + specs.clear(); + for (auto spec : parsed.specs.unbridged()) { + // Currently availability macros only supports platform version specs. + if (auto *platformVersionSpec = + dyn_cast( + spec.unbridged())) + specs.push_back(platformVersionSpec); + } + + return false; +} + +bool parseAvailabilityMacroDefinitionViaLegacyParser( + unsigned bufferID, ASTContext &ctx, std::string &name, + llvm::VersionTuple &version, SmallVectorImpl &specs) { + auto &SM = ctx.SourceMgr; + + // Create temporary parser. + swift::ParserUnit PU(SM, SourceFileKind::Main, bufferID, ctx.LangOpts, + "unknown"); + + ForwardingDiagnosticConsumer PDC(ctx.Diags); + PU.getDiagnosticEngine().addConsumer(PDC); + + // Parse the argument. + SmallVector tmpSpecs; + ParserStatus status = + PU.getParser().parseAvailabilityMacroDefinition(name, version, tmpSpecs); + if (status.isError()) + return true; + + // Copy the Specs to the requesting ASTContext from the temporary context + // in the ParserUnit. + for (auto *spec : tmpSpecs) { + // Currently availability macros only supports platform version specs. + if (auto *platformVersionSpec = + dyn_cast(spec)) { + auto copy = new (ctx) + PlatformVersionConstraintAvailabilitySpec(*platformVersionSpec); + specs.push_back(copy); + } + } + + return false; +} + +bool parseAvailabilityMacroDefinition( + unsigned bufferID, ASTContext &ctx, std::string &name, + llvm::VersionTuple &version, SmallVectorImpl &specs) { +#if SWIFT_BUILD_SWIFT_SYNTAX + if (ctx.LangOpts.hasFeature(Feature::ParserASTGen)) + return parseAvailabilityMacroDefinitionViaASTGen(bufferID, ctx, name, + version, specs); +#endif + return parseAvailabilityMacroDefinitionViaLegacyParser(bufferID, ctx, name, + version, specs); +} + +} // namespace + +AvailabilityMacroMap * +AvailabilityMacroArgumentsRequest::evaluate(Evaluator &evaluator, + ASTContext *ctx) const { + SourceManager &SM = ctx->SourceMgr; + + // Allocate all buffers in one go to avoid repeating the sorting in + // findBufferContainingLocInternal. + llvm::SmallVector bufferIDs; + for (auto macro : ctx->LangOpts.AvailabilityMacros) { + unsigned bufferID = + SM.addMemBufferCopy(macro, "-define-availability argument"); + bufferIDs.push_back(bufferID); + } + + auto *map = new AvailabilityMacroMap(); + ctx->addCleanup([map]() { delete map; }); + + // Parse each macro definition. + for (unsigned bufferID : bufferIDs) { + std::string name; + llvm::VersionTuple version; + SmallVector specs; + if (parseAvailabilityMacroDefinition(bufferID, *ctx, name, version, specs)) + continue; + + if (map->hasMacroNameVersion(name, version)) { + ctx->Diags.diagnose(SM.getLocForBufferStart(bufferID), + diag::attr_availability_duplicate, name, + version.getAsString()); + continue; + } + + map->addEntry(name, version, specs); + } + + return map; +} + +//----------------------------------------------------------------------------// +// IDEInspectionSecondPassRequest computation. +//----------------------------------------------------------------------------// void swift::simple_display(llvm::raw_ostream &out, const IDEInspectionCallbacksFactory *factory) { } diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index e5c12d1b6d713..0ed1a345b4dcf 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -1434,8 +1434,9 @@ ParserResult Parser::parseStmtConditionPoundAvailable() { return makeParserResult(Status, result); } -ParserStatus -Parser::parseAvailabilityMacroDefinition(AvailabilityMacroDefinition &Result) { +ParserStatus Parser::parseAvailabilityMacroDefinition( + std::string &Name, llvm::VersionTuple &Version, + SmallVectorImpl &Specs) { // Prime the lexer. if (Tok.is(tok::NUM_TOKENS)) @@ -1446,23 +1447,23 @@ Parser::parseAvailabilityMacroDefinition(AvailabilityMacroDefinition &Result) { return makeParserError(); } - Result.Name = Tok.getText(); + Name = Tok.getText(); consumeToken(); if (Tok.isAny(tok::integer_literal, tok::floating_literal)) { SourceRange VersionRange; - if (parseVersionTuple(Result.Version, VersionRange, + if (parseVersionTuple(Version, VersionRange, diag::avail_query_expected_version_number)) { return makeParserError(); } } if (!consumeIf(tok::colon)) { - diagnose(Tok, diag::attr_availability_expected_colon_macro, Result.Name); + diagnose(Tok, diag::attr_availability_expected_colon_macro, Name); return makeParserError(); } - return parseAvailabilitySpecList(Result.Specs, AvailabilitySpecSource::Macro); + return parseAvailabilitySpecList(Specs, AvailabilitySpecSource::Macro); } ParserStatus diff --git a/test/ASTGen/attrs_available.swift b/test/ASTGen/attrs_available.swift new file mode 100644 index 0000000000000..3cbf1e6581647 --- /dev/null +++ b/test/ASTGen/attrs_available.swift @@ -0,0 +1,47 @@ +// RUN: %empty-directory(%t) + +// RUN: COMPILER_ARGS=( \ +// RUN: -define-availability '_iOS53Aligned:macOS 50.0, iOS 53.0' \ +// RUN: -define-availability '_iOS54Aligned:macOS 51.0, iOS 54.0' \ +// RUN: -define-availability '_iOS54:iOS 54.0' \ +// RUN: -define-availability '_macOS51_0:macOS 51.0' \ +// RUN: -define-availability '_myProject 1.0:macOS 51.0' \ +// RUN: -define-availability '_myProject 2.5:macOS 52.5' \ +// RUN: ) + +// RUN: %target-swift-frontend %s "${COMPILER_ARGS[@]}" -dump-parse \ +// RUN: -enable-experimental-feature ParserASTGen \ +// RUN: > %t/astgen.ast.raw + +// RUN: %target-swift-frontend %s "${COMPILER_ARGS[@]}" -dump-parse \ +// RUN: > %t/cpp-parser.ast.raw + +// Filter out any addresses in the dump, since they can differ. +// RUN: sed -E 's#0x[0-9a-fA-F]+##g' %t/astgen.ast.raw > %t/astgen.ast +// RUN: sed -E 's#0x[0-9a-fA-F]+##g' %t/cpp-parser.ast.raw > %t/cpp-parser.ast + +// RUN: %diff -u %t/astgen.ast %t/cpp-parser.ast + +// RUN: %target-typecheck-verify-swift "${COMPILER_ARGS[@]}" \ +// RUN: -enable-experimental-feature ParserASTGen + +// REQUIRES: shell +// REQUIRES: swift_feature_ParserASTGen + +@available(swift 4) +func testSwift4OrLater() {} + +@available(macOS 12, iOS 13.1, *) +func testShorthandMulti() {} + +@available(macOS, unavailable) +func testUnavailableMacOS() {} + +@available(macOS, deprecated: 12.0.5, message: "whatever") +func testDeprecaed12MacOS() {} + +@available(_iOS53Aligned, *) +func testMacroNameOnly() {} + +@available(_myProject 2.5, *) +func testMacroWithVersion() {}