clang 23.0.0git
SerializationFormat.h
Go to the documentation of this file.
1//===- SerializationFormat.h ------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Abstract SerializationFormat interface for reading and writing
10// TUSummary and LinkUnitResolution data.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_SCALABLESTATICANALYSIS_CORE_SERIALIZATION_SERIALIZATIONFORMAT_H
15#define LLVM_CLANG_SCALABLESTATICANALYSIS_CORE_SERIALIZATION_SERIALIZATIONFORMAT_H
16
25#include "llvm/ADT/STLFunctionalExtras.h"
26#include "llvm/ADT/StringRef.h"
27#include "llvm/Support/Error.h"
28#include "llvm/Support/Registry.h"
29
30#include <variant>
31
32namespace clang::ssaf {
33
34/// Sum type returned by \c SerializationFormat::readArtifact, used when the
35/// caller does not know up-front which kind of top-level SSAF artifact a
36/// file contains. The active alternative is decided by the file's
37/// self-describing type field.
38using Artifact = std::variant<TUSummary, LUSummary, WPASuite>;
39
40/// Lazily-deserialized counterpart of \c Artifact: the same on-disk
41/// artifacts but with their per-entity summary payloads left as opaque
42/// format-specific encodings rather than fully resolved analysis results.
43using ArtifactEncoding = std::variant<TUSummaryEncoding, LUSummaryEncoding>;
44
45/// Abstract base class for serialization formats.
47public:
48 virtual ~SerializationFormat() = default;
49
50 virtual llvm::Expected<TUSummary> readTUSummary(llvm::StringRef Path) = 0;
51
52 virtual llvm::Error writeTUSummary(const TUSummary &Summary,
53 llvm::StringRef Path) = 0;
54
56 readTUSummaryEncoding(llvm::StringRef Path) = 0;
57
58 virtual llvm::Error
60 llvm::StringRef Path) = 0;
61
62 virtual llvm::Expected<LUSummary> readLUSummary(llvm::StringRef Path) = 0;
63
64 virtual llvm::Error writeLUSummary(const LUSummary &Summary,
65 llvm::StringRef Path) = 0;
66
67 /// Generic read entry point. Inspects the file's self-describing type
68 /// field and dispatches to \c readTUSummary or \c readLUSummary
69 /// accordingly. Returns an error if the type field is missing or names
70 /// an unrecognized artifact kind.
71 virtual llvm::Expected<Artifact> readArtifact(llvm::StringRef Path) = 0;
72
73 /// Generic write entry point. Dispatches to \c writeTUSummary or
74 /// \c writeLUSummary based on the active variant alternative.
75 virtual llvm::Error writeArtifact(const Artifact &A,
76 llvm::StringRef Path) = 0;
77
78 /// Encoding-flavored counterpart of \c readArtifact. Inspects the
79 /// self-describing type field and dispatches to
80 /// \c readTUSummaryEncoding or \c readLUSummaryEncoding accordingly.
82 readArtifactEncoding(llvm::StringRef Path) = 0;
83
84 /// Encoding-flavored counterpart of \c writeArtifact. Dispatches to
85 /// \c writeTUSummaryEncoding or \c writeLUSummaryEncoding based on the
86 /// active variant alternative.
87 virtual llvm::Error writeArtifactEncoding(const ArtifactEncoding &E,
88 llvm::StringRef Path) = 0;
89
91 readLUSummaryEncoding(llvm::StringRef Path) = 0;
92
93 virtual llvm::Error
95 llvm::StringRef Path) = 0;
96
97 virtual llvm::Expected<WPASuite> readWPASuite(llvm::StringRef Path) = 0;
98
99 virtual llvm::Error writeWPASuite(const WPASuite &Suite,
100 llvm::StringRef Path) = 0;
101
102 /// Invokes \p Callback once for each analysis that has registered
103 /// serialization support for this format.
105 llvm::function_ref<void(llvm::StringRef Name, llvm::StringRef Desc)>
106 Callback) const = 0;
107
108protected:
109 // Helpers providing access to implementation details of basic data structures
110 // for efficient serialization/deserialization.
111
112 static EntityId makeEntityId(const size_t Index) { return EntityId(Index); }
113
114 /// Constructs an empty WPASuite. Bypasses the private default constructor
115 /// so that deserialization code can build a WPASuite incrementally.
116 static WPASuite makeWPASuite() { return WPASuite(); }
117
118#define FIELD(CLASS, FIELD_NAME) \
119 static const auto &get##FIELD_NAME(const CLASS &X) { return X.FIELD_NAME; } \
120 static auto &get##FIELD_NAME(CLASS &X) { return X.FIELD_NAME; }
121#include "clang/ScalableStaticAnalysis/Core/Model/PrivateFieldNames.def"
122
123 /// Per-format plugin registry for analysis result (de)serializers.
124 ///
125 /// Each concrete format (e.g. JSONFormat) instantiates this template once
126 /// via a public \c using alias. Analysis authors register support with:
127 ///
128 /// \code
129 /// static MyFormat::AnalysisResultRegistry::Add<MyAnalysisResult>
130 /// Reg(serializeFn, deserializeFn);
131 /// \endcode
132 ///
133 /// The serializer receives a \c const reference to \c MyAnalysisResult
134 /// directly and the \c Add wrapper handles the downcast from \c
135 /// AnalysisResult internally via virtual dispatch.
136 ///
137 /// \tparam FormatT Phantom type is needed to disambiguate \c llvm::Registry
138 /// instantiations. \c llvm::Registry is keyed on the \c Entry type,
139 /// so two formats sharing the same serializer/deserializer signatures
140 /// would collide on the same registry without this parameter.
141 template <class FormatT, class SerializerFn, class DeserializerFn>
143
144 template <class FormatT, class SerRet, class... SerArgs, class DesRet,
145 class... DesArgs>
147 FormatT, llvm::function_ref<SerRet(const AnalysisResult &, SerArgs...)>,
148 llvm::function_ref<DesRet(DesArgs...)>> {
149
150 using DeserializerFn = DesRet (*)(DesArgs...);
151
152 public:
153 /// Abstract base type stored in \c llvm::Registry<Codec>.
154 /// Subclasses override \c serialize() and \c deserialize() to
155 /// dispatch to the plugin's concrete functions.
156 ///
157 /// There is one \c Codec type (and one \c llvm::Registry<Codec>) per
158 /// format. All analysis-specific concrete subclasses for a given format
159 /// register into that single registry. The \c FormatT phantom type
160 /// parameter on the enclosing class ensures that different formats
161 /// produce distinct \c Codec types and thus separate registries.
162 struct Codec {
163 virtual ~Codec() = default;
164 virtual SerRet serialize(const AnalysisResult &, SerArgs...) const = 0;
165 virtual DesRet deserialize(DesArgs...) const = 0;
166 };
167
168 template <class AnalysisResultT> struct Add {
169 using TypedSerializerFn = SerRet (*)(const AnalysisResultT &, SerArgs...);
170
172 static inline DeserializerFn SavedDeserialize;
173
174 /// Takes the plugin's typed serializer and the deserializer, and
175 /// inserts them into \c llvm::Registry<Codec>.
176 Add(TypedSerializerFn TypedSerialize, DeserializerFn Deserialize) {
177 /// Per-\c AnalysisResultT guard: each template instantiation gets
178 /// its own \c static \c bool, so double-registration of the same
179 /// analysis is caught even across translation units.
180 static bool Registered = false;
181 if (Registered) {
182 ErrorBuilder::fatal("support is already registered for analysis: {0}",
183 AnalysisResultT::analysisName());
184 }
185 Registered = true;
186
187 /// The plugin's serializer and deserializer are captured in
188 /// static inline members of the Add template so that the
189 /// \c ConcreteCodec default constructor (required by \c llvm::Registry)
190 /// can read them. They use raw function pointers to prevent dangling
191 /// references to temporary stack variables during registration.
192 ///
193 /// Once read by the constructor, they are stored as instance members
194 /// of \c ConcreteCodec rather than directly executed from the \c static
195 /// \c inline class members. This prevents symbol visibility issues
196 /// across shared library boundaries on Linux (where \c dlopen with \c
197 /// RTLD_LOCAL can give the host and plugin separate copies of \c static
198 /// \c inline members).
199 SavedSerialize = TypedSerialize;
200 SavedDeserialize = Deserialize;
201
202 /// Concrete subclass of \c Codec for \c AnalysisResultT.
203 /// The \c serialize() override performs the downcast from
204 /// \c AnalysisResult to \c AnalysisResultT.
205 struct ConcreteCodec final : Codec {
206 TypedSerializerFn SerFn;
207 DeserializerFn DesFn;
208
209 ConcreteCodec() : SerFn(SavedSerialize), DesFn(SavedDeserialize) {}
210
211 SerRet serialize(const AnalysisResult &Base,
212 SerArgs... args) const override {
213 return SerFn(static_cast<const AnalysisResultT &>(Base), args...);
214 }
215
216 DesRet deserialize(DesArgs... args) const override {
217 return DesFn(args...);
218 }
219 };
220
221 /// \c llvm::Registry stores the name as a \c StringRef, so the
222 /// underlying string must be kept alive with a static declaration.
223 static std::string NameStr =
224 AnalysisResultT::analysisName().str().str();
225
226 /// This performs the actual registration. It appends a factory for \c
227 /// ConcreteCodec to the global \c llvm::Registry<Codec>. \c static
228 /// ensures the `Registry::Add` object lives for the entire program,
229 /// keeping its codec and node alive in the registry's linked list.
230 [[maybe_unused]] static
231 typename llvm::Registry<Codec>::template Add<ConcreteCodec>
232 RegisterUsingCtorSideEffect(NameStr, "");
233 }
234 };
235
236 /// Looks up the codec for \p Name by walking the registry list.
239 for (const auto &E : llvm::Registry<Codec>::entries()) {
240 if (E.getName() == Name.str()) {
241 return E.instantiate();
242 }
243 }
244 return ErrorBuilder::create(std::errc::invalid_argument,
245 "no support registered for analysis: {0}",
246 Name)
247 .build();
248 }
249 };
250};
251
252template <class SerializerFn, class DeserializerFn> struct FormatInfoEntry {
257 virtual ~FormatInfoEntry() = default;
258
260 SerializerFn Serialize;
261 DeserializerFn Deserialize;
262};
263
264} // namespace clang::ssaf
265
266#endif // LLVM_CLANG_SCALABLESTATICANALYSIS_CORE_SERIALIZATION_SERIALIZATIONFORMAT_H
static json::Object serialize(const EntitySummary &Summary, JSONFormat::EntityIdToJSONFn ToJSON)
static Expected< std::unique_ptr< EntitySummary > > deserialize(const json::Object &Obj, EntityIdTable &IdTable, JSONFormat::EntityIdFromJSONFn FromJSON)
Uniquely identifies a whole-program analysis and the AnalysisResult it produces.
llvm::StringRef str() const
Explicit conversion to the underlying string representation.
Base class for whole-program analysis results.
Lightweight opaque handle representing an entity in an EntityIdTable.
Definition EntityId.h:31
static ErrorBuilder create(std::error_code EC, const char *Fmt, Args &&...ArgVals)
Create an ErrorBuilder with an error code and formatted message.
static void fatal(const char *Fmt, Args &&...ArgVals)
Report a fatal error with formatted message and terminate execution.
llvm::Error build() const
Build and return the final error.
Represents a link unit summary in its serialized encoding.
Represents a link unit (LU) summary containing merged entity summaries.
Definition LUSummary.h:34
static llvm::Expected< std::unique_ptr< Codec > > instantiate(const AnalysisName &Name)
Looks up the codec for Name by walking the registry list.
Per-format plugin registry for analysis result (de)serializers.
Abstract base class for serialization formats.
virtual llvm::Error writeLUSummary(const LUSummary &Summary, llvm::StringRef Path)=0
virtual llvm::Expected< Artifact > readArtifact(llvm::StringRef Path)=0
Generic read entry point.
virtual llvm::Error writeArtifact(const Artifact &A, llvm::StringRef Path)=0
Generic write entry point.
virtual llvm::Expected< ArtifactEncoding > readArtifactEncoding(llvm::StringRef Path)=0
Encoding-flavored counterpart of readArtifact.
virtual llvm::Expected< LUSummary > readLUSummary(llvm::StringRef Path)=0
virtual llvm::Expected< WPASuite > readWPASuite(llvm::StringRef Path)=0
static EntityId makeEntityId(const size_t Index)
virtual llvm::Expected< LUSummaryEncoding > readLUSummaryEncoding(llvm::StringRef Path)=0
virtual llvm::Error writeWPASuite(const WPASuite &Suite, llvm::StringRef Path)=0
virtual llvm::Error writeTUSummary(const TUSummary &Summary, llvm::StringRef Path)=0
virtual void forEachRegisteredAnalysis(llvm::function_ref< void(llvm::StringRef Name, llvm::StringRef Desc)> Callback) const =0
Invokes Callback once for each analysis that has registered serialization support for this format.
virtual llvm::Error writeArtifactEncoding(const ArtifactEncoding &E, llvm::StringRef Path)=0
Encoding-flavored counterpart of writeArtifact.
virtual ~SerializationFormat()=default
virtual llvm::Expected< TUSummaryEncoding > readTUSummaryEncoding(llvm::StringRef Path)=0
virtual llvm::Error writeLUSummaryEncoding(const LUSummaryEncoding &SummaryEncoding, llvm::StringRef Path)=0
virtual llvm::Expected< TUSummary > readTUSummary(llvm::StringRef Path)=0
virtual llvm::Error writeTUSummaryEncoding(const TUSummaryEncoding &SummaryEncoding, llvm::StringRef Path)=0
static WPASuite makeWPASuite()
Constructs an empty WPASuite.
Uniquely identifies an analysis summary.
Definition SummaryName.h:22
Represents a translation unit summary in its serialized encoding.
Data extracted for a given translation unit and for a given set of analyses.
Definition TUSummary.h:25
Bundles the EntityIdTable (moved from the LUSummary) and the analysis results produced by one Analysi...
Definition WPASuite.h:37
std::variant< TUSummaryEncoding, LUSummaryEncoding > ArtifactEncoding
Lazily-deserialized counterpart of Artifact: the same on-disk artifacts but with their per-entity sum...
std::variant< TUSummary, LUSummary, WPASuite > Artifact
Sum type returned by SerializationFormat::readArtifact, used when the caller does not know up-front w...
Diagnostic wrappers for TextAPI types for error reporting.
Definition Dominators.h:30
FormatInfoEntry(SummaryName ForSummary, SerializerFn Serialize, DeserializerFn Deserialize)
virtual ~FormatInfoEntry()=default
Add(TypedSerializerFn TypedSerialize, DeserializerFn Deserialize)
Takes the plugin's typed serializer and the deserializer, and inserts them into llvm::Registry<Codec>...