@@ -161,6 +161,10 @@ static llvm::SmallString<128> getParseErrorMsg(TBDKey Key) {
161
161
return {" invalid " , Keys[Key], " section" };
162
162
}
163
163
164
+ static llvm::SmallString<128 > getSerializeErrorMsg (TBDKey Key) {
165
+ return {" missing " , Keys[Key], " information" };
166
+ }
167
+
164
168
class JSONStubError : public llvm ::ErrorInfo<llvm::json::ParseError> {
165
169
public:
166
170
JSONStubError (Twine ErrMsg) : Message(ErrMsg.str()) {}
@@ -716,3 +720,294 @@ MachO::getInterfaceFileFromJSON(StringRef JSON) {
716
720
}
717
721
return std::move (IF);
718
722
}
723
+
724
+ namespace {
725
+
726
+ template <typename ContainerT = Array>
727
+ bool insertNonEmptyValues (Object &Obj, TBDKey Key, ContainerT &&Contents) {
728
+ if (Contents.empty ())
729
+ return false ;
730
+ Obj[Keys[Key]] = std::move (Contents);
731
+ return true ;
732
+ }
733
+
734
+ std::string getFormattedStr (const MachO::Target &Targ) {
735
+ std::string PlatformStr = Targ.Platform == PLATFORM_MACCATALYST
736
+ ? " maccatalyst"
737
+ : getOSAndEnvironmentName (Targ.Platform );
738
+ return (getArchitectureName (Targ.Arch ) + " -" + PlatformStr).str ();
739
+ }
740
+
741
+ template <typename AggregateT>
742
+ std::vector<std::string> serializeTargets (const AggregateT Targets,
743
+ const TargetList &ActiveTargets) {
744
+ std::vector<std::string> TargetsStr;
745
+ if (Targets.size () == ActiveTargets.size ())
746
+ return TargetsStr;
747
+
748
+ llvm::for_each (Targets, [&TargetsStr](const MachO::Target &Target) {
749
+ TargetsStr.emplace_back (getFormattedStr (Target));
750
+ });
751
+ return TargetsStr;
752
+ }
753
+
754
+ Array serializeTargetInfo (const TargetList &ActiveTargets) {
755
+ Array Targets;
756
+ for (const auto Targ : ActiveTargets) {
757
+ Object TargetInfo;
758
+ TargetInfo[Keys[TBDKey::Deployment]] = Targ.MinDeployment .getAsString ();
759
+ TargetInfo[Keys[TBDKey::Target]] = getFormattedStr (Targ);
760
+ Targets.emplace_back (std::move (TargetInfo));
761
+ }
762
+ return Targets;
763
+ }
764
+
765
+ template <typename ValueT, typename EntryT = ValueT>
766
+ Array serializeScalar (TBDKey Key, ValueT Value, ValueT Default = ValueT()) {
767
+ if (Value == Default)
768
+ return {};
769
+ Array Container;
770
+ Object ScalarObj ({Object::KV ({Keys[Key], EntryT (Value)})});
771
+
772
+ Container.emplace_back (std::move (ScalarObj));
773
+ return Container;
774
+ }
775
+
776
+ using TargetsToValuesMap =
777
+ std::map<std::vector<std::string>, std::vector<std::string>>;
778
+
779
+ template <typename AggregateT = TargetsToValuesMap>
780
+ Array serializeAttrToTargets (AggregateT &Entries, TBDKey Key) {
781
+ Array Container;
782
+ for (const auto &[Targets, Values] : Entries) {
783
+ Object Obj;
784
+ insertNonEmptyValues (Obj, TBDKey::Targets, std::move (Targets));
785
+ Obj[Keys[Key]] = Values;
786
+ Container.emplace_back (std::move (Obj));
787
+ }
788
+ return Container;
789
+ }
790
+
791
+ template <typename ValueT = std::string,
792
+ typename AggregateT = std::vector<std::pair<MachO::Target, ValueT>>>
793
+ Array serializeField (TBDKey Key, const AggregateT &Values,
794
+ const TargetList &ActiveTargets, bool IsArray = true ) {
795
+ std::map<ValueT, std::set<MachO::Target>> Entries;
796
+ for (const auto &[Target, Val] : Values)
797
+ Entries[Val].insert (Target);
798
+
799
+ if (!IsArray) {
800
+ std::map<std::vector<std::string>, std::string> FinalEntries;
801
+ for (const auto &[Val, Targets] : Entries)
802
+ FinalEntries[serializeTargets (Targets, ActiveTargets)] = Val;
803
+ return serializeAttrToTargets (FinalEntries, Key);
804
+ }
805
+
806
+ TargetsToValuesMap FinalEntries;
807
+ for (const auto &[Val, Targets] : Entries)
808
+ FinalEntries[serializeTargets (Targets, ActiveTargets)].emplace_back (Val);
809
+ return serializeAttrToTargets (FinalEntries, Key);
810
+ }
811
+
812
+ Array serializeField (TBDKey Key, const std::vector<InterfaceFileRef> &Values,
813
+ const TargetList &ActiveTargets) {
814
+ TargetsToValuesMap FinalEntries;
815
+ for (const auto &Ref : Values) {
816
+ TargetList Targets{Ref.targets ().begin (), Ref.targets ().end ()};
817
+ FinalEntries[serializeTargets (Targets, ActiveTargets)].emplace_back (
818
+ Ref.getInstallName ());
819
+ }
820
+ return serializeAttrToTargets (FinalEntries, Key);
821
+ }
822
+
823
+ struct SymbolFields {
824
+ struct SymbolTypes {
825
+ std::vector<StringRef> Weaks;
826
+ std::vector<StringRef> Globals;
827
+ std::vector<StringRef> TLV;
828
+ std::vector<StringRef> ObjCClasses;
829
+ std::vector<StringRef> IVars;
830
+ std::vector<StringRef> EHTypes;
831
+
832
+ bool empty () const {
833
+ return Weaks.empty () && Globals.empty () && TLV.empty () &&
834
+ ObjCClasses.empty () && IVars.empty () && EHTypes.empty ();
835
+ }
836
+ };
837
+ SymbolTypes Data;
838
+ SymbolTypes Text;
839
+ };
840
+
841
+ Array serializeSymbols (InterfaceFile::const_filtered_symbol_range Symbols,
842
+ const TargetList &ActiveTargets) {
843
+ auto AssignForSymbolType = [](SymbolFields::SymbolTypes &Assignment,
844
+ const Symbol *Sym) {
845
+ switch (Sym->getKind ()) {
846
+ case SymbolKind::ObjectiveCClass:
847
+ Assignment.ObjCClasses .emplace_back (Sym->getName ());
848
+ return ;
849
+ case SymbolKind::ObjectiveCClassEHType:
850
+ Assignment.EHTypes .emplace_back (Sym->getName ());
851
+ return ;
852
+ case SymbolKind::ObjectiveCInstanceVariable:
853
+ Assignment.IVars .emplace_back (Sym->getName ());
854
+ return ;
855
+ case SymbolKind::GlobalSymbol: {
856
+ if (Sym->isWeakReferenced () || Sym->isWeakDefined ())
857
+ Assignment.Weaks .emplace_back (Sym->getName ());
858
+ else if (Sym->isThreadLocalValue ())
859
+ Assignment.TLV .emplace_back (Sym->getName ());
860
+ else
861
+ Assignment.Globals .emplace_back (Sym->getName ());
862
+ return ;
863
+ }
864
+ }
865
+ };
866
+
867
+ std::map<std::vector<std::string>, SymbolFields> Entries;
868
+ for (const auto *Sym : Symbols) {
869
+ std::set<MachO::Target> Targets{Sym->targets ().begin (),
870
+ Sym->targets ().end ()};
871
+ auto JSONTargets = serializeTargets (Targets, ActiveTargets);
872
+ if (Sym->isData ())
873
+ AssignForSymbolType (Entries[std::move (JSONTargets)].Data , Sym);
874
+ else if (Sym->isText ())
875
+ AssignForSymbolType (Entries[std::move (JSONTargets)].Text , Sym);
876
+ else
877
+ llvm_unreachable (" unexpected symbol type" );
878
+ }
879
+
880
+ auto InsertSymbolsToJSON = [](Object &SymSection, TBDKey SegmentKey,
881
+ SymbolFields::SymbolTypes &SymField) {
882
+ if (SymField.empty ())
883
+ return ;
884
+ Object Segment;
885
+ insertNonEmptyValues (Segment, TBDKey::Globals, std::move (SymField.Globals ));
886
+ insertNonEmptyValues (Segment, TBDKey::ThreadLocal, std::move (SymField.TLV ));
887
+ insertNonEmptyValues (Segment, TBDKey::Weak, std::move (SymField.Weaks ));
888
+ insertNonEmptyValues (Segment, TBDKey::ObjCClass,
889
+ std::move (SymField.ObjCClasses ));
890
+ insertNonEmptyValues (Segment, TBDKey::ObjCEHType,
891
+ std::move (SymField.EHTypes ));
892
+ insertNonEmptyValues (Segment, TBDKey::ObjCIvar, std::move (SymField.IVars ));
893
+ insertNonEmptyValues (SymSection, SegmentKey, std::move (Segment));
894
+ };
895
+
896
+ Array SymbolSection;
897
+ for (auto &[Targets, Fields] : Entries) {
898
+ Object AllSyms;
899
+ insertNonEmptyValues (AllSyms, TBDKey::Targets, std::move (Targets));
900
+ InsertSymbolsToJSON (AllSyms, TBDKey::Data, Fields.Data );
901
+ InsertSymbolsToJSON (AllSyms, TBDKey::Text, Fields.Text );
902
+ SymbolSection.emplace_back (std::move (AllSyms));
903
+ }
904
+
905
+ return SymbolSection;
906
+ }
907
+
908
+ Array serializeFlags (const InterfaceFile *File) {
909
+ // TODO: Give all Targets the same flags for now.
910
+ Array Flags;
911
+ if (!File->isTwoLevelNamespace ())
912
+ Flags.emplace_back (" flat_namespace" );
913
+ if (!File->isApplicationExtensionSafe ())
914
+ Flags.emplace_back (" not_app_extension_safe" );
915
+ return serializeScalar (TBDKey::Attributes, std::move (Flags));
916
+ }
917
+
918
+ Expected<Object> serializeIF (const InterfaceFile *File) {
919
+ Object Library;
920
+
921
+ // Handle required keys.
922
+ TargetList ActiveTargets{File->targets ().begin (), File->targets ().end ()};
923
+ if (!insertNonEmptyValues (Library, TBDKey::TargetInfo,
924
+ serializeTargetInfo (ActiveTargets)))
925
+ return make_error<JSONStubError>(getSerializeErrorMsg (TBDKey::TargetInfo));
926
+
927
+ Array Name = serializeScalar<StringRef>(TBDKey::Name, File->getInstallName ());
928
+ if (!insertNonEmptyValues (Library, TBDKey::InstallName, std::move (Name)))
929
+ return make_error<JSONStubError>(getSerializeErrorMsg (TBDKey::InstallName));
930
+
931
+ // Handle optional keys.
932
+ Array Flags = serializeFlags (File);
933
+ insertNonEmptyValues (Library, TBDKey::Flags, std::move (Flags));
934
+
935
+ Array CurrentV = serializeScalar<PackedVersion, std::string>(
936
+ TBDKey::Version, File->getCurrentVersion (), PackedVersion (1 , 0 , 0 ));
937
+ insertNonEmptyValues (Library, TBDKey::CurrentVersion, std::move (CurrentV));
938
+
939
+ Array CompatV = serializeScalar<PackedVersion, std::string>(
940
+ TBDKey::Version, File->getCompatibilityVersion (), PackedVersion (1 , 0 , 0 ));
941
+ insertNonEmptyValues (Library, TBDKey::CompatibilityVersion,
942
+ std::move (CompatV));
943
+
944
+ Array SwiftABI = serializeScalar<uint8_t , int64_t >(
945
+ TBDKey::ABI, File->getSwiftABIVersion (), 0u );
946
+ insertNonEmptyValues (Library, TBDKey::SwiftABI, std::move (SwiftABI));
947
+
948
+ Array RPaths = serializeField (TBDKey::Paths, File->rpaths (), ActiveTargets);
949
+ insertNonEmptyValues (Library, TBDKey::RPath, std::move (RPaths));
950
+
951
+ Array Umbrellas = serializeField (TBDKey::Umbrella, File->umbrellas (),
952
+ ActiveTargets, /* IsArray=*/ false );
953
+ insertNonEmptyValues (Library, TBDKey::ParentUmbrella, std::move (Umbrellas));
954
+
955
+ Array Clients =
956
+ serializeField (TBDKey::Clients, File->allowableClients (), ActiveTargets);
957
+ insertNonEmptyValues (Library, TBDKey::AllowableClients, std::move (Clients));
958
+
959
+ Array ReexportLibs =
960
+ serializeField (TBDKey::Names, File->reexportedLibraries (), ActiveTargets);
961
+ insertNonEmptyValues (Library, TBDKey::ReexportLibs, std::move (ReexportLibs));
962
+
963
+ // Handle symbols.
964
+ Array Exports = serializeSymbols (File->exports (), ActiveTargets);
965
+ insertNonEmptyValues (Library, TBDKey::Exports, std::move (Exports));
966
+
967
+ Array Reexports = serializeSymbols (File->reexports (), ActiveTargets);
968
+ insertNonEmptyValues (Library, TBDKey::Reexports, std::move (Reexports));
969
+
970
+ if (!File->isTwoLevelNamespace ()) {
971
+ Array Undefineds = serializeSymbols (File->undefineds (), ActiveTargets);
972
+ insertNonEmptyValues (Library, TBDKey::Undefineds, std::move (Undefineds));
973
+ }
974
+
975
+ return std::move (Library);
976
+ }
977
+
978
+ Expected<Object> getJSON (const InterfaceFile *File) {
979
+ assert (File->getFileType () == FileType::TBD_V5 &&
980
+ " unexpected json file format version" );
981
+ Object Root;
982
+
983
+ auto MainLibOrErr = serializeIF (File);
984
+ if (!MainLibOrErr)
985
+ return MainLibOrErr;
986
+ Root[Keys[TBDKey::MainLibrary]] = std::move (*MainLibOrErr);
987
+ Array Documents;
988
+ for (const auto &Doc : File->documents ()) {
989
+ auto LibOrErr = serializeIF (Doc.get ());
990
+ if (!LibOrErr)
991
+ return LibOrErr;
992
+ Documents.emplace_back (std::move (*LibOrErr));
993
+ }
994
+
995
+ Root[Keys[TBDKey::TBDVersion]] = 5 ;
996
+ insertNonEmptyValues (Root, TBDKey::Documents, std::move (Documents));
997
+ return std::move (Root);
998
+ }
999
+
1000
+ } // namespace
1001
+
1002
+ Error MachO::serializeInterfaceFileToJSON (raw_ostream &OS,
1003
+ const InterfaceFile &File,
1004
+ bool Compact) {
1005
+ auto TextFile = getJSON (&File);
1006
+ if (!TextFile)
1007
+ return TextFile.takeError ();
1008
+ if (Compact)
1009
+ OS << formatv (" {0}" , Value (std::move (*TextFile))) << " \n " ;
1010
+ else
1011
+ OS << formatv (" {0:2}" , Value (std::move (*TextFile))) << " \n " ;
1012
+ return Error::success ();
1013
+ }
0 commit comments