[llvm-branch-commits] [clang] release/19.x: [clang][modules] Enable built-in modules for the upcoming Apple releases (#102239) (PR #102335)
https://github.com/cyndyishida approved this pull request. LGTM We definitely need this for any clients with newer apple sdks using llvm-19 toolchain. https://github.com/llvm/llvm-project/pull/102335 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] release/19.x: [clang][modules] Enable built-in modules for the upcoming Apple releases (#102239) (PR #102517)
https://github.com/cyndyishida approved this pull request. Thanks for applying the code cleanup! https://github.com/llvm/llvm-project/pull/102517 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] release/19.x: [clang][modules] Built-in modules are not correctly enabled for Mac Catalyst (#104872) (PR #105093)
https://github.com/cyndyishida approved this pull request. https://github.com/llvm/llvm-project/pull/105093 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [InstallAPI] Capture C++ Decls (PR #83953)
https://github.com/cyndyishida created https://github.com/llvm/llvm-project/pull/83953 This includes capturing symbols for global variables, functions, classes, and templated definitions. As pre-determining what symbols are generated from C++ declarations can be non-trivial, InstallAPI only parses select declarations for symbol generation when in C++. For example, InstallAPI only looks at explicit template instantiations or full template specializations, instead of general function or class templates, for symbol generation. >From ab76a4cd4fcaff0633197ab34c595f8b2eab05b3 Mon Sep 17 00:00:00 2001 From: Cyndy Ishida Date: Mon, 4 Mar 2024 14:44:56 -0800 Subject: [PATCH] [InstallAPI] Add support for C++ headers This includes capturing symbols for global variables, functions, classes, and templated defintions. As pre-determing what symbols are generated from C++ declarations can be non-trivial, InstallAPI only parses select declarations for symbol generation when parsing c++. For example, installapi only looks at explicit template instantiations or full template specializations, instead of general function or class templates, for symbol emittion. --- clang/include/clang/InstallAPI/Visitor.h | 14 + clang/lib/InstallAPI/Frontend.cpp| 4 +- clang/lib/InstallAPI/Visitor.cpp | 425 +- clang/test/InstallAPI/cpp.test | 530 +++ clang/tools/clang-installapi/Options.cpp | 33 +- clang/tools/clang-installapi/Options.h | 7 + 6 files changed, 1007 insertions(+), 6 deletions(-) create mode 100644 clang/test/InstallAPI/cpp.test diff --git a/clang/include/clang/InstallAPI/Visitor.h b/clang/include/clang/InstallAPI/Visitor.h index 71d4d9894f4205..546a2b85cb38c5 100644 --- a/clang/include/clang/InstallAPI/Visitor.h +++ b/clang/include/clang/InstallAPI/Visitor.h @@ -13,6 +13,7 @@ #ifndef LLVM_CLANG_INSTALLAPI_VISITOR_H #define LLVM_CLANG_INSTALLAPI_VISITOR_H +#include "clang/AST/Availability.h" #include "clang/AST/Mangle.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/TargetInfo.h" @@ -33,6 +34,7 @@ class InstallAPIVisitor final : public ASTConsumer, MC(ItaniumMangleContext::create(ASTCtx, ASTCtx.getDiagnostics())), Layout(ASTCtx.getTargetInfo().getDataLayoutString()) {} void HandleTranslationUnit(ASTContext &ASTCtx) override; + bool shouldVisitTemplateInstantiations() const { return true; } /// Collect global variables. bool VisitVarDecl(const VarDecl *D); @@ -51,9 +53,19 @@ class InstallAPIVisitor final : public ASTConsumer, /// is therefore itself not collected. bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D); + /// Collect global c++ declarations. + bool VisitCXXRecordDecl(const CXXRecordDecl *D); + private: std::string getMangledName(const NamedDecl *D) const; std::string getBackendMangledName(llvm::Twine Name) const; + std::string getMangledCXXVTableName(const CXXRecordDecl *D) const; + std::string getMangledCXXThunk(const GlobalDecl &D, + const ThunkInfo &Thunk) const; + std::string getMangledCXXRTTI(const CXXRecordDecl *D) const; + std::string getMangledCXXRTTIName(const CXXRecordDecl *D) const; + std::string getMangledCtorDtor(const CXXMethodDecl *D, int Type) const; + std::optional getAccessForDecl(const NamedDecl *D) const; void recordObjCInstanceVariables( const ASTContext &ASTCtx, llvm::MachO::ObjCContainerRecord *Record, @@ -61,6 +73,8 @@ class InstallAPIVisitor final : public ASTConsumer, const llvm::iterator_range< DeclContext::specific_decl_iterator> Ivars); + void emitVTableSymbols(const CXXRecordDecl *D, const AvailabilityInfo &Avail, + const HeaderType Access, bool EmittedVTable = false); InstallAPIContext &Ctx; SourceManager &SrcMgr; diff --git a/clang/lib/InstallAPI/Frontend.cpp b/clang/lib/InstallAPI/Frontend.cpp index efc634d80dd218..c0d8526dae8228 100644 --- a/clang/lib/InstallAPI/Frontend.cpp +++ b/clang/lib/InstallAPI/Frontend.cpp @@ -136,9 +136,9 @@ std::unique_ptr createInputBuffer(InstallAPIContext &Ctx) { else OS << "#import "; if (H.useIncludeName()) - OS << "<" << H.getIncludeName() << ">"; + OS << "<" << H.getIncludeName() << ">\n"; else - OS << "\"" << H.getPath() << "\""; + OS << "\"" << H.getPath() << "\"\n"; Ctx.addKnownHeader(H); } diff --git a/clang/lib/InstallAPI/Visitor.cpp b/clang/lib/InstallAPI/Visitor.cpp index 1f2ef08e5aa252..89d753f8a01706 100644 --- a/clang/lib/InstallAPI/Visitor.cpp +++ b/clang/lib/InstallAPI/Visitor.cpp @@ -8,6 +8,7 @@ #include "clang/InstallAPI/Visitor.h" #include "clang/AST/ParentMapContext.h" +#include "clang/AST/VTableBuilder.h" #include "clang/Basic/Linkage.h" #include "clang/InstallAPI/Frontend.h" #include "llvm/ADT/SmallString.h" @@ -18,6 +19,15 @@ using namespace llvm; using namespace llvm::MachO; +namespace { +en
[llvm-branch-commits] [clang] [InstallAPI] Capture C++ Decls (PR #83953)
https://github.com/cyndyishida updated https://github.com/llvm/llvm-project/pull/83953 >From d73efd9fc4d4b3100fe902bbb6b690144acd51da Mon Sep 17 00:00:00 2001 From: Cyndy Ishida Date: Mon, 4 Mar 2024 14:44:56 -0800 Subject: [PATCH] [InstallAPI] Add support for C++ headers This includes capturing symbols for global variables, functions, classes, and templated defintions. As pre-determing what symbols are generated from C++ declarations can be non-trivial, InstallAPI only parses select declarations for symbol generation when parsing c++. For example, installapi only looks at explicit template instantiations or full template specializations, instead of general function or class templates, for symbol emittion. --- clang/include/clang/InstallAPI/Visitor.h | 14 + clang/lib/InstallAPI/Frontend.cpp| 4 +- clang/lib/InstallAPI/Visitor.cpp | 425 +- clang/test/InstallAPI/cpp.test | 530 +++ clang/tools/clang-installapi/Options.cpp | 33 +- clang/tools/clang-installapi/Options.h | 7 + 6 files changed, 1007 insertions(+), 6 deletions(-) create mode 100644 clang/test/InstallAPI/cpp.test diff --git a/clang/include/clang/InstallAPI/Visitor.h b/clang/include/clang/InstallAPI/Visitor.h index 71d4d9894f4205..546a2b85cb38c5 100644 --- a/clang/include/clang/InstallAPI/Visitor.h +++ b/clang/include/clang/InstallAPI/Visitor.h @@ -13,6 +13,7 @@ #ifndef LLVM_CLANG_INSTALLAPI_VISITOR_H #define LLVM_CLANG_INSTALLAPI_VISITOR_H +#include "clang/AST/Availability.h" #include "clang/AST/Mangle.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/TargetInfo.h" @@ -33,6 +34,7 @@ class InstallAPIVisitor final : public ASTConsumer, MC(ItaniumMangleContext::create(ASTCtx, ASTCtx.getDiagnostics())), Layout(ASTCtx.getTargetInfo().getDataLayoutString()) {} void HandleTranslationUnit(ASTContext &ASTCtx) override; + bool shouldVisitTemplateInstantiations() const { return true; } /// Collect global variables. bool VisitVarDecl(const VarDecl *D); @@ -51,9 +53,19 @@ class InstallAPIVisitor final : public ASTConsumer, /// is therefore itself not collected. bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D); + /// Collect global c++ declarations. + bool VisitCXXRecordDecl(const CXXRecordDecl *D); + private: std::string getMangledName(const NamedDecl *D) const; std::string getBackendMangledName(llvm::Twine Name) const; + std::string getMangledCXXVTableName(const CXXRecordDecl *D) const; + std::string getMangledCXXThunk(const GlobalDecl &D, + const ThunkInfo &Thunk) const; + std::string getMangledCXXRTTI(const CXXRecordDecl *D) const; + std::string getMangledCXXRTTIName(const CXXRecordDecl *D) const; + std::string getMangledCtorDtor(const CXXMethodDecl *D, int Type) const; + std::optional getAccessForDecl(const NamedDecl *D) const; void recordObjCInstanceVariables( const ASTContext &ASTCtx, llvm::MachO::ObjCContainerRecord *Record, @@ -61,6 +73,8 @@ class InstallAPIVisitor final : public ASTConsumer, const llvm::iterator_range< DeclContext::specific_decl_iterator> Ivars); + void emitVTableSymbols(const CXXRecordDecl *D, const AvailabilityInfo &Avail, + const HeaderType Access, bool EmittedVTable = false); InstallAPIContext &Ctx; SourceManager &SrcMgr; diff --git a/clang/lib/InstallAPI/Frontend.cpp b/clang/lib/InstallAPI/Frontend.cpp index efc634d80dd218..c0d8526dae8228 100644 --- a/clang/lib/InstallAPI/Frontend.cpp +++ b/clang/lib/InstallAPI/Frontend.cpp @@ -136,9 +136,9 @@ std::unique_ptr createInputBuffer(InstallAPIContext &Ctx) { else OS << "#import "; if (H.useIncludeName()) - OS << "<" << H.getIncludeName() << ">"; + OS << "<" << H.getIncludeName() << ">\n"; else - OS << "\"" << H.getPath() << "\""; + OS << "\"" << H.getPath() << "\"\n"; Ctx.addKnownHeader(H); } diff --git a/clang/lib/InstallAPI/Visitor.cpp b/clang/lib/InstallAPI/Visitor.cpp index 1f2ef08e5aa252..89d753f8a01706 100644 --- a/clang/lib/InstallAPI/Visitor.cpp +++ b/clang/lib/InstallAPI/Visitor.cpp @@ -8,6 +8,7 @@ #include "clang/InstallAPI/Visitor.h" #include "clang/AST/ParentMapContext.h" +#include "clang/AST/VTableBuilder.h" #include "clang/Basic/Linkage.h" #include "clang/InstallAPI/Frontend.h" #include "llvm/ADT/SmallString.h" @@ -18,6 +19,15 @@ using namespace llvm; using namespace llvm::MachO; +namespace { +enum class CXXLinkage { + ExternalLinkage, + LinkOnceODRLinkage, + WeakODRLinkage, + PrivateLinkage, +}; +} + namespace clang::installapi { // Exported NamedDecl needs to have external linkage and @@ -53,7 +63,7 @@ static bool isInlined(const FunctionDecl *D) { return true; } -static SymbolFlags getFlags(bool WeakDef, bool ThreadLocal) { +static SymbolFlags getFlags(bool WeakDef, bool ThreadLocal = false) { SymbolFlags Result = Symb
[llvm-branch-commits] [clang] [InstallAPI] Capture C++ Decls (PR #83953)
https://github.com/cyndyishida closed https://github.com/llvm/llvm-project/pull/83953 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [llvm] [InstallAPI] Introduce Basic Verifier (PR #85101)
https://github.com/cyndyishida created https://github.com/llvm/llvm-project/pull/85101 _NOTE:_ This PR is part of a stack, please review https://github.com/llvm/llvm-project/pull/85100 first. This adds basic support for calling the verifier on global declarations that are expected to represent symbol exports. The driver now exclusively uses this for knowing what symbols make up a TBD file. Future patches will check against the dylib's symbol table. >From a975bff1edf4f0eb47bd243d8219ce1ada321332 Mon Sep 17 00:00:00 2001 From: Cyndy Ishida Date: Tue, 12 Mar 2024 20:56:23 -0700 Subject: [PATCH] [InstallAPI] Introduce Basic Verifier This adds basic support for calling the verifier on global declarations that are expected to represent symbol exports. The driver now exclusively uses this for knowing what symbols make up a TBD file. Future patches will actually check against the dylib's symbol table. --- clang/include/clang/AST/Availability.h| 3 + clang/include/clang/InstallAPI/Context.h | 4 + .../include/clang/InstallAPI/DylibVerifier.h | 79 ++- clang/include/clang/InstallAPI/Frontend.h | 1 - .../clang/InstallAPI/FrontendRecords.h| 50 +++-- clang/include/clang/InstallAPI/MachO.h| 3 + clang/lib/InstallAPI/CMakeLists.txt | 2 + clang/lib/InstallAPI/DylibVerifier.cpp| 212 ++ clang/lib/InstallAPI/Frontend.cpp | 49 ++-- clang/lib/InstallAPI/Visitor.cpp | 101 + clang/test/InstallAPI/asm.test| 90 .../clang-installapi/ClangInstallAPI.cpp | 12 +- clang/tools/clang-installapi/Options.cpp | 9 +- llvm/include/llvm/TextAPI/Record.h| 7 +- 14 files changed, 525 insertions(+), 97 deletions(-) create mode 100644 clang/lib/InstallAPI/DylibVerifier.cpp create mode 100644 clang/test/InstallAPI/asm.test diff --git a/clang/include/clang/AST/Availability.h b/clang/include/clang/AST/Availability.h index ae3acbeffe7f18..5cfbaf0cdfbd21 100644 --- a/clang/include/clang/AST/Availability.h +++ b/clang/include/clang/AST/Availability.h @@ -75,6 +75,9 @@ struct AvailabilityInfo { /// Determine if this AvailabilityInfo represents the default availability. bool isDefault() const { return *this == AvailabilityInfo(); } + /// Check if the symbol has been obsoleted. + bool isObsoleted() const { return !Obsoleted.empty(); } + /// Check if the symbol is unconditionally deprecated. /// /// i.e. \code __attribute__((deprecated)) \endcode diff --git a/clang/include/clang/InstallAPI/Context.h b/clang/include/clang/InstallAPI/Context.h index bdb576d7d85fb6..074ff6f969773c 100644 --- a/clang/include/clang/InstallAPI/Context.h +++ b/clang/include/clang/InstallAPI/Context.h @@ -18,6 +18,7 @@ namespace clang { namespace installapi { class FrontendRecordsSlice; +class DylibVerifier; /// Struct used for generating validating InstallAPI. /// The attributes captured represent all necessary information @@ -45,6 +46,9 @@ struct InstallAPIContext { /// DiagnosticsEngine for all error reporting. DiagnosticsEngine *Diags = nullptr; + /// Verifier when binary dylib is passed as input. + std::unique_ptr Verifier = nullptr; + /// File Path of output location. llvm::StringRef OutputLoc{}; diff --git a/clang/include/clang/InstallAPI/DylibVerifier.h b/clang/include/clang/InstallAPI/DylibVerifier.h index 1a6121b3a258b5..72c4743fdf65e0 100644 --- a/clang/include/clang/InstallAPI/DylibVerifier.h +++ b/clang/include/clang/InstallAPI/DylibVerifier.h @@ -9,10 +9,12 @@ #ifndef LLVM_CLANG_INSTALLAPI_DYLIBVERIFIER_H #define LLVM_CLANG_INSTALLAPI_DYLIBVERIFIER_H -#include "llvm/TextAPI/Target.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/InstallAPI/MachO.h" namespace clang { namespace installapi { +struct FrontendAttrs; /// A list of InstallAPI verification modes. enum class VerificationMode { @@ -22,6 +24,81 @@ enum class VerificationMode { Pedantic, }; +/// Service responsible to tracking state of verification across the +/// lifetime of InstallAPI. +/// As declarations are collected during AST traversal, they are +/// compared as symbols against what is available in the binary dylib. +class DylibVerifier { +private: + struct SymbolContext; + +public: + enum class Result { NoVerify, Ignore, Valid, Invalid }; + struct VerifierContext { +// Current target being verified against the AST. +llvm::MachO::Target Target; + +// Query state of verification after AST has been traversed. +Result FrontendState; + +// First error for AST traversal, which is tied to the target triple. +bool DiscoveredFirstError; + }; + + DylibVerifier() = default; + + DylibVerifier(llvm::MachO::Records &&Dylib, DiagnosticsEngine *Diag, +VerificationMode Mode, bool Demangle) + : Dylib(std::move(Dylib)), Diag(Diag), Mode(Mode), Demangle(Demangle), +Exports(std::make_unique()) {} + + Re
[llvm-branch-commits] [InstallAPI] Introduce Basic Verifier (PR #85101)
https://github.com/cyndyishida closed https://github.com/llvm/llvm-project/pull/85101 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [InstallAPI] Introduce Basic Verifier (PR #85101)
https://github.com/cyndyishida updated https://github.com/llvm/llvm-project/pull/85101 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [llvm] [InstallAPI] Introduce Basic Verifier (PR #85106)
https://github.com/cyndyishida created https://github.com/llvm/llvm-project/pull/85106 _NOTE:_ This PR is part of a stack, please review https://github.com/llvm/llvm-project/pull/85100 first. This adds basic support for calling the verifier on global declarations that are expected to represent symbol exports. The driver now exclusively uses this for knowing what symbols make up a TBD file. Future patches will check against the dylib's symbol table. >From 2a2a3d71fae2be759d31bed6eb25c2487097a75e Mon Sep 17 00:00:00 2001 From: Cyndy Ishida Date: Tue, 12 Mar 2024 20:56:23 -0700 Subject: [PATCH] [InstallAPI] Introduce Basic Verifier This adds basic support for calling the verifier on global declarations that are expected to represent symbol exports. The driver now exclusively uses this for knowing what symbols make up a TBD file. Future patches will actually check against the dylib's symbol table. --- clang/include/clang/AST/Availability.h| 3 + clang/include/clang/InstallAPI/Context.h | 4 + .../include/clang/InstallAPI/DylibVerifier.h | 79 ++- clang/include/clang/InstallAPI/Frontend.h | 1 - .../clang/InstallAPI/FrontendRecords.h| 50 +++-- clang/include/clang/InstallAPI/MachO.h| 3 + clang/lib/InstallAPI/CMakeLists.txt | 2 + clang/lib/InstallAPI/DylibVerifier.cpp| 212 ++ clang/lib/InstallAPI/Frontend.cpp | 49 ++-- clang/lib/InstallAPI/Visitor.cpp | 101 + clang/test/InstallAPI/asm.test| 90 .../clang-installapi/ClangInstallAPI.cpp | 12 +- clang/tools/clang-installapi/Options.cpp | 9 +- llvm/include/llvm/TextAPI/Record.h| 7 +- 14 files changed, 525 insertions(+), 97 deletions(-) create mode 100644 clang/lib/InstallAPI/DylibVerifier.cpp create mode 100644 clang/test/InstallAPI/asm.test diff --git a/clang/include/clang/AST/Availability.h b/clang/include/clang/AST/Availability.h index ae3acbeffe7f18..5cfbaf0cdfbd21 100644 --- a/clang/include/clang/AST/Availability.h +++ b/clang/include/clang/AST/Availability.h @@ -75,6 +75,9 @@ struct AvailabilityInfo { /// Determine if this AvailabilityInfo represents the default availability. bool isDefault() const { return *this == AvailabilityInfo(); } + /// Check if the symbol has been obsoleted. + bool isObsoleted() const { return !Obsoleted.empty(); } + /// Check if the symbol is unconditionally deprecated. /// /// i.e. \code __attribute__((deprecated)) \endcode diff --git a/clang/include/clang/InstallAPI/Context.h b/clang/include/clang/InstallAPI/Context.h index bdb576d7d85fb6..074ff6f969773c 100644 --- a/clang/include/clang/InstallAPI/Context.h +++ b/clang/include/clang/InstallAPI/Context.h @@ -18,6 +18,7 @@ namespace clang { namespace installapi { class FrontendRecordsSlice; +class DylibVerifier; /// Struct used for generating validating InstallAPI. /// The attributes captured represent all necessary information @@ -45,6 +46,9 @@ struct InstallAPIContext { /// DiagnosticsEngine for all error reporting. DiagnosticsEngine *Diags = nullptr; + /// Verifier when binary dylib is passed as input. + std::unique_ptr Verifier = nullptr; + /// File Path of output location. llvm::StringRef OutputLoc{}; diff --git a/clang/include/clang/InstallAPI/DylibVerifier.h b/clang/include/clang/InstallAPI/DylibVerifier.h index 1a6121b3a258b5..72c4743fdf65e0 100644 --- a/clang/include/clang/InstallAPI/DylibVerifier.h +++ b/clang/include/clang/InstallAPI/DylibVerifier.h @@ -9,10 +9,12 @@ #ifndef LLVM_CLANG_INSTALLAPI_DYLIBVERIFIER_H #define LLVM_CLANG_INSTALLAPI_DYLIBVERIFIER_H -#include "llvm/TextAPI/Target.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/InstallAPI/MachO.h" namespace clang { namespace installapi { +struct FrontendAttrs; /// A list of InstallAPI verification modes. enum class VerificationMode { @@ -22,6 +24,81 @@ enum class VerificationMode { Pedantic, }; +/// Service responsible to tracking state of verification across the +/// lifetime of InstallAPI. +/// As declarations are collected during AST traversal, they are +/// compared as symbols against what is available in the binary dylib. +class DylibVerifier { +private: + struct SymbolContext; + +public: + enum class Result { NoVerify, Ignore, Valid, Invalid }; + struct VerifierContext { +// Current target being verified against the AST. +llvm::MachO::Target Target; + +// Query state of verification after AST has been traversed. +Result FrontendState; + +// First error for AST traversal, which is tied to the target triple. +bool DiscoveredFirstError; + }; + + DylibVerifier() = default; + + DylibVerifier(llvm::MachO::Records &&Dylib, DiagnosticsEngine *Diag, +VerificationMode Mode, bool Demangle) + : Dylib(std::move(Dylib)), Diag(Diag), Mode(Mode), Demangle(Demangle), +Exports(std::make_unique()) {} + + Res
[llvm-branch-commits] [clang] [llvm] [InstallAPI] Introduce Basic Verifier (PR #85106)
https://github.com/cyndyishida updated https://github.com/llvm/llvm-project/pull/85106 >From 192f306f8d693af77e267e1caa52799a353f4064 Mon Sep 17 00:00:00 2001 From: Cyndy Ishida Date: Tue, 12 Mar 2024 20:56:23 -0700 Subject: [PATCH 1/3] [InstallAPI] Introduce Basic Verifier This adds basic support for calling the verifier on global declarations that are expected to represent symbol exports. The driver now exclusively uses this for knowing what symbols make up a TBD file. Future patches will actually check against the dylib's symbol table. --- clang/include/clang/AST/Availability.h| 3 + clang/include/clang/InstallAPI/Context.h | 4 + .../include/clang/InstallAPI/DylibVerifier.h | 79 ++- clang/include/clang/InstallAPI/Frontend.h | 1 - .../clang/InstallAPI/FrontendRecords.h| 49 ++-- clang/include/clang/InstallAPI/MachO.h| 3 + clang/lib/InstallAPI/CMakeLists.txt | 2 + clang/lib/InstallAPI/DylibVerifier.cpp| 212 ++ clang/lib/InstallAPI/Frontend.cpp | 49 ++-- clang/lib/InstallAPI/Visitor.cpp | 101 + clang/test/InstallAPI/asm.test| 90 .../clang-installapi/ClangInstallAPI.cpp | 12 +- clang/tools/clang-installapi/Options.cpp | 9 +- llvm/include/llvm/TextAPI/Record.h| 7 +- 14 files changed, 524 insertions(+), 97 deletions(-) create mode 100644 clang/lib/InstallAPI/DylibVerifier.cpp create mode 100644 clang/test/InstallAPI/asm.test diff --git a/clang/include/clang/AST/Availability.h b/clang/include/clang/AST/Availability.h index ae3acbeffe7f18..5cfbaf0cdfbd21 100644 --- a/clang/include/clang/AST/Availability.h +++ b/clang/include/clang/AST/Availability.h @@ -75,6 +75,9 @@ struct AvailabilityInfo { /// Determine if this AvailabilityInfo represents the default availability. bool isDefault() const { return *this == AvailabilityInfo(); } + /// Check if the symbol has been obsoleted. + bool isObsoleted() const { return !Obsoleted.empty(); } + /// Check if the symbol is unconditionally deprecated. /// /// i.e. \code __attribute__((deprecated)) \endcode diff --git a/clang/include/clang/InstallAPI/Context.h b/clang/include/clang/InstallAPI/Context.h index bdb576d7d85fb6..074ff6f969773c 100644 --- a/clang/include/clang/InstallAPI/Context.h +++ b/clang/include/clang/InstallAPI/Context.h @@ -18,6 +18,7 @@ namespace clang { namespace installapi { class FrontendRecordsSlice; +class DylibVerifier; /// Struct used for generating validating InstallAPI. /// The attributes captured represent all necessary information @@ -45,6 +46,9 @@ struct InstallAPIContext { /// DiagnosticsEngine for all error reporting. DiagnosticsEngine *Diags = nullptr; + /// Verifier when binary dylib is passed as input. + std::unique_ptr Verifier = nullptr; + /// File Path of output location. llvm::StringRef OutputLoc{}; diff --git a/clang/include/clang/InstallAPI/DylibVerifier.h b/clang/include/clang/InstallAPI/DylibVerifier.h index 1a6121b3a258b5..72c4743fdf65e0 100644 --- a/clang/include/clang/InstallAPI/DylibVerifier.h +++ b/clang/include/clang/InstallAPI/DylibVerifier.h @@ -9,10 +9,12 @@ #ifndef LLVM_CLANG_INSTALLAPI_DYLIBVERIFIER_H #define LLVM_CLANG_INSTALLAPI_DYLIBVERIFIER_H -#include "llvm/TextAPI/Target.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/InstallAPI/MachO.h" namespace clang { namespace installapi { +struct FrontendAttrs; /// A list of InstallAPI verification modes. enum class VerificationMode { @@ -22,6 +24,81 @@ enum class VerificationMode { Pedantic, }; +/// Service responsible to tracking state of verification across the +/// lifetime of InstallAPI. +/// As declarations are collected during AST traversal, they are +/// compared as symbols against what is available in the binary dylib. +class DylibVerifier { +private: + struct SymbolContext; + +public: + enum class Result { NoVerify, Ignore, Valid, Invalid }; + struct VerifierContext { +// Current target being verified against the AST. +llvm::MachO::Target Target; + +// Query state of verification after AST has been traversed. +Result FrontendState; + +// First error for AST traversal, which is tied to the target triple. +bool DiscoveredFirstError; + }; + + DylibVerifier() = default; + + DylibVerifier(llvm::MachO::Records &&Dylib, DiagnosticsEngine *Diag, +VerificationMode Mode, bool Demangle) + : Dylib(std::move(Dylib)), Diag(Diag), Mode(Mode), Demangle(Demangle), +Exports(std::make_unique()) {} + + Result verify(GlobalRecord *R, const FrontendAttrs *FA); + Result verify(ObjCInterfaceRecord *R, const FrontendAttrs *FA); + Result verify(ObjCIVarRecord *R, const FrontendAttrs *FA, +const StringRef SuperClass); + + /// Initialize target for verification. + void setTarget(const Target &T); + + /// Release ownership over exports. + std::unique_ptr
[llvm-branch-commits] [clang] [llvm] [InstallAPI] Introduce Basic Verifier (PR #85106)
https://github.com/cyndyishida updated https://github.com/llvm/llvm-project/pull/85106 >From 192f306f8d693af77e267e1caa52799a353f4064 Mon Sep 17 00:00:00 2001 From: Cyndy Ishida Date: Tue, 12 Mar 2024 20:56:23 -0700 Subject: [PATCH] [InstallAPI] Introduce Basic Verifier This adds basic support for calling the verifier on global declarations that are expected to represent symbol exports. The driver now exclusively uses this for knowing what symbols make up a TBD file. Future patches will actually check against the dylib's symbol table. --- clang/include/clang/AST/Availability.h| 3 + clang/include/clang/InstallAPI/Context.h | 4 + .../include/clang/InstallAPI/DylibVerifier.h | 79 ++- clang/include/clang/InstallAPI/Frontend.h | 1 - .../clang/InstallAPI/FrontendRecords.h| 49 ++-- clang/include/clang/InstallAPI/MachO.h| 3 + clang/lib/InstallAPI/CMakeLists.txt | 2 + clang/lib/InstallAPI/DylibVerifier.cpp| 212 ++ clang/lib/InstallAPI/Frontend.cpp | 49 ++-- clang/lib/InstallAPI/Visitor.cpp | 101 + clang/test/InstallAPI/asm.test| 90 .../clang-installapi/ClangInstallAPI.cpp | 12 +- clang/tools/clang-installapi/Options.cpp | 9 +- llvm/include/llvm/TextAPI/Record.h| 7 +- 14 files changed, 524 insertions(+), 97 deletions(-) create mode 100644 clang/lib/InstallAPI/DylibVerifier.cpp create mode 100644 clang/test/InstallAPI/asm.test diff --git a/clang/include/clang/AST/Availability.h b/clang/include/clang/AST/Availability.h index ae3acbeffe7f18..5cfbaf0cdfbd21 100644 --- a/clang/include/clang/AST/Availability.h +++ b/clang/include/clang/AST/Availability.h @@ -75,6 +75,9 @@ struct AvailabilityInfo { /// Determine if this AvailabilityInfo represents the default availability. bool isDefault() const { return *this == AvailabilityInfo(); } + /// Check if the symbol has been obsoleted. + bool isObsoleted() const { return !Obsoleted.empty(); } + /// Check if the symbol is unconditionally deprecated. /// /// i.e. \code __attribute__((deprecated)) \endcode diff --git a/clang/include/clang/InstallAPI/Context.h b/clang/include/clang/InstallAPI/Context.h index bdb576d7d85fb6..074ff6f969773c 100644 --- a/clang/include/clang/InstallAPI/Context.h +++ b/clang/include/clang/InstallAPI/Context.h @@ -18,6 +18,7 @@ namespace clang { namespace installapi { class FrontendRecordsSlice; +class DylibVerifier; /// Struct used for generating validating InstallAPI. /// The attributes captured represent all necessary information @@ -45,6 +46,9 @@ struct InstallAPIContext { /// DiagnosticsEngine for all error reporting. DiagnosticsEngine *Diags = nullptr; + /// Verifier when binary dylib is passed as input. + std::unique_ptr Verifier = nullptr; + /// File Path of output location. llvm::StringRef OutputLoc{}; diff --git a/clang/include/clang/InstallAPI/DylibVerifier.h b/clang/include/clang/InstallAPI/DylibVerifier.h index 1a6121b3a258b5..72c4743fdf65e0 100644 --- a/clang/include/clang/InstallAPI/DylibVerifier.h +++ b/clang/include/clang/InstallAPI/DylibVerifier.h @@ -9,10 +9,12 @@ #ifndef LLVM_CLANG_INSTALLAPI_DYLIBVERIFIER_H #define LLVM_CLANG_INSTALLAPI_DYLIBVERIFIER_H -#include "llvm/TextAPI/Target.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/InstallAPI/MachO.h" namespace clang { namespace installapi { +struct FrontendAttrs; /// A list of InstallAPI verification modes. enum class VerificationMode { @@ -22,6 +24,81 @@ enum class VerificationMode { Pedantic, }; +/// Service responsible to tracking state of verification across the +/// lifetime of InstallAPI. +/// As declarations are collected during AST traversal, they are +/// compared as symbols against what is available in the binary dylib. +class DylibVerifier { +private: + struct SymbolContext; + +public: + enum class Result { NoVerify, Ignore, Valid, Invalid }; + struct VerifierContext { +// Current target being verified against the AST. +llvm::MachO::Target Target; + +// Query state of verification after AST has been traversed. +Result FrontendState; + +// First error for AST traversal, which is tied to the target triple. +bool DiscoveredFirstError; + }; + + DylibVerifier() = default; + + DylibVerifier(llvm::MachO::Records &&Dylib, DiagnosticsEngine *Diag, +VerificationMode Mode, bool Demangle) + : Dylib(std::move(Dylib)), Diag(Diag), Mode(Mode), Demangle(Demangle), +Exports(std::make_unique()) {} + + Result verify(GlobalRecord *R, const FrontendAttrs *FA); + Result verify(ObjCInterfaceRecord *R, const FrontendAttrs *FA); + Result verify(ObjCIVarRecord *R, const FrontendAttrs *FA, +const StringRef SuperClass); + + /// Initialize target for verification. + void setTarget(const Target &T); + + /// Release ownership over exports. + std::unique_ptr getE
[llvm-branch-commits] [clang] [InstallAPI] Verify that declarations in headers map to exports found in dylib (PR #85348)
https://github.com/cyndyishida created https://github.com/llvm/llvm-project/pull/85348 * This completes support for verifying every declaration found in a header is discovered in the dylib. Diagnostics are reported for each class for differences that are representable in TBD files. * This patch also now captures unavailable attributes that depend on target triples. This is needed for proper tbd file generation. >From 56efc49e5616b1b9958263ae89a914d19421b4bd Mon Sep 17 00:00:00 2001 From: Cyndy Ishida Date: Wed, 13 Mar 2024 18:57:14 -0700 Subject: [PATCH] [InstallAPI] Verify that declarations in header map to symbols found in dylib * This patch completes support for verifying every declaration found in a header is discovered in the dylib. Diagnostics are reported for each class for differences that is representable in TBD files. * This patch also now captures unavailable attributes that depend on target triples. This is needed for proper tbd file generation. --- clang/include/clang/AST/Availability.h| 13 +- .../clang/Basic/DiagnosticInstallAPIKinds.td | 23 + .../include/clang/InstallAPI/DylibVerifier.h | 57 +- clang/include/clang/InstallAPI/Frontend.h | 3 + clang/include/clang/InstallAPI/MachO.h| 1 + clang/lib/AST/Availability.cpp| 6 +- clang/lib/InstallAPI/DylibVerifier.cpp| 326 - clang/lib/InstallAPI/Visitor.cpp | 2 +- clang/test/InstallAPI/availability.test | 626 ++ clang/test/InstallAPI/diagnostics-cpp.test| 461 + clang/test/InstallAPI/hiddens.test| 262 .../clang-installapi/ClangInstallAPI.cpp | 6 +- clang/tools/clang-installapi/Options.cpp | 4 +- 13 files changed, 1766 insertions(+), 24 deletions(-) create mode 100644 clang/test/InstallAPI/availability.test create mode 100644 clang/test/InstallAPI/diagnostics-cpp.test create mode 100644 clang/test/InstallAPI/hiddens.test diff --git a/clang/include/clang/AST/Availability.h b/clang/include/clang/AST/Availability.h index 5cfbaf0cdfbd21..2ccc607d4b63dc 100644 --- a/clang/include/clang/AST/Availability.h +++ b/clang/include/clang/AST/Availability.h @@ -67,6 +67,7 @@ struct AvailabilityInfo { VersionTuple Introduced; VersionTuple Deprecated; VersionTuple Obsoleted; + bool Unavailable = false; bool UnconditionallyDeprecated = false; bool UnconditionallyUnavailable = false; @@ -78,6 +79,9 @@ struct AvailabilityInfo { /// Check if the symbol has been obsoleted. bool isObsoleted() const { return !Obsoleted.empty(); } + /// Check if the symbol is unavailable for the active platform and os version. + bool isUnavailable() const { return Unavailable; } + /// Check if the symbol is unconditionally deprecated. /// /// i.e. \code __attribute__((deprecated)) \endcode @@ -91,9 +95,10 @@ struct AvailabilityInfo { } AvailabilityInfo(StringRef Domain, VersionTuple I, VersionTuple D, - VersionTuple O, bool UD, bool UU) + VersionTuple O, bool U, bool UD, bool UU) : Domain(Domain), Introduced(I), Deprecated(D), Obsoleted(O), -UnconditionallyDeprecated(UD), UnconditionallyUnavailable(UU) {} +Unavailable(U), UnconditionallyDeprecated(UD), +UnconditionallyUnavailable(UU) {} friend bool operator==(const AvailabilityInfo &Lhs, const AvailabilityInfo &Rhs); @@ -105,10 +110,10 @@ struct AvailabilityInfo { inline bool operator==(const AvailabilityInfo &Lhs, const AvailabilityInfo &Rhs) { return std::tie(Lhs.Introduced, Lhs.Deprecated, Lhs.Obsoleted, - Lhs.UnconditionallyDeprecated, + Lhs.Unavailable, Lhs.UnconditionallyDeprecated, Lhs.UnconditionallyUnavailable) == std::tie(Rhs.Introduced, Rhs.Deprecated, Rhs.Obsoleted, - Rhs.UnconditionallyDeprecated, + Rhs.Unavailable, Rhs.UnconditionallyDeprecated, Rhs.UnconditionallyUnavailable); } diff --git a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td index 31be4f09cf3a1c..5ed2e23425dc5f 100644 --- a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td +++ b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td @@ -17,4 +17,27 @@ def err_no_install_name : Error<"no install name specified: add -install_name ; } // end of command line category. +let CategoryName = "Verification" in { +def warn_target: Warning<"violations found for %0">; +def err_library_missing_symbol : Error<"declaration has external linkage, but dynamic library doesn't have symbol '%0'">; +def warn_library_missing_symbol : Warning<"declaration has external linkage, but dynamic library doesn't have symbol '%0'">; +def err_library_hidden_symbol : Error<"declaration has external linkage, but symbol has internal linkage in dynamic library
[llvm-branch-commits] [llvm] [TextAPI] Add support to convert RecordSlices -> InterfaceFile (PR #75007)
https://github.com/cyndyishida created https://github.com/llvm/llvm-project/pull/75007 *Note*: This is a part of a stack. Please review https://github.com/llvm/llvm-project/pull/75006 first. Introduce RecordVisitor. This is used for different clients that want to extract information out of RecordSlice types. The first and immediate use case is for serializing symbol information into TBD files. >From d5e97577651b558b56de64f9ed74cd7893cea7ec Mon Sep 17 00:00:00 2001 From: Cyndy Ishida Date: Thu, 7 Dec 2023 13:57:17 -0800 Subject: [PATCH] [TextAPI] Add support to convert RecordSlices -> InterfaceFile Introduce RecordVisitor. This is used for different clients that want to extract information out of RecordSlice types. The first and immediate usecase is for serializing symbol information into TBD files. --- llvm/include/llvm/TextAPI/DylibReader.h | 5 + llvm/include/llvm/TextAPI/Record.h| 9 +- llvm/include/llvm/TextAPI/RecordVisitor.h | 54 ++ llvm/include/llvm/TextAPI/RecordsSlice.h | 6 +- llvm/lib/TextAPI/CMakeLists.txt | 1 + llvm/lib/TextAPI/DylibReader.cpp | 10 ++ llvm/lib/TextAPI/RecordVisitor.cpp| 67 llvm/lib/TextAPI/RecordsSlice.cpp | 124 +- 8 files changed, 272 insertions(+), 4 deletions(-) create mode 100644 llvm/include/llvm/TextAPI/RecordVisitor.h create mode 100644 llvm/lib/TextAPI/RecordVisitor.cpp diff --git a/llvm/include/llvm/TextAPI/DylibReader.h b/llvm/include/llvm/TextAPI/DylibReader.h index aa98df99c99fa..3d4ddb9745ddd 100644 --- a/llvm/include/llvm/TextAPI/DylibReader.h +++ b/llvm/include/llvm/TextAPI/DylibReader.h @@ -42,6 +42,11 @@ struct ParseOption { /// \return List of record slices. Expected readFile(MemoryBufferRef Buffer, const ParseOption &Opt); +/// Get TAPI file representation of binary dylib. +/// +/// \param Buffer Data that points to dylib. +Expected> get(MemoryBufferRef Buffer); + } // namespace DylibReader } // end namespace MachO. diff --git a/llvm/include/llvm/TextAPI/Record.h b/llvm/include/llvm/TextAPI/Record.h index 5317982cbfa2b..ec93098b320ce 100644 --- a/llvm/include/llvm/TextAPI/Record.h +++ b/llvm/include/llvm/TextAPI/Record.h @@ -14,6 +14,7 @@ #ifndef LLVM_TEXTAPI_RECORD_H #define LLVM_TEXTAPI_RECORD_H +#include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" #include "llvm/TextAPI/Symbol.h" @@ -50,7 +51,7 @@ class Record { public: Record() = default; Record(StringRef Name, RecordLinkage Linkage, SymbolFlags Flags) - : Name(Name), Linkage(Linkage), Flags(Flags) {} + : Name(Name), Linkage(Linkage), Flags(mergeFlags(Flags, Linkage)) {} bool isWeakDefined() const { return (Flags & SymbolFlags::WeakDefined) == SymbolFlags::WeakDefined; @@ -79,6 +80,10 @@ class Record { bool isRexported() const { return Linkage == RecordLinkage::Rexported; } StringRef getName() const { return Name; } + SymbolFlags getFlags() const { return Flags; } + +private: + SymbolFlags mergeFlags(SymbolFlags Flags, RecordLinkage Linkage); protected: StringRef Name; @@ -137,6 +142,7 @@ class ObjCContainerRecord : public Record { ObjCIVarRecord *addObjCIVar(StringRef IVar, RecordLinkage Linkage); ObjCIVarRecord *findObjCIVar(StringRef IVar) const; + std::vector getObjCIVars() const; private: RecordMap IVars; @@ -163,6 +169,7 @@ class ObjCInterfaceRecord : public ObjCContainerRecord { bool hasExceptionAttribute() const { return HasEHType; } bool addObjCCategory(ObjCCategoryRecord *Record); + std::vector getObjCCategories() const; private: bool HasEHType; diff --git a/llvm/include/llvm/TextAPI/RecordVisitor.h b/llvm/include/llvm/TextAPI/RecordVisitor.h new file mode 100644 index 0..34e43f5b0027f --- /dev/null +++ b/llvm/include/llvm/TextAPI/RecordVisitor.h @@ -0,0 +1,54 @@ +//===- llvm/TextAPI/RecordSlice.h - TAPI RecordSlice *- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +/// +/// Defines the TAPI Record Visitor. +/// +//===--===// + +#ifndef LLVM_TEXTAPI_RECORDVISITOR_H +#define LLVM_TEXTAPI_RECORDVISITOR_H + +#include "llvm/TextAPI/Record.h" +#include "llvm/TextAPI/SymbolSet.h" + +namespace llvm { +namespace MachO { + +/// Base class for any usage of traversing over collected Records. +class RecordVisitor { +public: + virtual ~RecordVisitor(); + + virtual void visitGlobal(const GlobalRecord &) = 0; + virtual void visitObjCInterface(const ObjCInterfaceRecord &); + virtual void visitObjCCategory(const ObjCCategoryRecord &); +}; + +/// Specialized RecordVisitor for collecting exported symbols +/// a
[llvm-branch-commits] [llvm] [TextAPI] Add support to convert RecordSlices -> InterfaceFile (PR #75007)
https://github.com/cyndyishida updated https://github.com/llvm/llvm-project/pull/75007 >From d5e97577651b558b56de64f9ed74cd7893cea7ec Mon Sep 17 00:00:00 2001 From: Cyndy Ishida Date: Thu, 7 Dec 2023 13:57:17 -0800 Subject: [PATCH 1/2] [TextAPI] Add support to convert RecordSlices -> InterfaceFile Introduce RecordVisitor. This is used for different clients that want to extract information out of RecordSlice types. The first and immediate usecase is for serializing symbol information into TBD files. --- llvm/include/llvm/TextAPI/DylibReader.h | 5 + llvm/include/llvm/TextAPI/Record.h| 9 +- llvm/include/llvm/TextAPI/RecordVisitor.h | 54 ++ llvm/include/llvm/TextAPI/RecordsSlice.h | 6 +- llvm/lib/TextAPI/CMakeLists.txt | 1 + llvm/lib/TextAPI/DylibReader.cpp | 10 ++ llvm/lib/TextAPI/RecordVisitor.cpp| 67 llvm/lib/TextAPI/RecordsSlice.cpp | 124 +- 8 files changed, 272 insertions(+), 4 deletions(-) create mode 100644 llvm/include/llvm/TextAPI/RecordVisitor.h create mode 100644 llvm/lib/TextAPI/RecordVisitor.cpp diff --git a/llvm/include/llvm/TextAPI/DylibReader.h b/llvm/include/llvm/TextAPI/DylibReader.h index aa98df99c99fa6..3d4ddb9745ddd4 100644 --- a/llvm/include/llvm/TextAPI/DylibReader.h +++ b/llvm/include/llvm/TextAPI/DylibReader.h @@ -42,6 +42,11 @@ struct ParseOption { /// \return List of record slices. Expected readFile(MemoryBufferRef Buffer, const ParseOption &Opt); +/// Get TAPI file representation of binary dylib. +/// +/// \param Buffer Data that points to dylib. +Expected> get(MemoryBufferRef Buffer); + } // namespace DylibReader } // end namespace MachO. diff --git a/llvm/include/llvm/TextAPI/Record.h b/llvm/include/llvm/TextAPI/Record.h index 5317982cbfa2bf..ec93098b320ce1 100644 --- a/llvm/include/llvm/TextAPI/Record.h +++ b/llvm/include/llvm/TextAPI/Record.h @@ -14,6 +14,7 @@ #ifndef LLVM_TEXTAPI_RECORD_H #define LLVM_TEXTAPI_RECORD_H +#include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" #include "llvm/TextAPI/Symbol.h" @@ -50,7 +51,7 @@ class Record { public: Record() = default; Record(StringRef Name, RecordLinkage Linkage, SymbolFlags Flags) - : Name(Name), Linkage(Linkage), Flags(Flags) {} + : Name(Name), Linkage(Linkage), Flags(mergeFlags(Flags, Linkage)) {} bool isWeakDefined() const { return (Flags & SymbolFlags::WeakDefined) == SymbolFlags::WeakDefined; @@ -79,6 +80,10 @@ class Record { bool isRexported() const { return Linkage == RecordLinkage::Rexported; } StringRef getName() const { return Name; } + SymbolFlags getFlags() const { return Flags; } + +private: + SymbolFlags mergeFlags(SymbolFlags Flags, RecordLinkage Linkage); protected: StringRef Name; @@ -137,6 +142,7 @@ class ObjCContainerRecord : public Record { ObjCIVarRecord *addObjCIVar(StringRef IVar, RecordLinkage Linkage); ObjCIVarRecord *findObjCIVar(StringRef IVar) const; + std::vector getObjCIVars() const; private: RecordMap IVars; @@ -163,6 +169,7 @@ class ObjCInterfaceRecord : public ObjCContainerRecord { bool hasExceptionAttribute() const { return HasEHType; } bool addObjCCategory(ObjCCategoryRecord *Record); + std::vector getObjCCategories() const; private: bool HasEHType; diff --git a/llvm/include/llvm/TextAPI/RecordVisitor.h b/llvm/include/llvm/TextAPI/RecordVisitor.h new file mode 100644 index 00..34e43f5b0027f8 --- /dev/null +++ b/llvm/include/llvm/TextAPI/RecordVisitor.h @@ -0,0 +1,54 @@ +//===- llvm/TextAPI/RecordSlice.h - TAPI RecordSlice *- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +/// +/// Defines the TAPI Record Visitor. +/// +//===--===// + +#ifndef LLVM_TEXTAPI_RECORDVISITOR_H +#define LLVM_TEXTAPI_RECORDVISITOR_H + +#include "llvm/TextAPI/Record.h" +#include "llvm/TextAPI/SymbolSet.h" + +namespace llvm { +namespace MachO { + +/// Base class for any usage of traversing over collected Records. +class RecordVisitor { +public: + virtual ~RecordVisitor(); + + virtual void visitGlobal(const GlobalRecord &) = 0; + virtual void visitObjCInterface(const ObjCInterfaceRecord &); + virtual void visitObjCCategory(const ObjCCategoryRecord &); +}; + +/// Specialized RecordVisitor for collecting exported symbols +/// and undefined symbols if RecordSlice being visited represents a +/// flat-namespaced library. +class SymbolConverter : public RecordVisitor { +public: + SymbolConverter(SymbolSet *Symbols, const Target &T, + const bool RecordUndefs = false) + : Symbols(Symbols), Targ(T), RecordUndefs(
[llvm-branch-commits] [llvm] [readtapi] Setup simple stubify support (PR #75008)
https://github.com/cyndyishida closed https://github.com/llvm/llvm-project/pull/75008 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [lld] e6c034b - [TextAPI] Implement TBDv5 Reader
Author: Cyndy Ishida Date: 2023-02-16T13:51:08-08:00 New Revision: e6c034b0e43a062274e5bfefb47bd95201ec5899 URL: https://github.com/llvm/llvm-project/commit/e6c034b0e43a062274e5bfefb47bd95201ec5899 DIFF: https://github.com/llvm/llvm-project/commit/e6c034b0e43a062274e5bfefb47bd95201ec5899.diff LOG: [TextAPI] Implement TBDv5 Reader Introduce initial reader for TBDv5 which is in JSON. This captures all the currently understood fields within the internal structure `InterfaceFile`. New fields & follow up tests will be followed up in future PRs. Differential Revision: https://reviews.llvm.org/D144156 Added: llvm/lib/TextAPI/TextStubV5.cpp llvm/unittests/TextAPI/TextStubV5Tests.cpp Modified: lld/test/MachO/Inputs/libStubLink.tbd lld/test/MachO/invalid/invalid-stub.s lld/test/MachO/tapi-link.s llvm/include/llvm/TextAPI/InterfaceFile.h llvm/lib/TextAPI/CMakeLists.txt llvm/lib/TextAPI/TextStub.cpp llvm/lib/TextAPI/TextStubCommon.cpp llvm/lib/TextAPI/TextStubCommon.h llvm/test/Object/Inputs/tapi-v4-watchos.tbd llvm/test/tools/llvm-tapi-diff/Inputs/v4A.tbd llvm/test/tools/llvm-tapi-diff/Inputs/v4B.tbd llvm/test/tools/llvm-tapi-diff/Inputs/v4C.tbd llvm/test/tools/llvm-tapi-diff/Inputs/v4D.tbd llvm/test/tools/llvm-tapi-diff/Inputs/v4E.tbd llvm/unittests/TextAPI/CMakeLists.txt llvm/unittests/TextAPI/TextStubHelpers.h llvm/unittests/TextAPI/TextStubV4Tests.cpp Removed: diff --git a/lld/test/MachO/Inputs/libStubLink.tbd b/lld/test/MachO/Inputs/libStubLink.tbd index 6e6237edbc8a2..eaf216d0a1f3f 100644 --- a/lld/test/MachO/Inputs/libStubLink.tbd +++ b/lld/test/MachO/Inputs/libStubLink.tbd @@ -22,3 +22,4 @@ current-version: 1.0.0 exports: - targets: [ arm64-ios-simulator ] symbols: [ _arm64_sim_only ] +... diff --git a/lld/test/MachO/invalid/invalid-stub.s b/lld/test/MachO/invalid/invalid-stub.s index 997594918cd53..a80dfa6f8f15c 100644 --- a/lld/test/MachO/invalid/invalid-stub.s +++ b/lld/test/MachO/invalid/invalid-stub.s @@ -7,9 +7,8 @@ # RUN: not %lld -L%t -linvalidYAML %t/test.o -o %t/test 2>&1 | FileCheck %s -DDIR=%t # RUN: not %lld -F%t -framework invalidYAML %t/test.o -o %t/test 2>&1 | FileCheck %s -DDIR=%t --check-prefix=CHECK-FRAMEWORK -# CHECK: could not load TAPI file at [[DIR]]{{[\\/]}}libinvalidYAML.tbd: malformed file -# CHECK-FRAMEWORK: could not load TAPI file at [[DIR]]{{[\\/]}}invalidYAML.framework{{[\\/]}}invalidYAML.tbd: malformed file - +# CHECK: could not load TAPI file at [[DIR]]{{[\\/]}}libinvalidYAML.tbd: unsupported file type +# CHECK-FRAMEWORK: could not load TAPI file at [[DIR]]{{[\\/]}}invalidYAML.framework{{[\\/]}}invalidYAML.tbd: unsupported file type .globl _main _main: ret diff --git a/lld/test/MachO/tapi-link.s b/lld/test/MachO/tapi-link.s index b2aa2f208281e..af205b6c24e99 100644 --- a/lld/test/MachO/tapi-link.s +++ b/lld/test/MachO/tapi-link.s @@ -121,7 +121,6 @@ exports: re-exports: [ 'libNested.dylib' ] ... -## This tests that weak and thread-local symbols are imported as such. #--- libTlvWeak.tbd --- !tapi-tbd tbd-version: 4 @@ -131,8 +130,8 @@ uuids: value:---- install-name: '/usr/lib/libTlvWeak.dylib' current-version: 0001.001.1 -exports: +exports:# Validate weak & thread-local symbols - targets: [ x86_64-macos ] weak-symbols: [ _weak ] thread-local-symbols: [ _tlv ] +... diff --git a/llvm/include/llvm/TextAPI/InterfaceFile.h b/llvm/include/llvm/TextAPI/InterfaceFile.h index 5f07397adacaa..cb8ec4b8f76d6 100644 --- a/llvm/include/llvm/TextAPI/InterfaceFile.h +++ b/llvm/include/llvm/TextAPI/InterfaceFile.h @@ -66,6 +66,9 @@ enum FileType : unsigned { /// Text-based stub file (.tbd) version 4.0 TBD_V4 = 1U << 3, + /// Text-based stub file (.tbd) version 5.0 + TBD_V5 = 1U << 4, + All = ~0U, LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/All), diff --git a/llvm/lib/TextAPI/CMakeLists.txt b/llvm/lib/TextAPI/CMakeLists.txt index c7e9e1009ab22..1714ce33ef205 100644 --- a/llvm/lib/TextAPI/CMakeLists.txt +++ b/llvm/lib/TextAPI/CMakeLists.txt @@ -2,6 +2,7 @@ add_llvm_component_library(LLVMTextAPI Architecture.cpp ArchitectureSet.cpp InterfaceFile.cpp + TextStubV5.cpp PackedVersion.cpp Platform.cpp Symbol.cpp diff --git a/llvm/lib/TextAPI/TextStub.cpp b/llvm/lib/TextAPI/TextStub.cpp index ff93e43356f73..73cb61472bff3 100644 --- a/llvm/lib/TextAPI/TextStub.cpp +++ b/llvm/lib/TextAPI/TextStub.cpp @@ -258,16 +258,6 @@ struct UUIDv4 { UUIDv4(const Target &TargetID, const std::string &Value) : TargetID(TargetID), Value(Value) {} }; - -// clang-format off -enum TBDFlags : unsigned { - None = 0U, - FlatNamespace= 1U << 0, - NotApplicationExtensi
[llvm-branch-commits] [llvm] 79aeef6 - [TextAPI] Capture new properties from TBD to InterfaceFile
Author: Cyndy Ishida Date: 2023-02-16T13:52:12-08:00 New Revision: 79aeef6900dbdf683f44499e9cc83f683f3bfbf7 URL: https://github.com/llvm/llvm-project/commit/79aeef6900dbdf683f44499e9cc83f683f3bfbf7 DIFF: https://github.com/llvm/llvm-project/commit/79aeef6900dbdf683f44499e9cc83f683f3bfbf7.diff LOG: [TextAPI] Capture new properties from TBD to InterfaceFile * Deployment Versions for targets * Run Search Paths * Text vs Data Segment attributes to symbols Differential Revision: https://reviews.llvm.org/D144158 Added: Modified: llvm/include/llvm/TextAPI/InterfaceFile.h llvm/include/llvm/TextAPI/Symbol.h llvm/include/llvm/TextAPI/Target.h llvm/lib/TextAPI/InterfaceFile.cpp llvm/lib/TextAPI/Target.cpp llvm/lib/TextAPI/TextStubV5.cpp llvm/unittests/TextAPI/TextStubHelpers.h llvm/unittests/TextAPI/TextStubV3Tests.cpp llvm/unittests/TextAPI/TextStubV4Tests.cpp llvm/unittests/TextAPI/TextStubV5Tests.cpp Removed: diff --git a/llvm/include/llvm/TextAPI/InterfaceFile.h b/llvm/include/llvm/TextAPI/InterfaceFile.h index cb8ec4b8f76d6..c32917da69f8a 100644 --- a/llvm/include/llvm/TextAPI/InterfaceFile.h +++ b/llvm/include/llvm/TextAPI/InterfaceFile.h @@ -348,6 +348,18 @@ class InterfaceFile { return Documents; } + /// Set the runpath search paths. + /// \param InputTarget The target applicable to runpath search path. + /// \param RPath The name of runpath. + void addRPath(const Target &InputTarget, StringRef RPath); + + /// Get the list of runpath search paths. + /// + /// \return Returns a list of the rpaths per target. + const std::vector> &rpaths() const { +return RPaths; + } + /// Add a symbol to the symbols list or extend an existing one. void addSymbol(SymbolKind Kind, StringRef Name, const TargetList &Targets, SymbolFlags Flags = SymbolFlags::None); @@ -435,6 +447,7 @@ class InterfaceFile { std::vector ReexportedLibraries; std::vector> Documents; std::vector> UUIDs; + std::vector> RPaths; SymbolMapType Symbols; InterfaceFile *Parent = nullptr; }; diff --git a/llvm/include/llvm/TextAPI/Symbol.h b/llvm/include/llvm/TextAPI/Symbol.h index 1c25295b299d3..6cb462ad403b3 100644 --- a/llvm/include/llvm/TextAPI/Symbol.h +++ b/llvm/include/llvm/TextAPI/Symbol.h @@ -40,7 +40,13 @@ enum class SymbolFlags : uint8_t { /// Rexported Rexported= 1U << 4, - LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/Rexported), + /// Data Segment + Data = 1U << 5, + + /// Text Segment + Text = 1U << 6, + + LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/Text), }; // clang-format on @@ -93,6 +99,14 @@ class Symbol { return (Flags & SymbolFlags::Rexported) == SymbolFlags::Rexported; } + bool isData() const { +return (Flags & SymbolFlags::Data) == SymbolFlags::Data; + } + + bool isText() const { +return (Flags & SymbolFlags::Text) == SymbolFlags::Text; + } + using const_target_iterator = TargetList::const_iterator; using const_target_range = llvm::iterator_range; const_target_range targets() const { return {Targets}; } diff --git a/llvm/include/llvm/TextAPI/Target.h b/llvm/include/llvm/TextAPI/Target.h index fbb76295f706a..dc0e4f92ae802 100644 --- a/llvm/include/llvm/TextAPI/Target.h +++ b/llvm/include/llvm/TextAPI/Target.h @@ -10,6 +10,8 @@ #define LLVM_TEXTAPI_TARGET_H #include "llvm/Support/Error.h" +#include "llvm/Support/VersionTuple.h" +#include "llvm/TargetParser/Triple.h" #include "llvm/TextAPI/Architecture.h" #include "llvm/TextAPI/ArchitectureSet.h" #include "llvm/TextAPI/Platform.h" @@ -26,10 +28,12 @@ namespace MachO { class Target { public: Target() = default; - Target(Architecture Arch, PlatformType Platform) - : Arch(Arch), Platform(Platform) {} + Target(Architecture Arch, PlatformType Platform, + VersionTuple MinDeployment = {}) + : Arch(Arch), Platform(Platform), MinDeployment(MinDeployment) {} explicit Target(const llvm::Triple &Triple) - : Arch(mapToArchitecture(Triple)), Platform(mapToPlatformType(Triple)) {} + : Arch(mapToArchitecture(Triple)), Platform(mapToPlatformType(Triple)), +MinDeployment(Triple.getOSVersion()) {} static llvm::Expected create(StringRef Target); @@ -37,6 +41,7 @@ class Target { Architecture Arch; PlatformType Platform; + VersionTuple MinDeployment; }; inline bool operator==(const Target &LHS, const Target &RHS) { diff --git a/llvm/lib/TextAPI/InterfaceFile.cpp b/llvm/lib/TextAPI/InterfaceFile.cpp index 1156a39228e7a..f9b5e95d5f6fb 100644 --- a/llvm/lib/TextAPI/InterfaceFile.cpp +++ b/llvm/lib/TextAPI/InterfaceFile.cpp @@ -71,6 +71,19 @@ void InterfaceFile::addParentUmbrella(const Target &Target_, StringRef Parent) { ParentUmbrellas.emplace(Iter, Target_, std::string(Parent)); } +void InterfaceFile::addRPath(const Target &InputTarget, St
[llvm-branch-commits] [llvm] 7f25460 - [text] WIP writerf
Author: Cyndy Ishida Date: 2023-02-16T13:53:38-08:00 New Revision: 7f254605c66e0260f8b169cd62b094e8a56ddb70 URL: https://github.com/llvm/llvm-project/commit/7f254605c66e0260f8b169cd62b094e8a56ddb70 DIFF: https://github.com/llvm/llvm-project/commit/7f254605c66e0260f8b169cd62b094e8a56ddb70.diff LOG: [text] WIP writerf Added: Modified: llvm/lib/TextAPI/TextStub.cpp llvm/lib/TextAPI/TextStubCommon.h llvm/lib/TextAPI/TextStubV5.cpp llvm/unittests/TextAPI/TextStubV5Tests.cpp Removed: diff --git a/llvm/lib/TextAPI/TextStub.cpp b/llvm/lib/TextAPI/TextStub.cpp index 73cb61472bff..af60bd794e2d 100644 --- a/llvm/lib/TextAPI/TextStub.cpp +++ b/llvm/lib/TextAPI/TextStub.cpp @@ -1163,6 +1163,12 @@ Error TextAPIWriter::writeToStream(raw_ostream &OS, const InterfaceFile &File) { TextAPIContext Ctx; Ctx.Path = std::string(File.getPath()); Ctx.FileKind = File.getFileType(); + + // Write out in JSON format. + if (Ctx.FileKind >= FileType::TBD_V5) { +return serializeInterfaceFileToJSON(OS, File); + } + llvm::yaml::Output YAMLOut(OS, &Ctx, /*WrapColumn=*/80); std::vector Files; diff --git a/llvm/lib/TextAPI/TextStubCommon.h b/llvm/lib/TextAPI/TextStubCommon.h index 51b423137f4e..6ee5b3931831 100644 --- a/llvm/lib/TextAPI/TextStubCommon.h +++ b/llvm/lib/TextAPI/TextStubCommon.h @@ -45,6 +45,8 @@ class PackedVersion; Expected> getInterfaceFileFromJSON(StringRef JSON); + +Error serializeInterfaceFileToJSON(raw_ostream &OS, const InterfaceFile &File); } // namespace MachO namespace yaml { diff --git a/llvm/lib/TextAPI/TextStubV5.cpp b/llvm/lib/TextAPI/TextStubV5.cpp index d19f7dd457f3..abd3f6030e96 100644 --- a/llvm/lib/TextAPI/TextStubV5.cpp +++ b/llvm/lib/TextAPI/TextStubV5.cpp @@ -155,6 +155,10 @@ static llvm::SmallString<128> getParseErrorMsg(TBDKey Key) { return {"invalid ", Keys[Key], " section"}; } +static llvm::SmallString<128> getSerializeErrorMsg(TBDKey Key) { + return {"missing ", Keys[Key], " information"}; +} + class JSONStubError : public llvm::ErrorInfo { public: JSONStubError(Twine ErrMsg) : Message(ErrMsg.str()) {} @@ -710,3 +714,78 @@ MachO::getInterfaceFileFromJSON(StringRef JSON) { } return std::move(IF); } + +namespace { + +bool insertNonEmptyArray(Object &Obj, TBDKey Key, Array &&Contents) { + if (Contents.empty()) +return false; + Obj[Keys[Key]] = std::move(Contents); + return true; +} + +Array serializeTargets(const InterfaceFile *File) { + Array Targets; + for (const auto Targ : File->targets()) { +Object TargetInfo; +TargetInfo[Keys[TBDKey::Deployment]] = Targ.MinDeployment.getAsString(); +TargetInfo[Keys[TBDKey::Target]] = +(getArchitectureName(Targ.Arch) + "-" + getPlatformName(Targ.Platform)) +.str(); +Targets.emplace_back(std::move(TargetInfo)); + } + return Targets; +} + +Array serializeInstallNames(const InterfaceFile *File) { + Array Names; + return Names; +} + +Expected serializeIF(const InterfaceFile *File) { + Object Library; + + // Handle required keys. + if (!insertNonEmptyArray(Library, TBDKey::TargetInfo, serializeTargets(File))) +return make_error(getSerializeErrorMsg(TBDKey::TargetInfo)); + + // if (!insertNonEmptyArray(Library, TBDKey::InstallName, + // serializeInstallNames(File))) + // return + // make_error(getSerializeErrorMsg(TBDKey::InstallName)); + + return Library; +} + +Expected getJSON(const InterfaceFile *File) { + assert(File->getFileType() == FileType::TBD_V5 && + "unexpected json file format version"); + Object Root; + + Array Documents; + auto MainLibOrErr = serializeIF(File); + if (!MainLibOrErr) +return MainLibOrErr; + Documents.emplace_back(std::move(*MainLibOrErr)); + for (const auto &Doc : File->documents()) { +auto LibOrErr = serializeIF(Doc.get()); +if (!LibOrErr) + return LibOrErr; +Documents.emplace_back(std::move(*LibOrErr)); + } + + Root[Keys[TBDKey::TBDVersion]] = 5; + Root[Keys[TBDKey::Document]] = std::move(Documents); + return Root; +} + +} // namespace + +Error MachO::serializeInterfaceFileToJSON(raw_ostream &OS, + const InterfaceFile &File) { + auto TextFile = getJSON(&File); + if (!TextFile) +return TextFile.takeError(); + OS << formatv("{0:2}", Value(std::move(*TextFile))) << "\n"; + return Error::success(); +} diff --git a/llvm/unittests/TextAPI/TextStubV5Tests.cpp b/llvm/unittests/TextAPI/TextStubV5Tests.cpp index 5b0b596b1cd1..8ccde0c79483 100644 --- a/llvm/unittests/TextAPI/TextStubV5Tests.cpp +++ b/llvm/unittests/TextAPI/TextStubV5Tests.cpp @@ -519,4 +519,154 @@ TEST(TBDv5, ReadMultipleDocuments) { std::equal(Exports.begin(), Exports.end(), std::begin(ExpectedExports))); } +TEST(TBDv5, WriteFile) { + static const char TBDv5File[] = R"({ +"tapi_tbd_version": 5, +"files": [ +{ +"target_info": [ +
[llvm-branch-commits] [llvm] c3d171f - [llvm][TextAPI] add simulators to output
Author: Cyndy Ishida Date: 2020-02-11T10:32:48-08:00 New Revision: c3d171f8828eb4fe0a32df3119d7ac69af948285 URL: https://github.com/llvm/llvm-project/commit/c3d171f8828eb4fe0a32df3119d7ac69af948285 DIFF: https://github.com/llvm/llvm-project/commit/c3d171f8828eb4fe0a32df3119d7ac69af948285.diff LOG: [llvm][TextAPI] add simulators to output Summary: * for <= tbd_v3, simulator platforms appear the same as the real platform and we distinct the difference from the architecture. fixes: rdar://problem/59161559 Reviewers: ributzka, steven_wu Reviewed By: ributzka Subscribers: hiraditya, dexonsmith, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D74416 Added: Modified: llvm/lib/TextAPI/MachO/TextStubCommon.cpp llvm/unittests/TextAPI/TextStubV3Tests.cpp Removed: diff --git a/llvm/lib/TextAPI/MachO/TextStubCommon.cpp b/llvm/lib/TextAPI/MachO/TextStubCommon.cpp index e4e58cd66f3f..21be654e130c 100644 --- a/llvm/lib/TextAPI/MachO/TextStubCommon.cpp +++ b/llvm/lib/TextAPI/MachO/TextStubCommon.cpp @@ -62,12 +62,18 @@ void ScalarTraits::output(const PlatformSet &Values, void *IO, case PlatformKind::macOS: OS << "macosx"; break; + case PlatformKind::iOSSimulator: +LLVM_FALLTHROUGH; case PlatformKind::iOS: OS << "ios"; break; + case PlatformKind::watchOSSimulator: +LLVM_FALLTHROUGH; case PlatformKind::watchOS: OS << "watchos"; break; + case PlatformKind::tvOSSimulator: +LLVM_FALLTHROUGH; case PlatformKind::tvOS: OS << "tvos"; break; diff --git a/llvm/unittests/TextAPI/TextStubV3Tests.cpp b/llvm/unittests/TextAPI/TextStubV3Tests.cpp index 0180989ff331..a9e54807cc85 100644 --- a/llvm/unittests/TextAPI/TextStubV3Tests.cpp +++ b/llvm/unittests/TextAPI/TextStubV3Tests.cpp @@ -364,6 +364,78 @@ TEST(TBDv3, Platform_zippered) { stripWhitespace(Buffer.c_str())); } +TEST(TBDv3, Platform_iOSSim) { + static const char tbd_v3_platform_iossim[] = "--- !tapi-tbd-v3\n" + "archs: [ x86_64 ]\n" + "platform: ios\n" + "install-name: Test.dylib\n" + "...\n"; + + auto Result = + TextAPIReader::get(MemoryBufferRef(tbd_v3_platform_iossim, "Test.tbd")); + EXPECT_TRUE(!!Result); + auto Platform = PlatformKind::iOSSimulator; + auto File = std::move(Result.get()); + EXPECT_EQ(FileType::TBD_V3, File->getFileType()); + EXPECT_EQ(File->getPlatforms().size(), 1U); + EXPECT_EQ(Platform, *File->getPlatforms().begin()); + + SmallString<4096> Buffer; + raw_svector_ostream OS(Buffer); + auto WriteResult = TextAPIWriter::writeToStream(OS, *File); + EXPECT_TRUE(!WriteResult); + EXPECT_EQ(stripWhitespace(tbd_v3_platform_iossim), +stripWhitespace(Buffer.c_str())); +} + +TEST(TBDv3, Platform_watchOSSim) { + static const char tbd_v3_platform_watchossim[] = "--- !tapi-tbd-v3\n" + "archs: [ x86_64 ]\n" + "platform: watchos\n" + "install-name: Test.dylib\n" + "...\n"; + + auto Result = TextAPIReader::get( + MemoryBufferRef(tbd_v3_platform_watchossim, "Test.tbd")); + EXPECT_TRUE(!!Result); + auto Platform = PlatformKind::watchOSSimulator; + auto File = std::move(Result.get()); + EXPECT_EQ(FileType::TBD_V3, File->getFileType()); + EXPECT_EQ(File->getPlatforms().size(), 1U); + EXPECT_EQ(Platform, *File->getPlatforms().begin()); + + SmallString<4096> Buffer; + raw_svector_ostream OS(Buffer); + auto WriteResult = TextAPIWriter::writeToStream(OS, *File); + EXPECT_TRUE(!WriteResult); + EXPECT_EQ(stripWhitespace(tbd_v3_platform_watchossim), +stripWhitespace(Buffer.c_str())); +} + +TEST(TBDv3, Platform_tvOSSim) { + static const char tbd_v3_platform_tvossim[] = "--- !tapi-tbd-v3\n" +"archs: [ x86_64 ]\n" +"platform: tvos\n" +"install-name: Test.dylib\n" +"...\n"; + + auto Result = + TextAPIReader::get(MemoryBufferRef(tbd_v3_platform_tvossim, "Test.tbd")); + EXPECT_TRUE(!!Result); + auto File = std::move(Result.get()); + auto Platform = PlatformKind::tvOSSimulator; + EXPECT_EQ(FileType::TBD_V3, File->getFileType()); + EXPECT_EQ(File->getPlatforms().size(), 1U); + EXPECT_EQ(Platform, *File->getPlatforms().begin()); + + SmallString<4096> Buffer; + raw_svector_ostream OS(Buffer); + auto WriteResult = TextAPIWriter::writeToStream(OS, *File); + EXPECT_TRUE(!WriteResult); + EXPECT_EQ(stripWhitespace(tbd_v3_platform_