[clang][ssaf] Add `StaticLibrary` data structure (#205946)
This change introduces the `StaticLibrary` data structure, the SSAF analogue of `ar`, `libtool -static`, or `lib.exe`: a single-architecture bundle of `TUSummary` objects. `StaticLibrary` only stores `TUSummaryEncoding` because it will be used by `clang-ssaf-linker` that does not decode the summary data. We don't plan to create a decoded variant because there will be no consumer. Support for constructing and linking static libraries will be introduced in future PRs.
rdar://180665891
diff --git a/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/StaticLibrary.h b/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/StaticLibrary.h
new file mode 100644
index 0000000..ae8cfa4
--- /dev/null
+++ b/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/StaticLibrary.h
@@ -0,0 +1,75 @@
+//===- StaticLibrary.h ------------------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the StaticLibrary class, which represents a static
+// library of translation unit summary encodings (the SSAF analogue of an
+// ar / libtool -static / lib.exe output).
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SCALABLESTATICANALYSIS_CORE_ENTITYLINKER_STATICLIBRARY_H
+#define LLVM_CLANG_SCALABLESTATICANALYSIS_CORE_ENTITYLINKER_STATICLIBRARY_H
+
+#include "clang/ScalableStaticAnalysis/Core/EntityLinker/TUSummaryEncoding.h"
+#include "clang/ScalableStaticAnalysis/Core/Model/BuildNamespace.h"
+#include "llvm/TargetParser/Triple.h"
+#include <memory>
+#include <set>
+
+namespace clang::ssaf {
+
+/// Represents a static library of translation unit summary encodings.
+///
+/// A StaticLibrary bundles member translation units without performing
+/// entity resolution, mirroring the role of ar / libtool -static / lib.exe
+/// in native build pipelines. It is consumed by the EntityLinker for
+/// selective inclusion when passed as a command line argument.
+///
+/// Static libraries are single-architecture: every member's target triple
+/// must equal the library's. Multi-architecture static libraries are
+/// expressed as a fat wrapper around per-architecture StaticLibrary
+/// instances rather than as a single mixed-architecture library.
+///
+/// Members are stored as encoded TUSummaryEncoding objects: the archiver
+/// tool never decodes per-entity payloads, and the linker consumes them
+/// as-is during its selective inclusion pass.
+class StaticLibrary {
+ friend class SerializationFormat;
+ friend class TestFixture;
+
+ /// Orders members by their TUNamespace. As a nested struct of
+ /// StaticLibrary, it inherits StaticLibrary's friend access to
+ /// TUSummaryEncoding's private fields.
+ struct MemberByNamespace {
+ bool operator()(const std::unique_ptr<TUSummaryEncoding> &A,
+ const std::unique_ptr<TUSummaryEncoding> &B) const {
+ return A->TUNamespace < B->TUNamespace;
+ }
+ };
+
+ // Target triple of the static library. All member TUs must share this
+ // triple.
+ llvm::Triple TargetTriple;
+
+ // The namespace identifying this static library (kind=StaticLibrary).
+ BuildNamespace Namespace;
+
+ // Member translation units, ordered by their TUNamespace. Membership is
+ // by namespace identity: inserting a TU whose TUNamespace already exists
+ // in the set is rejected during deserialization.
+ std::set<std::unique_ptr<TUSummaryEncoding>, MemberByNamespace> Members;
+
+public:
+ StaticLibrary(llvm::Triple TargetTriple, BuildNamespace Namespace)
+ : TargetTriple(std::move(TargetTriple)), Namespace(std::move(Namespace)) {
+ }
+};
+
+} // namespace clang::ssaf
+
+#endif // LLVM_CLANG_SCALABLESTATICANALYSIS_CORE_ENTITYLINKER_STATICLIBRARY_H
diff --git a/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/TUSummaryEncoding.h b/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/TUSummaryEncoding.h
index 2c672a5..2ece195 100644
--- a/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/TUSummaryEncoding.h
+++ b/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/TUSummaryEncoding.h
@@ -35,6 +35,7 @@
class TUSummaryEncoding {
friend class EntityLinker;
friend class SerializationFormat;
+ friend class StaticLibrary;
friend class TestFixture;
// Target triple of the translation unit.
diff --git a/clang/include/clang/ScalableStaticAnalysis/Core/Model/BuildNamespace.h b/clang/include/clang/ScalableStaticAnalysis/Core/Model/BuildNamespace.h
index 6da5a9e..1549b35 100644
--- a/clang/include/clang/ScalableStaticAnalysis/Core/Model/BuildNamespace.h
+++ b/clang/include/clang/ScalableStaticAnalysis/Core/Model/BuildNamespace.h
@@ -27,7 +27,11 @@
namespace clang::ssaf {
-enum class BuildNamespaceKind : unsigned short { CompilationUnit, LinkUnit };
+enum class BuildNamespaceKind : unsigned short {
+ CompilationUnit,
+ LinkUnit,
+ StaticLibrary
+};
/// Represents a single namespace in the build process.
///
diff --git a/clang/include/clang/ScalableStaticAnalysis/Core/Model/PrivateFieldNames.def b/clang/include/clang/ScalableStaticAnalysis/Core/Model/PrivateFieldNames.def
index 4493102..b1c3782 100644
--- a/clang/include/clang/ScalableStaticAnalysis/Core/Model/PrivateFieldNames.def
+++ b/clang/include/clang/ScalableStaticAnalysis/Core/Model/PrivateFieldNames.def
@@ -36,6 +36,9 @@
FIELD(LUSummaryEncoding, LinkageTable)
FIELD(LUSummaryEncoding, LUNamespace)
FIELD(NestedBuildNamespace, Namespaces)
+FIELD(StaticLibrary, Members)
+FIELD(StaticLibrary, Namespace)
+FIELD(StaticLibrary, TargetTriple)
FIELD(TUSummary, TargetTriple)
FIELD(TUSummary, Data)
FIELD(TUSummary, IdTable)
diff --git a/clang/include/clang/ScalableStaticAnalysis/Core/Serialization/JSONFormat.h b/clang/include/clang/ScalableStaticAnalysis/Core/Serialization/JSONFormat.h
index 9d9b1ff..d4b6cfc 100644
--- a/clang/include/clang/ScalableStaticAnalysis/Core/Serialization/JSONFormat.h
+++ b/clang/include/clang/ScalableStaticAnalysis/Core/Serialization/JSONFormat.h
@@ -68,6 +68,12 @@
llvm::Error writeLUSummaryEncoding(const LUSummaryEncoding &SummaryEncoding,
llvm::StringRef Path) override;
+ llvm::Expected<StaticLibrary>
+ readStaticLibrary(llvm::StringRef Path) override;
+
+ llvm::Error writeStaticLibrary(const StaticLibrary &S,
+ llvm::StringRef Path) override;
+
llvm::Expected<WPASuite> readWPASuite(llvm::StringRef Path) override;
llvm::Error writeWPASuite(const WPASuite &Suite,
@@ -122,6 +128,15 @@
llvm::Expected<LUSummaryEncoding>
readLUSummaryEncodingFromObject(const Object &Root);
+ /// Parses a StaticLibrary from an already-validated root JSON object.
+ /// See \c readTUSummaryFromObject for caller responsibilities.
+ llvm::Expected<StaticLibrary> readStaticLibraryFromObject(const Object &Root);
+
+ /// Serializes a TUSummaryEncoding to a JSON object including its
+ /// self-describing \c type field. Used both by \c writeTUSummaryEncoding
+ /// and by the StaticLibrary writer to emit member entries.
+ Object tuSummaryEncodingToJSON(const TUSummaryEncoding &SE) const;
+
/// Parses a WPASuite from an already-validated root JSON object. See
/// \c readTUSummaryFromObject for caller responsibilities.
llvm::Expected<WPASuite> readWPASuiteFromObject(const Object &Root);
diff --git a/clang/include/clang/ScalableStaticAnalysis/Core/Serialization/SerializationFormat.h b/clang/include/clang/ScalableStaticAnalysis/Core/Serialization/SerializationFormat.h
index ca3ee9c..29b662b 100644
--- a/clang/include/clang/ScalableStaticAnalysis/Core/Serialization/SerializationFormat.h
+++ b/clang/include/clang/ScalableStaticAnalysis/Core/Serialization/SerializationFormat.h
@@ -16,6 +16,7 @@
#include "clang/ScalableStaticAnalysis/Core/EntityLinker/LUSummary.h"
#include "clang/ScalableStaticAnalysis/Core/EntityLinker/LUSummaryEncoding.h"
+#include "clang/ScalableStaticAnalysis/Core/EntityLinker/StaticLibrary.h"
#include "clang/ScalableStaticAnalysis/Core/EntityLinker/TUSummaryEncoding.h"
#include "clang/ScalableStaticAnalysis/Core/Model/BuildNamespace.h"
#include "clang/ScalableStaticAnalysis/Core/Model/SummaryName.h"
@@ -40,7 +41,12 @@
/// Lazily-deserialized counterpart of \c Artifact: the same on-disk
/// artifacts but with their per-entity summary payloads left as opaque
/// format-specific encodings rather than fully resolved analysis results.
-using ArtifactEncoding = std::variant<TUSummaryEncoding, LUSummaryEncoding>;
+///
+/// \c StaticLibrary appears only in this variant: the archiver tool and
+/// the linker pass member payloads through without decoding them, so a
+/// fully decoded static-library shape would have no consumer.
+using ArtifactEncoding =
+ std::variant<TUSummaryEncoding, LUSummaryEncoding, StaticLibrary>;
/// Abstract base class for serialization formats.
class SerializationFormat {
@@ -94,6 +100,12 @@
writeLUSummaryEncoding(const LUSummaryEncoding &SummaryEncoding,
llvm::StringRef Path) = 0;
+ virtual llvm::Expected<StaticLibrary>
+ readStaticLibrary(llvm::StringRef Path) = 0;
+
+ virtual llvm::Error writeStaticLibrary(const StaticLibrary &S,
+ llvm::StringRef Path) = 0;
+
virtual llvm::Expected<WPASuite> readWPASuite(llvm::StringRef Path) = 0;
virtual llvm::Error writeWPASuite(const WPASuite &Suite,
diff --git a/clang/lib/ScalableStaticAnalysis/Core/CMakeLists.txt b/clang/lib/ScalableStaticAnalysis/Core/CMakeLists.txt
index b2cde5f..0a0ce19 100644
--- a/clang/lib/ScalableStaticAnalysis/Core/CMakeLists.txt
+++ b/clang/lib/ScalableStaticAnalysis/Core/CMakeLists.txt
@@ -17,6 +17,7 @@
Serialization/JSONFormat/JSONFormatImpl.cpp
Serialization/JSONFormat/LUSummary.cpp
Serialization/JSONFormat/LUSummaryEncoding.cpp
+ Serialization/JSONFormat/StaticLibrary.cpp
Serialization/JSONFormat/TUSummary.cpp
Serialization/JSONFormat/TUSummaryEncoding.cpp
Serialization/JSONFormat/WPASuite.cpp
diff --git a/clang/lib/ScalableStaticAnalysis/Core/ModelStringConversions.h b/clang/lib/ScalableStaticAnalysis/Core/ModelStringConversions.h
index ee1603e..8d3c932 100644
--- a/clang/lib/ScalableStaticAnalysis/Core/ModelStringConversions.h
+++ b/clang/lib/ScalableStaticAnalysis/Core/ModelStringConversions.h
@@ -36,6 +36,8 @@
return "CompilationUnit";
case BuildNamespaceKind::LinkUnit:
return "LinkUnit";
+ case BuildNamespaceKind::StaticLibrary:
+ return "StaticLibrary";
}
llvm_unreachable("Unhandled BuildNamespaceKind variant");
}
@@ -48,6 +50,8 @@
return BuildNamespaceKind::CompilationUnit;
if (Str == "LinkUnit")
return BuildNamespaceKind::LinkUnit;
+ if (Str == "StaticLibrary")
+ return BuildNamespaceKind::StaticLibrary;
return std::nullopt;
}
diff --git a/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/Artifact.cpp b/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/Artifact.cpp
index 424d736..e5fc46a 100644
--- a/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/Artifact.cpp
+++ b/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/Artifact.cpp
@@ -145,10 +145,21 @@
return ArtifactEncoding{std::move(*ExpectedLU)};
}
+ if (*ExpectedType == JSONTypeValueStaticLibrary) {
+ auto ExpectedStaticLibrary = readStaticLibraryFromObject(*RootObjectPtr);
+ if (!ExpectedStaticLibrary) {
+ return ErrorBuilder::wrap(ExpectedStaticLibrary.takeError())
+ .context(ErrorMessages::ReadingFromFile, "ArtifactEncoding", Path)
+ .build();
+ }
+ return ArtifactEncoding{std::move(*ExpectedStaticLibrary)};
+ }
+
return ErrorBuilder::create(std::errc::invalid_argument,
ErrorMessages::UnknownArtifactEncodingType,
*ExpectedType, JSONTypeKey,
- JSONTypeValueTUSummary, JSONTypeValueLUSummary)
+ JSONTypeValueTUSummary, JSONTypeValueLUSummary,
+ JSONTypeValueStaticLibrary)
.context(ErrorMessages::ReadingFromFile, "ArtifactEncoding", Path)
.build();
}
@@ -160,11 +171,13 @@
using T = std::decay_t<decltype(Enc)>;
if constexpr (std::is_same_v<T, TUSummaryEncoding>) {
return writeTUSummaryEncoding(Enc, Path);
+ } else if constexpr (std::is_same_v<T, LUSummaryEncoding>) {
+ return writeLUSummaryEncoding(Enc, Path);
} else {
static_assert(
- std::is_same_v<T, LUSummaryEncoding>,
+ std::is_same_v<T, StaticLibrary>,
"ArtifactEncoding visitor must cover all variant alternatives");
- return writeLUSummaryEncoding(Enc, Path);
+ return writeStaticLibrary(Enc, Path);
}
},
E);
diff --git a/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/JSONFormatImpl.h b/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/JSONFormatImpl.h
index 191be83..e83a8da 100644
--- a/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/JSONFormatImpl.h
+++ b/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/JSONFormatImpl.h
@@ -85,7 +85,7 @@
inline constexpr const char *UnknownArtifactType =
"unknown value '{0}' for field '{1}': expected '{2}', '{3}', or '{4}'";
inline constexpr const char *UnknownArtifactEncodingType =
- "unknown value '{0}' for field '{1}': expected '{2}', or '{3}'";
+ "unknown value '{0}' for field '{1}': expected '{2}', '{3}', or '{4}'";
inline constexpr const char *FailedToDeserializeEntitySummaryNoFormatInfo =
"failed to deserialize EntitySummary: no FormatInfo registered for '{0}'";
@@ -149,6 +149,9 @@
/// Value written to \c JSONTypeKey for serialized \c LUSummary files.
inline constexpr const char *JSONTypeValueLUSummary = "LUSummary";
+/// Value written to \c JSONTypeKey for serialized \c StaticLibrary files.
+inline constexpr const char *JSONTypeValueStaticLibrary = "StaticLibrary";
+
/// Value written to \c JSONTypeKey for serialized \c WPASuite files.
inline constexpr const char *JSONTypeValueWPASuite = "WPASuite";
diff --git a/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/StaticLibrary.cpp b/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/StaticLibrary.cpp
new file mode 100644
index 0000000..b34c63b
--- /dev/null
+++ b/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/StaticLibrary.cpp
@@ -0,0 +1,192 @@
+//===- StaticLibrary.cpp --------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "JSONFormatImpl.h"
+
+#include "clang/ScalableStaticAnalysis/Core/EntityLinker/StaticLibrary.h"
+#include "clang/ScalableStaticAnalysis/Core/EntityLinker/TUSummaryEncoding.h"
+#include "llvm/TargetParser/Triple.h"
+
+namespace clang::ssaf {
+
+//----------------------------------------------------------------------------
+// StaticLibrary
+//----------------------------------------------------------------------------
+
+llvm::Expected<StaticLibrary>
+JSONFormat::readStaticLibrary(llvm::StringRef Path) {
+ auto ExpectedJSON = readJSON(Path);
+ if (!ExpectedJSON) {
+ return ErrorBuilder::wrap(ExpectedJSON.takeError())
+ .context(ErrorMessages::ReadingFromFile, "StaticLibrary", Path)
+ .build();
+ }
+
+ Object *RootObjectPtr = ExpectedJSON->getAsObject();
+ if (!RootObjectPtr) {
+ return ErrorBuilder::create(std::errc::invalid_argument,
+ ErrorMessages::FailedToReadObject,
+ "StaticLibrary", "object")
+ .context(ErrorMessages::ReadingFromFile, "StaticLibrary", Path)
+ .build();
+ }
+
+ if (auto Err = checkSummaryType(*RootObjectPtr, JSONTypeValueStaticLibrary)) {
+ return ErrorBuilder::wrap(std::move(Err))
+ .context(ErrorMessages::ReadingFromFile, "StaticLibrary", Path)
+ .build();
+ }
+
+ auto ExpectedStaticLibrary = readStaticLibraryFromObject(*RootObjectPtr);
+ if (!ExpectedStaticLibrary) {
+ return ErrorBuilder::wrap(ExpectedStaticLibrary.takeError())
+ .context(ErrorMessages::ReadingFromFile, "StaticLibrary", Path)
+ .build();
+ }
+
+ return std::move(*ExpectedStaticLibrary);
+}
+
+llvm::Expected<StaticLibrary>
+JSONFormat::readStaticLibraryFromObject(const Object &RootObject) {
+ auto OptTargetTriple = RootObject.getString("target_triple");
+ if (!OptTargetTriple) {
+ return ErrorBuilder::create(std::errc::invalid_argument,
+ ErrorMessages::FailedToReadObjectAtField,
+ "TargetTriple", "target_triple", "string")
+ .build();
+ }
+
+ if (auto Err = validateNormalizedTargetTriple(*OptTargetTriple)) {
+ return ErrorBuilder::wrap(std::move(Err))
+ .context(ErrorMessages::ReadingFromField, "TargetTriple",
+ "target_triple")
+ .build();
+ }
+
+ llvm::Triple T(*OptTargetTriple);
+
+ const Object *NamespaceObject = RootObject.getObject("namespace");
+ if (!NamespaceObject) {
+ return ErrorBuilder::create(std::errc::invalid_argument,
+ ErrorMessages::FailedToReadObjectAtField,
+ "BuildNamespace", "namespace", "object")
+ .build();
+ }
+
+ auto ExpectedNamespace = buildNamespaceFromJSON(*NamespaceObject);
+ if (!ExpectedNamespace) {
+ return ErrorBuilder::wrap(ExpectedNamespace.takeError())
+ .context(ErrorMessages::ReadingFromField, "BuildNamespace", "namespace")
+ .build();
+ }
+
+ if (getKind(*ExpectedNamespace) != BuildNamespaceKind::StaticLibrary) {
+ return ErrorBuilder::create(
+ std::errc::invalid_argument,
+ ErrorMessages::MismatchedSummaryType,
+ buildNamespaceKindToJSON(BuildNamespaceKind::StaticLibrary),
+ "namespace.kind",
+ buildNamespaceKindToJSON(getKind(*ExpectedNamespace)))
+ .build();
+ }
+
+ StaticLibrary S(std::move(T), std::move(*ExpectedNamespace));
+
+ const Array *MembersArray = RootObject.getArray("members");
+ if (!MembersArray) {
+ return ErrorBuilder::create(std::errc::invalid_argument,
+ ErrorMessages::FailedToReadObjectAtField,
+ "StaticLibrary members", "members", "array")
+ .build();
+ }
+
+ auto &Members = getMembers(S);
+ const auto &StaticLibraryTriple = getTargetTriple(S);
+
+ for (const auto &[Index, MemberValue] : llvm::enumerate(*MembersArray)) {
+ const Object *MemberObject = MemberValue.getAsObject();
+ if (!MemberObject) {
+ return ErrorBuilder::create(std::errc::invalid_argument,
+ ErrorMessages::FailedToReadObjectAtIndex,
+ "StaticLibrary member", Index, "object")
+ .build();
+ }
+
+ if (auto Err = checkSummaryType(*MemberObject, JSONTypeValueTUSummary)) {
+ return ErrorBuilder::wrap(std::move(Err))
+ .context(ErrorMessages::ReadingFromIndex, "StaticLibrary member",
+ Index)
+ .build();
+ }
+
+ auto ExpectedMember = readTUSummaryEncodingFromObject(*MemberObject);
+ if (!ExpectedMember) {
+ return ErrorBuilder::wrap(ExpectedMember.takeError())
+ .context(ErrorMessages::ReadingFromIndex, "StaticLibrary member",
+ Index)
+ .build();
+ }
+
+ if (ExpectedMember->getTargetTriple() != StaticLibraryTriple) {
+ return ErrorBuilder::create(
+ std::errc::invalid_argument,
+ ErrorMessages::MismatchedSummaryType,
+ llvm::Triple::normalize(StaticLibraryTriple.str()),
+ "target_triple",
+ llvm::Triple::normalize(
+ ExpectedMember->getTargetTriple().str()))
+ .context(ErrorMessages::ReadingFromIndex, "StaticLibrary member",
+ Index)
+ .build();
+ }
+
+ auto MemberNamespace = getTUNamespace(*ExpectedMember);
+ auto Owned =
+ std::make_unique<TUSummaryEncoding>(std::move(*ExpectedMember));
+ auto [It, Inserted] = Members.insert(std::move(Owned));
+ if (!Inserted) {
+ return ErrorBuilder::create(std::errc::invalid_argument,
+ ErrorMessages::FailedInsertionOnDuplication,
+ "StaticLibrary member", Index,
+ MemberNamespace)
+ .build();
+ }
+ }
+
+ return std::move(S);
+}
+
+llvm::Error JSONFormat::writeStaticLibrary(const StaticLibrary &S,
+ llvm::StringRef Path) {
+ Object RootObject;
+
+ RootObject[JSONTypeKey] = JSONTypeValueStaticLibrary;
+
+ RootObject["target_triple"] =
+ llvm::Triple::normalize(getTargetTriple(S).str());
+
+ RootObject["namespace"] = buildNamespaceToJSON(getNamespace(S));
+
+ Array MembersArray;
+ MembersArray.reserve(getMembers(S).size());
+ for (const auto &Member : getMembers(S)) {
+ MembersArray.push_back(tuSummaryEncodingToJSON(*Member));
+ }
+ RootObject["members"] = std::move(MembersArray);
+
+ if (auto Error = writeJSON(std::move(RootObject), Path)) {
+ return ErrorBuilder::wrap(std::move(Error))
+ .context(ErrorMessages::WritingToFile, "StaticLibrary", Path)
+ .build();
+ }
+
+ return llvm::Error::success();
+}
+
+} // namespace clang::ssaf
diff --git a/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/TUSummaryEncoding.cpp b/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/TUSummaryEncoding.cpp
index 5a5ab98..3ee4f05 100644
--- a/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/TUSummaryEncoding.cpp
+++ b/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/TUSummaryEncoding.cpp
@@ -164,6 +164,17 @@
llvm::Error
JSONFormat::writeTUSummaryEncoding(const TUSummaryEncoding &SummaryEncoding,
llvm::StringRef Path) {
+ if (auto Error = writeJSON(tuSummaryEncodingToJSON(SummaryEncoding), Path)) {
+ return ErrorBuilder::wrap(std::move(Error))
+ .context(ErrorMessages::WritingToFile, "TUSummary", Path)
+ .build();
+ }
+
+ return llvm::Error::success();
+}
+
+Object JSONFormat::tuSummaryEncodingToJSON(
+ const TUSummaryEncoding &SummaryEncoding) const {
Object RootObject;
RootObject[JSONTypeKey] = JSONTypeValueTUSummary;
@@ -181,13 +192,7 @@
RootObject["data"] = encodingSummaryDataMapToJSON(getData(SummaryEncoding));
- if (auto Error = writeJSON(std::move(RootObject), Path)) {
- return ErrorBuilder::wrap(std::move(Error))
- .context(ErrorMessages::WritingToFile, "TUSummary", Path)
- .build();
- }
-
- return llvm::Error::success();
+ return RootObject;
}
} // namespace clang::ssaf
diff --git a/clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/rt-static-library-empty.json b/clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/rt-static-library-empty.json
new file mode 100644
index 0000000..3059d00
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/rt-static-library-empty.json
@@ -0,0 +1,9 @@
+{
+ "members": [],
+ "namespace": {
+ "kind": "StaticLibrary",
+ "name": "libempty"
+ },
+ "target_triple": "arm64-apple-macosx",
+ "type": "StaticLibrary"
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/Artifact/round-trip.test b/clang/test/Analysis/Scalable/ssaf-format/Artifact/round-trip.test
index 4ddb233..d6d6782 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/Artifact/round-trip.test
+++ b/clang/test/Analysis/Scalable/ssaf-format/Artifact/round-trip.test
@@ -38,3 +38,12 @@
// RUN: diff %S/Inputs/rt-lu-empty.json %t/rt-lu-empty-enc.json
// RUN: clang-ssaf-format --type auto --encoding %S/Inputs/rt-lu-empty.json -o %t/rt-lu-empty-enc-explicit.json
// RUN: diff %S/Inputs/rt-lu-empty.json %t/rt-lu-empty-enc-explicit.json
+
+// StaticLibrary appears only in the ArtifactEncoding variant (the archiver
+// tool and the linker pass member payloads through encoded), so it
+// round-trips only via --encoding here.
+
+// RUN: clang-ssaf-format --encoding %S/Inputs/rt-static-library-empty.json -o %t/rt-static-library-empty-enc.json
+// RUN: diff %S/Inputs/rt-static-library-empty.json %t/rt-static-library-empty-enc.json
+// RUN: clang-ssaf-format --type auto --encoding %S/Inputs/rt-static-library-empty.json -o %t/rt-static-library-empty-enc-explicit.json
+// RUN: diff %S/Inputs/rt-static-library-empty.json %t/rt-static-library-empty-enc-explicit.json
diff --git a/clang/test/Analysis/Scalable/ssaf-format/Artifact/top-level.test b/clang/test/Analysis/Scalable/ssaf-format/Artifact/top-level.test
index 904b1df..7838f3a 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/Artifact/top-level.test
+++ b/clang/test/Analysis/Scalable/ssaf-format/Artifact/top-level.test
@@ -40,4 +40,4 @@
// RUN: not clang-ssaf-format --type auto --encoding %S/Inputs/unknown-type.json 2>&1 \
// RUN: | FileCheck %s --match-full-lines --check-prefix=ENCODING-UNKNOWN-TYPE
// ENCODING-UNKNOWN-TYPE: clang-ssaf-format: error: reading ArtifactEncoding from file '{{.*}}unknown-type.json'
-// ENCODING-UNKNOWN-TYPE-NEXT: unknown value 'Mystery' for field 'type': expected 'TUSummary', or 'LUSummary'
+// ENCODING-UNKNOWN-TYPE-NEXT: unknown value 'Mystery' for field 'type': expected 'TUSummary', 'LUSummary', or 'StaticLibrary'
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/duplicate-member.json b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/duplicate-member.json
new file mode 100644
index 0000000..e3ea75b
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/duplicate-member.json
@@ -0,0 +1,32 @@
+{
+ "type": "StaticLibrary",
+ "target_triple": "arm64-apple-macosx",
+ "namespace": {
+ "kind": "StaticLibrary",
+ "name": "libfoo"
+ },
+ "members": [
+ {
+ "type": "TUSummary",
+ "target_triple": "arm64-apple-macosx",
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "a.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [],
+ "data": []
+ },
+ {
+ "type": "TUSummary",
+ "target_triple": "arm64-apple-macosx",
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "a.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [],
+ "data": []
+ }
+ ]
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/invalid-syntax.json b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/invalid-syntax.json
new file mode 100644
index 0000000..b0e13f6
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/invalid-syntax.json
@@ -0,0 +1 @@
+{ invalid json }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/member-inner-error.json b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/member-inner-error.json
new file mode 100644
index 0000000..5134814
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/member-inner-error.json
@@ -0,0 +1,17 @@
+{
+ "members": [
+ {
+ "type": "TUSummary",
+ "target_triple": "arm64-apple-macosx",
+ "id_table": [],
+ "linkage_table": [],
+ "data": []
+ }
+ ],
+ "namespace": {
+ "kind": "StaticLibrary",
+ "name": "libfoo"
+ },
+ "target_triple": "arm64-apple-macosx",
+ "type": "StaticLibrary"
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/member-mismatched-type.json b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/member-mismatched-type.json
new file mode 100644
index 0000000..cf85ec2
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/member-mismatched-type.json
@@ -0,0 +1,18 @@
+{
+ "type": "StaticLibrary",
+ "target_triple": "arm64-apple-macosx",
+ "namespace": {
+ "kind": "StaticLibrary",
+ "name": "libfoo"
+ },
+ "members": [
+ {
+ "type": "LUSummary",
+ "target_triple": "arm64-apple-macosx",
+ "lu_namespace": [],
+ "id_table": [],
+ "linkage_table": [],
+ "data": []
+ }
+ ]
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/member-missing-type.json b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/member-missing-type.json
new file mode 100644
index 0000000..3ba536e
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/member-missing-type.json
@@ -0,0 +1,20 @@
+{
+ "members": [
+ {
+ "target_triple": "arm64-apple-macosx",
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "a.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [],
+ "data": []
+ }
+ ],
+ "namespace": {
+ "kind": "StaticLibrary",
+ "name": "libfoo"
+ },
+ "target_triple": "arm64-apple-macosx",
+ "type": "StaticLibrary"
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/member-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/member-not-object.json
new file mode 100644
index 0000000..d62af50
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/member-not-object.json
@@ -0,0 +1,9 @@
+{
+ "type": "StaticLibrary",
+ "target_triple": "arm64-apple-macosx",
+ "namespace": {
+ "kind": "StaticLibrary",
+ "name": "libfoo"
+ },
+ "members": ["not an object"]
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/member-triple-mismatch.json b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/member-triple-mismatch.json
new file mode 100644
index 0000000..39a8c23
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/member-triple-mismatch.json
@@ -0,0 +1,21 @@
+{
+ "type": "StaticLibrary",
+ "target_triple": "arm64-apple-macosx",
+ "namespace": {
+ "kind": "StaticLibrary",
+ "name": "libfoo"
+ },
+ "members": [
+ {
+ "type": "TUSummary",
+ "target_triple": "x86_64-apple-macosx",
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "a.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [],
+ "data": []
+ }
+ ]
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/members-not-array.json b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/members-not-array.json
new file mode 100644
index 0000000..1686e7a
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/members-not-array.json
@@ -0,0 +1,9 @@
+{
+ "type": "StaticLibrary",
+ "target_triple": "arm64-apple-macosx",
+ "namespace": {
+ "kind": "StaticLibrary",
+ "name": "libfoo"
+ },
+ "members": {}
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/mismatched-type.json b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/mismatched-type.json
new file mode 100644
index 0000000..5c75499
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/mismatched-type.json
@@ -0,0 +1,9 @@
+{
+ "type": "TUSummary",
+ "target_triple": "arm64-apple-macosx",
+ "namespace": {
+ "kind": "StaticLibrary",
+ "name": "libfoo"
+ },
+ "members": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/missing-members.json b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/missing-members.json
new file mode 100644
index 0000000..6f5059e
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/missing-members.json
@@ -0,0 +1,8 @@
+{
+ "type": "StaticLibrary",
+ "target_triple": "arm64-apple-macosx",
+ "namespace": {
+ "kind": "StaticLibrary",
+ "name": "libfoo"
+ }
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/missing-namespace.json b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/missing-namespace.json
new file mode 100644
index 0000000..59aa554
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/missing-namespace.json
@@ -0,0 +1,5 @@
+{
+ "type": "StaticLibrary",
+ "target_triple": "arm64-apple-macosx",
+ "members": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/missing-target-triple.json b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/missing-target-triple.json
new file mode 100644
index 0000000..6ab76fc
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/missing-target-triple.json
@@ -0,0 +1,8 @@
+{
+ "type": "StaticLibrary",
+ "namespace": {
+ "kind": "StaticLibrary",
+ "name": "libfoo"
+ },
+ "members": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/missing-type.json b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/missing-type.json
new file mode 100644
index 0000000..9e47006
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/missing-type.json
@@ -0,0 +1,8 @@
+{
+ "target_triple": "arm64-apple-macosx",
+ "namespace": {
+ "kind": "StaticLibrary",
+ "name": "libfoo"
+ },
+ "members": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/namespace-invalid-kind.json b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/namespace-invalid-kind.json
new file mode 100644
index 0000000..5e96399
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/namespace-invalid-kind.json
@@ -0,0 +1,9 @@
+{
+ "type": "StaticLibrary",
+ "target_triple": "arm64-apple-macosx",
+ "namespace": {
+ "kind": "invalid_kind",
+ "name": "libfoo"
+ },
+ "members": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/namespace-missing-kind.json b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/namespace-missing-kind.json
new file mode 100644
index 0000000..7aa0a00
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/namespace-missing-kind.json
@@ -0,0 +1,8 @@
+{
+ "type": "StaticLibrary",
+ "target_triple": "arm64-apple-macosx",
+ "namespace": {
+ "name": "libfoo"
+ },
+ "members": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/namespace-missing-name.json b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/namespace-missing-name.json
new file mode 100644
index 0000000..750e310
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/namespace-missing-name.json
@@ -0,0 +1,8 @@
+{
+ "type": "StaticLibrary",
+ "target_triple": "arm64-apple-macosx",
+ "namespace": {
+ "kind": "StaticLibrary"
+ },
+ "members": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/namespace-wrong-kind.json b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/namespace-wrong-kind.json
new file mode 100644
index 0000000..073cd4a
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/namespace-wrong-kind.json
@@ -0,0 +1,9 @@
+{
+ "type": "StaticLibrary",
+ "target_triple": "arm64-apple-macosx",
+ "namespace": {
+ "kind": "CompilationUnit",
+ "name": "libfoo"
+ },
+ "members": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/not-json-extension.txt b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/not-json-extension.txt
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/not-json-extension.txt
@@ -0,0 +1 @@
+{}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/not-normalized-target-triple.json b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/not-normalized-target-triple.json
new file mode 100644
index 0000000..f9b0c33
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/not-normalized-target-triple.json
@@ -0,0 +1,9 @@
+{
+ "type": "StaticLibrary",
+ "target_triple": "arm64-macosx-apple",
+ "namespace": {
+ "kind": "StaticLibrary",
+ "name": "libfoo"
+ },
+ "members": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/not-object.json b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/not-object.json
new file mode 100644
index 0000000..fe51488
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/not-object.json
@@ -0,0 +1 @@
+[]
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/rt-empty.json b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/rt-empty.json
new file mode 100644
index 0000000..3059d00
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/rt-empty.json
@@ -0,0 +1,9 @@
+{
+ "members": [],
+ "namespace": {
+ "kind": "StaticLibrary",
+ "name": "libempty"
+ },
+ "target_triple": "arm64-apple-macosx",
+ "type": "StaticLibrary"
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/rt-multiple-members.json b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/rt-multiple-members.json
new file mode 100644
index 0000000..7e1636d
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/rt-multiple-members.json
@@ -0,0 +1,43 @@
+{
+ "members": [
+ {
+ "data": [],
+ "id_table": [],
+ "linkage_table": [],
+ "target_triple": "arm64-apple-macosx",
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "a.cpp"
+ },
+ "type": "TUSummary"
+ },
+ {
+ "data": [],
+ "id_table": [],
+ "linkage_table": [],
+ "target_triple": "arm64-apple-macosx",
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "b.cpp"
+ },
+ "type": "TUSummary"
+ },
+ {
+ "data": [],
+ "id_table": [],
+ "linkage_table": [],
+ "target_triple": "arm64-apple-macosx",
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "c.cpp"
+ },
+ "type": "TUSummary"
+ }
+ ],
+ "namespace": {
+ "kind": "StaticLibrary",
+ "name": "libmulti"
+ },
+ "target_triple": "arm64-apple-macosx",
+ "type": "StaticLibrary"
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/rt-single-member.json b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/rt-single-member.json
new file mode 100644
index 0000000..7ad6021
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/rt-single-member.json
@@ -0,0 +1,21 @@
+{
+ "members": [
+ {
+ "data": [],
+ "id_table": [],
+ "linkage_table": [],
+ "target_triple": "arm64-apple-macosx",
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "a.cpp"
+ },
+ "type": "TUSummary"
+ }
+ ],
+ "namespace": {
+ "kind": "StaticLibrary",
+ "name": "libfoo"
+ },
+ "target_triple": "arm64-apple-macosx",
+ "type": "StaticLibrary"
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/unsorted-members-input.json b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/unsorted-members-input.json
new file mode 100644
index 0000000..fb6820c
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/Inputs/unsorted-members-input.json
@@ -0,0 +1,43 @@
+{
+ "members": [
+ {
+ "data": [],
+ "id_table": [],
+ "linkage_table": [],
+ "target_triple": "arm64-apple-macosx",
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "c.cpp"
+ },
+ "type": "TUSummary"
+ },
+ {
+ "data": [],
+ "id_table": [],
+ "linkage_table": [],
+ "target_triple": "arm64-apple-macosx",
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "a.cpp"
+ },
+ "type": "TUSummary"
+ },
+ {
+ "data": [],
+ "id_table": [],
+ "linkage_table": [],
+ "target_triple": "arm64-apple-macosx",
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "b.cpp"
+ },
+ "type": "TUSummary"
+ }
+ ],
+ "namespace": {
+ "kind": "StaticLibrary",
+ "name": "libmulti"
+ },
+ "target_triple": "arm64-apple-macosx",
+ "type": "StaticLibrary"
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/io.test b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/io.test
new file mode 100644
index 0000000..22a94dd
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/io.test
@@ -0,0 +1,49 @@
+// File-I/O error tests: readJSON() input validation and writeJSON() output
+// validation for clang-ssaf-format --type static-library.
+
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+
+// ============================================================================
+// readJSON() errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type static-library %S/Inputs/nonexistent.json 2>&1 \
+// RUN: | FileCheck %s --check-prefix=NONEXISTENT-FILE
+// NONEXISTENT-FILE: clang-ssaf-format: error: failed to validate path '{{.*}}nonexistent.json': Path does not exist
+
+// RUN: mkdir -p %t/test-directory.json
+// RUN: not clang-ssaf-format --type static-library %t/test-directory.json 2>&1 \
+// RUN: | FileCheck %s --check-prefix=PATH-IS-DIRECTORY
+// PATH-IS-DIRECTORY: clang-ssaf-format: error: failed to validate path '{{.*}}test-directory.json': Path is not a file
+
+// RUN: not clang-ssaf-format --type static-library %S/Inputs/not-json-extension.txt 2>&1 \
+// RUN: | FileCheck %s --check-prefix=NOT-JSON-EXTENSION
+// NOT-JSON-EXTENSION: clang-ssaf-format: error: failed to validate path '{{.*}}not-json-extension.txt': No format registered for extension 'txt'
+
+// RUN: not clang-ssaf-format --type static-library %S/Inputs/invalid-syntax.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=INVALID-SYNTAX
+// INVALID-SYNTAX: clang-ssaf-format: error: reading StaticLibrary from file '{{.*}}invalid-syntax.json'
+// INVALID-SYNTAX-NEXT: {{.*}}Expected object key
+
+// RUN: not clang-ssaf-format --type static-library %S/Inputs/not-object.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=NOT-OBJECT
+// NOT-OBJECT: clang-ssaf-format: error: reading StaticLibrary from file '{{.*}}not-object.json'
+// NOT-OBJECT-NEXT: failed to read StaticLibrary: expected JSON object
+
+// ============================================================================
+// writeJSON() errors
+// ============================================================================
+
+// RUN: echo '{}' > %t/existing.json
+// RUN: not clang-ssaf-format --type static-library %S/Inputs/rt-empty.json -o %t/existing.json 2>&1 \
+// RUN: | FileCheck %s --check-prefix=WRITE-FILE-ALREADY-EXISTS
+// WRITE-FILE-ALREADY-EXISTS: clang-ssaf-format: error: failed to validate path '{{.*}}existing.json': File already exists
+
+// RUN: not clang-ssaf-format --type static-library %S/Inputs/rt-empty.json -o %t/nonexistent-dir/test.json 2>&1 \
+// RUN: | FileCheck %s --check-prefix=WRITE-PARENT-DIRECTORY-NOT-FOUND
+// WRITE-PARENT-DIRECTORY-NOT-FOUND: clang-ssaf-format: error: failed to validate path '{{.*}}nonexistent-dir{{.}}test.json': Parent directory does not exist
+
+// RUN: not clang-ssaf-format --type static-library %S/Inputs/rt-empty.json -o %t/test.txt 2>&1 \
+// RUN: | FileCheck %s --check-prefix=WRITE-NOT-JSON-EXTENSION
+// WRITE-NOT-JSON-EXTENSION: clang-ssaf-format: error: failed to validate path '{{.*}}test.txt': No format registered for extension 'txt'
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/permissions.test b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/permissions.test
new file mode 100644
index 0000000..a9455a0
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/permissions.test
@@ -0,0 +1,40 @@
+// Tests for clang-ssaf-format --type static-library that require filesystem
+// permission support (symlinks, chmod).
+
+// UNSUPPORTED: system-windows
+// REQUIRES: non-root-user
+
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+
+// ============================================================================
+// Broken symlink
+// ============================================================================
+
+// RUN: ln -sf %t/nonexistent-target.json %t/broken-symlink.json
+// RUN: not clang-ssaf-format --type static-library %t/broken-symlink.json 2>&1 \
+// RUN: | FileCheck %s --check-prefix=BROKEN-SYMLINK
+// BROKEN-SYMLINK: clang-ssaf-format: error: failed to validate path '{{.*}}broken-symlink.json': Path does not exist
+
+// ============================================================================
+// No read permission
+// ============================================================================
+
+// RUN: cp %S/Inputs/rt-empty.json %t/no-read-permission.json
+// RUN: chmod -r %t/no-read-permission.json
+// RUN: not clang-ssaf-format --type static-library %t/no-read-permission.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=NO-READ-PERMISSION
+// RUN: chmod +r %t/no-read-permission.json
+// NO-READ-PERMISSION: clang-ssaf-format: error: reading StaticLibrary from file '{{.*}}no-read-permission.json'
+// NO-READ-PERMISSION-NEXT: failed to read file '{{.*}}no-read-permission.json': {{.*}}
+
+// ============================================================================
+// Write to directory without write permission
+// ============================================================================
+
+// RUN: mkdir -p %t/write-protected-dir
+// RUN: chmod -w %t/write-protected-dir
+// RUN: not clang-ssaf-format --type static-library %S/Inputs/rt-empty.json -o %t/write-protected-dir/test.json 2>&1 \
+// RUN: | FileCheck %s --check-prefix=WRITE-STREAM-OPEN-FAILURE
+// RUN: chmod +w %t/write-protected-dir
+// WRITE-STREAM-OPEN-FAILURE: clang-ssaf-format: error: failed to validate path '{{.*}}write-protected-dir{{.}}test.json': Parent directory is not writable
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/round-trip.test b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/round-trip.test
new file mode 100644
index 0000000..b63dd08
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/round-trip.test
@@ -0,0 +1,42 @@
+// Round-trip tests: read a StaticLibrary JSON input, write it back out,
+// and diff the result against the original.
+//
+// StaticLibrary has only an encoding representation, so --encoding is a
+// no-op for --type static-library and both invocations must produce the
+// same output.
+
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+
+// ============================================================================
+// Round-Trip Tests
+// ============================================================================
+
+// RUN: clang-ssaf-format --type static-library %S/Inputs/rt-empty.json -o %t/rt-empty.json
+// RUN: diff %S/Inputs/rt-empty.json %t/rt-empty.json
+// RUN: clang-ssaf-format --type static-library --encoding %S/Inputs/rt-empty.json -o %t/rt-empty-enc.json
+// RUN: diff %S/Inputs/rt-empty.json %t/rt-empty-enc.json
+
+// RUN: clang-ssaf-format --type static-library %S/Inputs/rt-single-member.json -o %t/rt-single-member.json
+// RUN: diff %S/Inputs/rt-single-member.json %t/rt-single-member.json
+// RUN: clang-ssaf-format --type static-library --encoding %S/Inputs/rt-single-member.json -o %t/rt-single-member-enc.json
+// RUN: diff %S/Inputs/rt-single-member.json %t/rt-single-member-enc.json
+
+// RUN: clang-ssaf-format --type static-library %S/Inputs/rt-multiple-members.json -o %t/rt-multiple-members.json
+// RUN: diff %S/Inputs/rt-multiple-members.json %t/rt-multiple-members.json
+// RUN: clang-ssaf-format --type static-library --encoding %S/Inputs/rt-multiple-members.json -o %t/rt-multiple-members-enc.json
+// RUN: diff %S/Inputs/rt-multiple-members.json %t/rt-multiple-members-enc.json
+
+// ============================================================================
+// Member sort order
+// ============================================================================
+//
+// Members are stored in a std::set ordered by TUNamespace, so the writer
+// emits them sorted regardless of input order. unsorted-members-input.json
+// has the same members as rt-multiple-members.json but listed c, a, b;
+// the writer must produce the canonical (a, b, c) ordering.
+
+// RUN: clang-ssaf-format --type static-library %S/Inputs/unsorted-members-input.json -o %t/unsorted-members-output.json
+// RUN: diff %S/Inputs/rt-multiple-members.json %t/unsorted-members-output.json
+// RUN: clang-ssaf-format --type static-library --encoding %S/Inputs/unsorted-members-input.json -o %t/unsorted-members-output-enc.json
+// RUN: diff %S/Inputs/rt-multiple-members.json %t/unsorted-members-output-enc.json
diff --git a/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/top-level.test b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/top-level.test
new file mode 100644
index 0000000..a27496f
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/StaticLibrary/top-level.test
@@ -0,0 +1,125 @@
+// Top-level StaticLibrary structure tests: target_triple, namespace
+// (StaticLibrary kind), members array, and per-member validation. Mirrors
+// the LUSummary top-level test pattern but covers the StaticLibrary-specific
+// shape.
+
+// ============================================================================
+// readStaticLibrary() / writeStaticLibrary() type-field errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type static-library %S/Inputs/missing-type.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=MISSING-TYPE
+// MISSING-TYPE: clang-ssaf-format: error: reading StaticLibrary from file '{{.*}}missing-type.json'
+// MISSING-TYPE-NEXT: failed to read summary type from field 'type': expected JSON string
+
+// RUN: not clang-ssaf-format --type static-library %S/Inputs/mismatched-type.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=MISMATCHED-TYPE
+// MISMATCHED-TYPE: clang-ssaf-format: error: reading StaticLibrary from file '{{.*}}mismatched-type.json'
+// MISMATCHED-TYPE-NEXT: expected 'StaticLibrary' for field 'type' but got 'TUSummary'
+
+// ============================================================================
+// target_triple errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type static-library %S/Inputs/missing-target-triple.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=MISSING-TARGET-TRIPLE
+// MISSING-TARGET-TRIPLE: clang-ssaf-format: error: reading StaticLibrary from file '{{.*}}missing-target-triple.json'
+// MISSING-TARGET-TRIPLE-NEXT: failed to read TargetTriple from field 'target_triple': expected JSON string
+
+// RUN: not clang-ssaf-format --type static-library %S/Inputs/not-normalized-target-triple.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=NOT-NORMALIZED-TARGET-TRIPLE
+// NOT-NORMALIZED-TARGET-TRIPLE: clang-ssaf-format: error: reading StaticLibrary from file '{{.*}}not-normalized-target-triple.json'
+// NOT-NORMALIZED-TARGET-TRIPLE-NEXT: reading TargetTriple from field 'target_triple'
+// NOT-NORMALIZED-TARGET-TRIPLE-NEXT: target triple 'arm64-macosx-apple' is not in normalized form (expected 'arm64-apple-macosx')
+
+// ============================================================================
+// namespace errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type static-library %S/Inputs/missing-namespace.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=MISSING-NAMESPACE
+// MISSING-NAMESPACE: clang-ssaf-format: error: reading StaticLibrary from file '{{.*}}missing-namespace.json'
+// MISSING-NAMESPACE-NEXT: failed to read BuildNamespace from field 'namespace': expected JSON object
+
+// RUN: not clang-ssaf-format --type static-library %S/Inputs/namespace-missing-kind.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=NAMESPACE-MISSING-KIND
+// NAMESPACE-MISSING-KIND: clang-ssaf-format: error: reading StaticLibrary from file '{{.*}}namespace-missing-kind.json'
+// NAMESPACE-MISSING-KIND-NEXT: reading BuildNamespace from field 'namespace'
+// NAMESPACE-MISSING-KIND-NEXT: failed to read BuildNamespaceKind from field 'kind': expected JSON string
+
+// RUN: not clang-ssaf-format --type static-library %S/Inputs/namespace-invalid-kind.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=NAMESPACE-INVALID-KIND
+// NAMESPACE-INVALID-KIND: clang-ssaf-format: error: reading StaticLibrary from file '{{.*}}namespace-invalid-kind.json'
+// NAMESPACE-INVALID-KIND-NEXT: reading BuildNamespace from field 'namespace'
+// NAMESPACE-INVALID-KIND-NEXT: reading BuildNamespaceKind from field 'kind'
+// NAMESPACE-INVALID-KIND-NEXT: invalid BuildNamespaceKind value 'invalid_kind' for field 'kind'
+
+// StaticLibrary's namespace field must specifically have kind=StaticLibrary.
+// Any other well-formed kind (CompilationUnit, LinkUnit) is reported as a
+// mismatch.
+// RUN: not clang-ssaf-format --type static-library %S/Inputs/namespace-wrong-kind.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=NAMESPACE-WRONG-KIND
+// NAMESPACE-WRONG-KIND: clang-ssaf-format: error: reading StaticLibrary from file '{{.*}}namespace-wrong-kind.json'
+// NAMESPACE-WRONG-KIND-NEXT: expected 'StaticLibrary' for field 'namespace.kind' but got 'CompilationUnit'
+
+// RUN: not clang-ssaf-format --type static-library %S/Inputs/namespace-missing-name.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=NAMESPACE-MISSING-NAME
+// NAMESPACE-MISSING-NAME: clang-ssaf-format: error: reading StaticLibrary from file '{{.*}}namespace-missing-name.json'
+// NAMESPACE-MISSING-NAME-NEXT: reading BuildNamespace from field 'namespace'
+// NAMESPACE-MISSING-NAME-NEXT: failed to read BuildNamespaceName from field 'name': expected JSON string
+
+// ============================================================================
+// members array errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type static-library %S/Inputs/missing-members.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=MISSING-MEMBERS
+// MISSING-MEMBERS: clang-ssaf-format: error: reading StaticLibrary from file '{{.*}}missing-members.json'
+// MISSING-MEMBERS-NEXT: failed to read StaticLibrary members from field 'members': expected JSON array
+
+// RUN: not clang-ssaf-format --type static-library %S/Inputs/members-not-array.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=MEMBERS-NOT-ARRAY
+// MEMBERS-NOT-ARRAY: clang-ssaf-format: error: reading StaticLibrary from file '{{.*}}members-not-array.json'
+// MEMBERS-NOT-ARRAY-NEXT: failed to read StaticLibrary members from field 'members': expected JSON array
+
+// RUN: not clang-ssaf-format --type static-library %S/Inputs/member-not-object.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=MEMBER-NOT-OBJECT
+// MEMBER-NOT-OBJECT: clang-ssaf-format: error: reading StaticLibrary from file '{{.*}}member-not-object.json'
+// MEMBER-NOT-OBJECT-NEXT: failed to read StaticLibrary member from index '0': expected JSON object
+
+// ============================================================================
+// per-member errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type static-library %S/Inputs/member-mismatched-type.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=MEMBER-MISMATCHED-TYPE
+// MEMBER-MISMATCHED-TYPE: clang-ssaf-format: error: reading StaticLibrary from file '{{.*}}member-mismatched-type.json'
+// MEMBER-MISMATCHED-TYPE-NEXT: reading StaticLibrary member from index '0'
+// MEMBER-MISMATCHED-TYPE-NEXT: expected 'TUSummary' for field 'type' but got 'LUSummary'
+
+// RUN: not clang-ssaf-format --type static-library %S/Inputs/member-missing-type.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=MEMBER-MISSING-TYPE
+// MEMBER-MISSING-TYPE: clang-ssaf-format: error: reading StaticLibrary from file '{{.*}}member-missing-type.json'
+// MEMBER-MISSING-TYPE-NEXT: reading StaticLibrary member from index '0'
+// MEMBER-MISSING-TYPE-NEXT: failed to read summary type from field 'type': expected JSON string
+
+// Verifies that errors raised inside readTUSummaryEncodingFromObject (here,
+// a missing tu_namespace on the member) are properly wrapped with the
+// "reading StaticLibrary member from index 'N'" context, then with the
+// outer "reading StaticLibrary from file '...'" context.
+// RUN: not clang-ssaf-format --type static-library %S/Inputs/member-inner-error.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=MEMBER-INNER-ERROR
+// MEMBER-INNER-ERROR: clang-ssaf-format: error: reading StaticLibrary from file '{{.*}}member-inner-error.json'
+// MEMBER-INNER-ERROR-NEXT: reading StaticLibrary member from index '0'
+// MEMBER-INNER-ERROR-NEXT: failed to read BuildNamespace from field 'tu_namespace': expected JSON object
+
+// RUN: not clang-ssaf-format --type static-library %S/Inputs/member-triple-mismatch.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=MEMBER-TRIPLE-MISMATCH
+// MEMBER-TRIPLE-MISMATCH: clang-ssaf-format: error: reading StaticLibrary from file '{{.*}}member-triple-mismatch.json'
+// MEMBER-TRIPLE-MISMATCH-NEXT: reading StaticLibrary member from index '0'
+// MEMBER-TRIPLE-MISMATCH-NEXT: expected 'arm64-apple-macosx' for field 'target_triple' but got 'x86_64-apple-macosx'
+
+// RUN: not clang-ssaf-format --type static-library %S/Inputs/duplicate-member.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=DUPLICATE-MEMBER
+// DUPLICATE-MEMBER: clang-ssaf-format: error: reading StaticLibrary from file '{{.*}}duplicate-member.json'
+// DUPLICATE-MEMBER-NEXT: failed to insert StaticLibrary member at index '1': encountered duplicate 'BuildNamespace(CompilationUnit, a.cpp)'
diff --git a/clang/tools/clang-ssaf-format/SSAFFormat.cpp b/clang/tools/clang-ssaf-format/SSAFFormat.cpp
index 9416b45..5b94da3 100644
--- a/clang/tools/clang-ssaf-format/SSAFFormat.cpp
+++ b/clang/tools/clang-ssaf-format/SSAFFormat.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/ScalableStaticAnalysis/Core/EntityLinker/LUSummaryEncoding.h"
+#include "clang/ScalableStaticAnalysis/Core/EntityLinker/StaticLibrary.h"
#include "clang/ScalableStaticAnalysis/Core/EntityLinker/TUSummaryEncoding.h"
#include "clang/ScalableStaticAnalysis/Core/Serialization/JSONFormat.h"
#include "clang/ScalableStaticAnalysis/Core/Serialization/SerializationFormatRegistry.h"
@@ -39,7 +40,7 @@
// Summary Type
//===----------------------------------------------------------------------===//
-enum class SummaryType { Auto, TU, LU, WPA };
+enum class SummaryType { Auto, TU, LU, StaticLibrary, WPA };
//===----------------------------------------------------------------------===//
// Command-Line Options
@@ -63,6 +64,8 @@
"Detect type from the file's 'type' field"),
clEnumValN(SummaryType::TU, "tu", "Translation unit summary"),
clEnumValN(SummaryType::LU, "lu", "Link unit summary"),
+ clEnumValN(SummaryType::StaticLibrary, "static-library",
+ "Static library of translation unit summaries"),
clEnumValN(SummaryType::WPA, "wpa",
"Whole-program analysis suite")),
cl::init(SummaryType::Auto), cl::cat(SsafFormatCategory));
@@ -295,6 +298,12 @@
&SerializationFormat::writeLUSummary);
}
return;
+ case SummaryType::StaticLibrary:
+ // StaticLibrary has only an encoded representation, so --encoding is a
+ // no-op here: both paths route to readStaticLibrary / writeStaticLibrary.
+ run(FI, &SerializationFormat::readStaticLibrary,
+ &SerializationFormat::writeStaticLibrary);
+ return;
case SummaryType::WPA:
run(FI, &SerializationFormat::readWPASuite,
&SerializationFormat::writeWPASuite);
diff --git a/clang/unittests/ScalableStaticAnalysis/BuildNamespaceTest.cpp b/clang/unittests/ScalableStaticAnalysis/BuildNamespaceTest.cpp
index e98efd4..5089796 100644
--- a/clang/unittests/ScalableStaticAnalysis/BuildNamespaceTest.cpp
+++ b/clang/unittests/ScalableStaticAnalysis/BuildNamespaceTest.cpp
@@ -83,6 +83,8 @@
"CompilationUnit");
EXPECT_EQ(llvm::formatv("{0}", BuildNamespaceKind::LinkUnit).str(),
"LinkUnit");
+ EXPECT_EQ(llvm::formatv("{0}", BuildNamespaceKind::StaticLibrary).str(),
+ "StaticLibrary");
}
TEST(BuildNamespaceKindTest, StreamOutputCompilationUnit) {
@@ -97,6 +99,12 @@
EXPECT_EQ(S, "LinkUnit");
}
+TEST(BuildNamespaceKindTest, StreamOutputStaticLibrary) {
+ std::string S;
+ llvm::raw_string_ostream(S) << BuildNamespaceKind::StaticLibrary;
+ EXPECT_EQ(S, "StaticLibrary");
+}
+
TEST(BuildNamespaceTest, FormatProvider) {
EXPECT_EQ(
llvm::formatv("{0}", BuildNamespace(BuildNamespaceKind::CompilationUnit,
diff --git a/clang/unittests/ScalableStaticAnalysis/Frontend/TUSummaryExtractorFrontendActionTest.cpp b/clang/unittests/ScalableStaticAnalysis/Frontend/TUSummaryExtractorFrontendActionTest.cpp
index 2d65fb6..4baf593 100644
--- a/clang/unittests/ScalableStaticAnalysis/Frontend/TUSummaryExtractorFrontendActionTest.cpp
+++ b/clang/unittests/ScalableStaticAnalysis/Frontend/TUSummaryExtractorFrontendActionTest.cpp
@@ -98,6 +98,16 @@
return failing("writeLUSummaryEncoding");
}
+ llvm::Expected<StaticLibrary>
+ readStaticLibrary(llvm::StringRef Path) override {
+ return failing("readStaticLibrary");
+ }
+
+ llvm::Error writeStaticLibrary(const StaticLibrary &S,
+ llvm::StringRef Path) override {
+ return failing("writeStaticLibrary");
+ }
+
llvm::Expected<WPASuite> readWPASuite(llvm::StringRef Path) override {
return failing("readWPASuite");
}
@@ -179,6 +189,13 @@
llvm::StringRef) override {
return llvm::Error::success();
}
+ llvm::Expected<StaticLibrary> readStaticLibrary(llvm::StringRef) override {
+ return llvm::createStringError("not implemented");
+ }
+ llvm::Error writeStaticLibrary(const StaticLibrary &,
+ llvm::StringRef) override {
+ return llvm::Error::success();
+ }
llvm::Expected<WPASuite> readWPASuite(llvm::StringRef) override {
return llvm::createStringError("not implemented");
}
diff --git a/clang/unittests/ScalableStaticAnalysis/ModelStringConversionsTest.cpp b/clang/unittests/ScalableStaticAnalysis/ModelStringConversionsTest.cpp
index ff24a83..b0c741d 100644
--- a/clang/unittests/ScalableStaticAnalysis/ModelStringConversionsTest.cpp
+++ b/clang/unittests/ScalableStaticAnalysis/ModelStringConversionsTest.cpp
@@ -27,6 +27,11 @@
"LinkUnit");
}
+TEST(BuildNamespaceKindStringTest, ToStringStaticLibrary) {
+ EXPECT_EQ(buildNamespaceKindToString(BuildNamespaceKind::StaticLibrary),
+ "StaticLibrary");
+}
+
TEST(BuildNamespaceKindStringTest, FromStringCompilationUnit) {
EXPECT_EQ(buildNamespaceKindFromString("CompilationUnit"),
BuildNamespaceKind::CompilationUnit);
@@ -37,9 +42,15 @@
BuildNamespaceKind::LinkUnit);
}
+TEST(BuildNamespaceKindStringTest, FromStringStaticLibrary) {
+ EXPECT_EQ(buildNamespaceKindFromString("StaticLibrary"),
+ BuildNamespaceKind::StaticLibrary);
+}
+
TEST(BuildNamespaceKindStringTest, FromStringUnknown) {
EXPECT_EQ(buildNamespaceKindFromString("compilation_unit"), std::nullopt);
EXPECT_EQ(buildNamespaceKindFromString("link_unit"), std::nullopt);
+ EXPECT_EQ(buildNamespaceKindFromString("static_library"), std::nullopt);
EXPECT_EQ(buildNamespaceKindFromString(""), std::nullopt);
EXPECT_EQ(buildNamespaceKindFromString("unknown"), std::nullopt);
}
@@ -51,6 +62,9 @@
EXPECT_EQ(buildNamespaceKindFromString(
buildNamespaceKindToString(BuildNamespaceKind::LinkUnit)),
BuildNamespaceKind::LinkUnit);
+ EXPECT_EQ(buildNamespaceKindFromString(
+ buildNamespaceKindToString(BuildNamespaceKind::StaticLibrary)),
+ BuildNamespaceKind::StaticLibrary);
}
//===----------------------------------------------------------------------===//
diff --git a/clang/unittests/ScalableStaticAnalysis/Registries/MockSerializationFormat.cpp b/clang/unittests/ScalableStaticAnalysis/Registries/MockSerializationFormat.cpp
index 915fe15..4a01248 100644
--- a/clang/unittests/ScalableStaticAnalysis/Registries/MockSerializationFormat.cpp
+++ b/clang/unittests/ScalableStaticAnalysis/Registries/MockSerializationFormat.cpp
@@ -9,6 +9,7 @@
#include "Registries/MockSerializationFormat.h"
#include "clang/ScalableStaticAnalysis/Core/EntityLinker/LUSummary.h"
#include "clang/ScalableStaticAnalysis/Core/EntityLinker/LUSummaryEncoding.h"
+#include "clang/ScalableStaticAnalysis/Core/EntityLinker/StaticLibrary.h"
#include "clang/ScalableStaticAnalysis/Core/EntityLinker/TUSummaryEncoding.h"
#include "clang/ScalableStaticAnalysis/Core/Model/BuildNamespace.h"
#include "clang/ScalableStaticAnalysis/Core/Model/EntityName.h"
@@ -198,6 +199,16 @@
"MockSerializationFormat does not support LUSummaryEncoding");
}
+llvm::Expected<StaticLibrary>
+MockSerializationFormat::readStaticLibrary(llvm::StringRef Path) {
+ llvm_unreachable("MockSerializationFormat does not support StaticLibrary");
+}
+
+llvm::Error MockSerializationFormat::writeStaticLibrary(const StaticLibrary &S,
+ llvm::StringRef Path) {
+ llvm_unreachable("MockSerializationFormat does not support StaticLibrary");
+}
+
llvm::Expected<WPASuite>
MockSerializationFormat::readWPASuite(llvm::StringRef Path) {
llvm_unreachable("MockSerializationFormat does not support WPASuite");
diff --git a/clang/unittests/ScalableStaticAnalysis/Registries/MockSerializationFormat.h b/clang/unittests/ScalableStaticAnalysis/Registries/MockSerializationFormat.h
index 2ecaab9..0cadd0b 100644
--- a/clang/unittests/ScalableStaticAnalysis/Registries/MockSerializationFormat.h
+++ b/clang/unittests/ScalableStaticAnalysis/Registries/MockSerializationFormat.h
@@ -44,6 +44,12 @@
llvm::Error writeLUSummaryEncoding(const LUSummaryEncoding &SummaryEncoding,
llvm::StringRef Path) override;
+ llvm::Expected<StaticLibrary>
+ readStaticLibrary(llvm::StringRef Path) override;
+
+ llvm::Error writeStaticLibrary(const StaticLibrary &S,
+ llvm::StringRef Path) override;
+
llvm::Expected<Artifact> readArtifact(llvm::StringRef Path) override;
llvm::Error writeArtifact(const Artifact &A, llvm::StringRef Path) override;
diff --git a/clang/unittests/ScalableStaticAnalysis/TestFixture.h b/clang/unittests/ScalableStaticAnalysis/TestFixture.h
index 22fbff7..e7eed94 100644
--- a/clang/unittests/ScalableStaticAnalysis/TestFixture.h
+++ b/clang/unittests/ScalableStaticAnalysis/TestFixture.h
@@ -11,6 +11,7 @@
#include "clang/ScalableStaticAnalysis/Core/EntityLinker/LUSummary.h"
#include "clang/ScalableStaticAnalysis/Core/EntityLinker/LUSummaryEncoding.h"
+#include "clang/ScalableStaticAnalysis/Core/EntityLinker/StaticLibrary.h"
#include "clang/ScalableStaticAnalysis/Core/EntityLinker/TUSummaryEncoding.h"
#include "clang/ScalableStaticAnalysis/Core/Model/BuildNamespace.h"
#include "clang/ScalableStaticAnalysis/Core/Model/EntityId.h"