Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
35271 views
1
//===- ExtractAPI/Serialization/SymbolGraphSerializer.cpp -------*- 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
/// \file
10
/// This file implements the SymbolGraphSerializer.
11
///
12
//===----------------------------------------------------------------------===//
13
14
#include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h"
15
#include "clang/Basic/SourceLocation.h"
16
#include "clang/Basic/Version.h"
17
#include "clang/ExtractAPI/API.h"
18
#include "clang/ExtractAPI/DeclarationFragments.h"
19
#include "llvm/ADT/STLExtras.h"
20
#include "llvm/ADT/STLFunctionalExtras.h"
21
#include "llvm/ADT/SmallVector.h"
22
#include "llvm/Support/Casting.h"
23
#include "llvm/Support/Compiler.h"
24
#include "llvm/Support/Path.h"
25
#include "llvm/Support/VersionTuple.h"
26
#include "llvm/Support/raw_ostream.h"
27
#include <iterator>
28
#include <optional>
29
#include <type_traits>
30
31
using namespace clang;
32
using namespace clang::extractapi;
33
using namespace llvm;
34
35
namespace {
36
37
/// Helper function to inject a JSON object \p Obj into another object \p Paren
38
/// at position \p Key.
39
void serializeObject(Object &Paren, StringRef Key,
40
std::optional<Object> &&Obj) {
41
if (Obj)
42
Paren[Key] = std::move(*Obj);
43
}
44
45
/// Helper function to inject a JSON array \p Array into object \p Paren at
46
/// position \p Key.
47
void serializeArray(Object &Paren, StringRef Key,
48
std::optional<Array> &&Array) {
49
if (Array)
50
Paren[Key] = std::move(*Array);
51
}
52
53
/// Helper function to inject a JSON array composed of the values in \p C into
54
/// object \p Paren at position \p Key.
55
template <typename ContainerTy>
56
void serializeArray(Object &Paren, StringRef Key, ContainerTy &&C) {
57
Paren[Key] = Array(C);
58
}
59
60
/// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version
61
/// format.
62
///
63
/// A semantic version object contains three numeric fields, representing the
64
/// \c major, \c minor, and \c patch parts of the version tuple.
65
/// For example version tuple 1.0.3 is serialized as:
66
/// \code
67
/// {
68
/// "major" : 1,
69
/// "minor" : 0,
70
/// "patch" : 3
71
/// }
72
/// \endcode
73
///
74
/// \returns \c std::nullopt if the version \p V is empty, or an \c Object
75
/// containing the semantic version representation of \p V.
76
std::optional<Object> serializeSemanticVersion(const VersionTuple &V) {
77
if (V.empty())
78
return std::nullopt;
79
80
Object Version;
81
Version["major"] = V.getMajor();
82
Version["minor"] = V.getMinor().value_or(0);
83
Version["patch"] = V.getSubminor().value_or(0);
84
return Version;
85
}
86
87
/// Serialize the OS information in the Symbol Graph platform property.
88
///
89
/// The OS information in Symbol Graph contains the \c name of the OS, and an
90
/// optional \c minimumVersion semantic version field.
91
Object serializeOperatingSystem(const Triple &T) {
92
Object OS;
93
OS["name"] = T.getOSTypeName(T.getOS());
94
serializeObject(OS, "minimumVersion",
95
serializeSemanticVersion(T.getMinimumSupportedOSVersion()));
96
return OS;
97
}
98
99
/// Serialize the platform information in the Symbol Graph module section.
100
///
101
/// The platform object describes a target platform triple in corresponding
102
/// three fields: \c architecture, \c vendor, and \c operatingSystem.
103
Object serializePlatform(const Triple &T) {
104
Object Platform;
105
Platform["architecture"] = T.getArchName();
106
Platform["vendor"] = T.getVendorName();
107
Platform["operatingSystem"] = serializeOperatingSystem(T);
108
return Platform;
109
}
110
111
/// Serialize a source position.
112
Object serializeSourcePosition(const PresumedLoc &Loc) {
113
assert(Loc.isValid() && "invalid source position");
114
115
Object SourcePosition;
116
SourcePosition["line"] = Loc.getLine() - 1;
117
SourcePosition["character"] = Loc.getColumn() - 1;
118
119
return SourcePosition;
120
}
121
122
/// Serialize a source location in file.
123
///
124
/// \param Loc The presumed location to serialize.
125
/// \param IncludeFileURI If true, include the file path of \p Loc as a URI.
126
/// Defaults to false.
127
Object serializeSourceLocation(const PresumedLoc &Loc,
128
bool IncludeFileURI = false) {
129
Object SourceLocation;
130
serializeObject(SourceLocation, "position", serializeSourcePosition(Loc));
131
132
if (IncludeFileURI) {
133
std::string FileURI = "file://";
134
// Normalize file path to use forward slashes for the URI.
135
FileURI += sys::path::convert_to_slash(Loc.getFilename());
136
SourceLocation["uri"] = FileURI;
137
}
138
139
return SourceLocation;
140
}
141
142
/// Serialize a source range with begin and end locations.
143
Object serializeSourceRange(const PresumedLoc &BeginLoc,
144
const PresumedLoc &EndLoc) {
145
Object SourceRange;
146
serializeObject(SourceRange, "start", serializeSourcePosition(BeginLoc));
147
serializeObject(SourceRange, "end", serializeSourcePosition(EndLoc));
148
return SourceRange;
149
}
150
151
/// Serialize the availability attributes of a symbol.
152
///
153
/// Availability information contains the introduced, deprecated, and obsoleted
154
/// versions of the symbol as semantic versions, if not default.
155
/// Availability information also contains flags to indicate if the symbol is
156
/// unconditionally unavailable or deprecated,
157
/// i.e. \c __attribute__((unavailable)) and \c __attribute__((deprecated)).
158
///
159
/// \returns \c std::nullopt if the symbol has default availability attributes,
160
/// or an \c Array containing an object with the formatted availability
161
/// information.
162
std::optional<Array> serializeAvailability(const AvailabilityInfo &Avail) {
163
if (Avail.isDefault())
164
return std::nullopt;
165
166
Array AvailabilityArray;
167
168
if (Avail.isUnconditionallyDeprecated()) {
169
Object UnconditionallyDeprecated;
170
UnconditionallyDeprecated["domain"] = "*";
171
UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true;
172
AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated));
173
}
174
Object Availability;
175
176
Availability["domain"] = Avail.Domain;
177
178
if (Avail.isUnavailable()) {
179
Availability["isUnconditionallyUnavailable"] = true;
180
} else {
181
serializeObject(Availability, "introduced",
182
serializeSemanticVersion(Avail.Introduced));
183
serializeObject(Availability, "deprecated",
184
serializeSemanticVersion(Avail.Deprecated));
185
serializeObject(Availability, "obsoleted",
186
serializeSemanticVersion(Avail.Obsoleted));
187
}
188
189
AvailabilityArray.emplace_back(std::move(Availability));
190
return AvailabilityArray;
191
}
192
193
/// Get the language name string for interface language references.
194
StringRef getLanguageName(Language Lang) {
195
switch (Lang) {
196
case Language::C:
197
return "c";
198
case Language::ObjC:
199
return "objective-c";
200
case Language::CXX:
201
return "c++";
202
case Language::ObjCXX:
203
return "objective-c++";
204
205
// Unsupported language currently
206
case Language::OpenCL:
207
case Language::OpenCLCXX:
208
case Language::CUDA:
209
case Language::RenderScript:
210
case Language::HIP:
211
case Language::HLSL:
212
213
// Languages that the frontend cannot parse and compile
214
case Language::Unknown:
215
case Language::Asm:
216
case Language::LLVM_IR:
217
case Language::CIR:
218
llvm_unreachable("Unsupported language kind");
219
}
220
221
llvm_unreachable("Unhandled language kind");
222
}
223
224
/// Serialize the identifier object as specified by the Symbol Graph format.
225
///
226
/// The identifier property of a symbol contains the USR for precise and unique
227
/// references, and the interface language name.
228
Object serializeIdentifier(const APIRecord &Record, Language Lang) {
229
Object Identifier;
230
Identifier["precise"] = Record.USR;
231
Identifier["interfaceLanguage"] = getLanguageName(Lang);
232
233
return Identifier;
234
}
235
236
/// Serialize the documentation comments attached to a symbol, as specified by
237
/// the Symbol Graph format.
238
///
239
/// The Symbol Graph \c docComment object contains an array of lines. Each line
240
/// represents one line of striped documentation comment, with source range
241
/// information.
242
/// e.g.
243
/// \code
244
/// /// This is a documentation comment
245
/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' First line.
246
/// /// with multiple lines.
247
/// ^~~~~~~~~~~~~~~~~~~~~~~' Second line.
248
/// \endcode
249
///
250
/// \returns \c std::nullopt if \p Comment is empty, or an \c Object containing
251
/// the formatted lines.
252
std::optional<Object> serializeDocComment(const DocComment &Comment) {
253
if (Comment.empty())
254
return std::nullopt;
255
256
Object DocComment;
257
258
Array LinesArray;
259
for (const auto &CommentLine : Comment) {
260
Object Line;
261
Line["text"] = CommentLine.Text;
262
serializeObject(Line, "range",
263
serializeSourceRange(CommentLine.Begin, CommentLine.End));
264
LinesArray.emplace_back(std::move(Line));
265
}
266
267
serializeArray(DocComment, "lines", std::move(LinesArray));
268
269
return DocComment;
270
}
271
272
/// Serialize the declaration fragments of a symbol.
273
///
274
/// The Symbol Graph declaration fragments is an array of tagged important
275
/// parts of a symbol's declaration. The fragments sequence can be joined to
276
/// form spans of declaration text, with attached information useful for
277
/// purposes like syntax-highlighting etc. For example:
278
/// \code
279
/// const int pi; -> "declarationFragments" : [
280
/// {
281
/// "kind" : "keyword",
282
/// "spelling" : "const"
283
/// },
284
/// {
285
/// "kind" : "text",
286
/// "spelling" : " "
287
/// },
288
/// {
289
/// "kind" : "typeIdentifier",
290
/// "preciseIdentifier" : "c:I",
291
/// "spelling" : "int"
292
/// },
293
/// {
294
/// "kind" : "text",
295
/// "spelling" : " "
296
/// },
297
/// {
298
/// "kind" : "identifier",
299
/// "spelling" : "pi"
300
/// }
301
/// ]
302
/// \endcode
303
///
304
/// \returns \c std::nullopt if \p DF is empty, or an \c Array containing the
305
/// formatted declaration fragments array.
306
std::optional<Array>
307
serializeDeclarationFragments(const DeclarationFragments &DF) {
308
if (DF.getFragments().empty())
309
return std::nullopt;
310
311
Array Fragments;
312
for (const auto &F : DF.getFragments()) {
313
Object Fragment;
314
Fragment["spelling"] = F.Spelling;
315
Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind);
316
if (!F.PreciseIdentifier.empty())
317
Fragment["preciseIdentifier"] = F.PreciseIdentifier;
318
Fragments.emplace_back(std::move(Fragment));
319
}
320
321
return Fragments;
322
}
323
324
/// Serialize the \c names field of a symbol as specified by the Symbol Graph
325
/// format.
326
///
327
/// The Symbol Graph names field contains multiple representations of a symbol
328
/// that can be used for different applications:
329
/// - \c title : The simple declared name of the symbol;
330
/// - \c subHeading : An array of declaration fragments that provides tags,
331
/// and potentially more tokens (for example the \c +/- symbol for
332
/// Objective-C methods). Can be used as sub-headings for documentation.
333
Object serializeNames(const APIRecord *Record) {
334
Object Names;
335
Names["title"] = Record->Name;
336
337
serializeArray(Names, "subHeading",
338
serializeDeclarationFragments(Record->SubHeading));
339
DeclarationFragments NavigatorFragments;
340
NavigatorFragments.append(Record->Name,
341
DeclarationFragments::FragmentKind::Identifier,
342
/*PreciseIdentifier*/ "");
343
serializeArray(Names, "navigator",
344
serializeDeclarationFragments(NavigatorFragments));
345
346
return Names;
347
}
348
349
Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {
350
auto AddLangPrefix = [&Lang](StringRef S) -> std::string {
351
return (getLanguageName(Lang) + "." + S).str();
352
};
353
354
Object Kind;
355
switch (RK) {
356
case APIRecord::RK_Unknown:
357
Kind["identifier"] = AddLangPrefix("unknown");
358
Kind["displayName"] = "Unknown";
359
break;
360
case APIRecord::RK_Namespace:
361
Kind["identifier"] = AddLangPrefix("namespace");
362
Kind["displayName"] = "Namespace";
363
break;
364
case APIRecord::RK_GlobalFunction:
365
Kind["identifier"] = AddLangPrefix("func");
366
Kind["displayName"] = "Function";
367
break;
368
case APIRecord::RK_GlobalFunctionTemplate:
369
Kind["identifier"] = AddLangPrefix("func");
370
Kind["displayName"] = "Function Template";
371
break;
372
case APIRecord::RK_GlobalFunctionTemplateSpecialization:
373
Kind["identifier"] = AddLangPrefix("func");
374
Kind["displayName"] = "Function Template Specialization";
375
break;
376
case APIRecord::RK_GlobalVariableTemplate:
377
Kind["identifier"] = AddLangPrefix("var");
378
Kind["displayName"] = "Global Variable Template";
379
break;
380
case APIRecord::RK_GlobalVariableTemplateSpecialization:
381
Kind["identifier"] = AddLangPrefix("var");
382
Kind["displayName"] = "Global Variable Template Specialization";
383
break;
384
case APIRecord::RK_GlobalVariableTemplatePartialSpecialization:
385
Kind["identifier"] = AddLangPrefix("var");
386
Kind["displayName"] = "Global Variable Template Partial Specialization";
387
break;
388
case APIRecord::RK_GlobalVariable:
389
Kind["identifier"] = AddLangPrefix("var");
390
Kind["displayName"] = "Global Variable";
391
break;
392
case APIRecord::RK_EnumConstant:
393
Kind["identifier"] = AddLangPrefix("enum.case");
394
Kind["displayName"] = "Enumeration Case";
395
break;
396
case APIRecord::RK_Enum:
397
Kind["identifier"] = AddLangPrefix("enum");
398
Kind["displayName"] = "Enumeration";
399
break;
400
case APIRecord::RK_StructField:
401
Kind["identifier"] = AddLangPrefix("property");
402
Kind["displayName"] = "Instance Property";
403
break;
404
case APIRecord::RK_Struct:
405
Kind["identifier"] = AddLangPrefix("struct");
406
Kind["displayName"] = "Structure";
407
break;
408
case APIRecord::RK_UnionField:
409
Kind["identifier"] = AddLangPrefix("property");
410
Kind["displayName"] = "Instance Property";
411
break;
412
case APIRecord::RK_Union:
413
Kind["identifier"] = AddLangPrefix("union");
414
Kind["displayName"] = "Union";
415
break;
416
case APIRecord::RK_CXXField:
417
Kind["identifier"] = AddLangPrefix("property");
418
Kind["displayName"] = "Instance Property";
419
break;
420
case APIRecord::RK_StaticField:
421
Kind["identifier"] = AddLangPrefix("type.property");
422
Kind["displayName"] = "Type Property";
423
break;
424
case APIRecord::RK_ClassTemplate:
425
case APIRecord::RK_ClassTemplateSpecialization:
426
case APIRecord::RK_ClassTemplatePartialSpecialization:
427
case APIRecord::RK_CXXClass:
428
Kind["identifier"] = AddLangPrefix("class");
429
Kind["displayName"] = "Class";
430
break;
431
case APIRecord::RK_CXXMethodTemplate:
432
Kind["identifier"] = AddLangPrefix("method");
433
Kind["displayName"] = "Method Template";
434
break;
435
case APIRecord::RK_CXXMethodTemplateSpecialization:
436
Kind["identifier"] = AddLangPrefix("method");
437
Kind["displayName"] = "Method Template Specialization";
438
break;
439
case APIRecord::RK_CXXFieldTemplate:
440
Kind["identifier"] = AddLangPrefix("property");
441
Kind["displayName"] = "Template Property";
442
break;
443
case APIRecord::RK_Concept:
444
Kind["identifier"] = AddLangPrefix("concept");
445
Kind["displayName"] = "Concept";
446
break;
447
case APIRecord::RK_CXXStaticMethod:
448
Kind["identifier"] = AddLangPrefix("type.method");
449
Kind["displayName"] = "Static Method";
450
break;
451
case APIRecord::RK_CXXInstanceMethod:
452
Kind["identifier"] = AddLangPrefix("method");
453
Kind["displayName"] = "Instance Method";
454
break;
455
case APIRecord::RK_CXXConstructorMethod:
456
Kind["identifier"] = AddLangPrefix("method");
457
Kind["displayName"] = "Constructor";
458
break;
459
case APIRecord::RK_CXXDestructorMethod:
460
Kind["identifier"] = AddLangPrefix("method");
461
Kind["displayName"] = "Destructor";
462
break;
463
case APIRecord::RK_ObjCIvar:
464
Kind["identifier"] = AddLangPrefix("ivar");
465
Kind["displayName"] = "Instance Variable";
466
break;
467
case APIRecord::RK_ObjCInstanceMethod:
468
Kind["identifier"] = AddLangPrefix("method");
469
Kind["displayName"] = "Instance Method";
470
break;
471
case APIRecord::RK_ObjCClassMethod:
472
Kind["identifier"] = AddLangPrefix("type.method");
473
Kind["displayName"] = "Type Method";
474
break;
475
case APIRecord::RK_ObjCInstanceProperty:
476
Kind["identifier"] = AddLangPrefix("property");
477
Kind["displayName"] = "Instance Property";
478
break;
479
case APIRecord::RK_ObjCClassProperty:
480
Kind["identifier"] = AddLangPrefix("type.property");
481
Kind["displayName"] = "Type Property";
482
break;
483
case APIRecord::RK_ObjCInterface:
484
Kind["identifier"] = AddLangPrefix("class");
485
Kind["displayName"] = "Class";
486
break;
487
case APIRecord::RK_ObjCCategory:
488
Kind["identifier"] = AddLangPrefix("class.extension");
489
Kind["displayName"] = "Class Extension";
490
break;
491
case APIRecord::RK_ObjCProtocol:
492
Kind["identifier"] = AddLangPrefix("protocol");
493
Kind["displayName"] = "Protocol";
494
break;
495
case APIRecord::RK_MacroDefinition:
496
Kind["identifier"] = AddLangPrefix("macro");
497
Kind["displayName"] = "Macro";
498
break;
499
case APIRecord::RK_Typedef:
500
Kind["identifier"] = AddLangPrefix("typealias");
501
Kind["displayName"] = "Type Alias";
502
break;
503
default:
504
llvm_unreachable("API Record with uninstantiable kind");
505
}
506
507
return Kind;
508
}
509
510
/// Serialize the symbol kind information.
511
///
512
/// The Symbol Graph symbol kind property contains a shorthand \c identifier
513
/// which is prefixed by the source language name, useful for tooling to parse
514
/// the kind, and a \c displayName for rendering human-readable names.
515
Object serializeSymbolKind(const APIRecord &Record, Language Lang) {
516
return serializeSymbolKind(Record.KindForDisplay, Lang);
517
}
518
519
/// Serialize the function signature field, as specified by the
520
/// Symbol Graph format.
521
///
522
/// The Symbol Graph function signature property contains two arrays.
523
/// - The \c returns array is the declaration fragments of the return type;
524
/// - The \c parameters array contains names and declaration fragments of the
525
/// parameters.
526
template <typename RecordTy>
527
void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) {
528
const auto &FS = Record.Signature;
529
if (FS.empty())
530
return;
531
532
Object Signature;
533
serializeArray(Signature, "returns",
534
serializeDeclarationFragments(FS.getReturnType()));
535
536
Array Parameters;
537
for (const auto &P : FS.getParameters()) {
538
Object Parameter;
539
Parameter["name"] = P.Name;
540
serializeArray(Parameter, "declarationFragments",
541
serializeDeclarationFragments(P.Fragments));
542
Parameters.emplace_back(std::move(Parameter));
543
}
544
545
if (!Parameters.empty())
546
Signature["parameters"] = std::move(Parameters);
547
548
serializeObject(Paren, "functionSignature", std::move(Signature));
549
}
550
551
template <typename RecordTy>
552
void serializeTemplateMixin(Object &Paren, const RecordTy &Record) {
553
const auto &Template = Record.Templ;
554
if (Template.empty())
555
return;
556
557
Object Generics;
558
Array GenericParameters;
559
for (const auto &Param : Template.getParameters()) {
560
Object Parameter;
561
Parameter["name"] = Param.Name;
562
Parameter["index"] = Param.Index;
563
Parameter["depth"] = Param.Depth;
564
GenericParameters.emplace_back(std::move(Parameter));
565
}
566
if (!GenericParameters.empty())
567
Generics["parameters"] = std::move(GenericParameters);
568
569
Array GenericConstraints;
570
for (const auto &Constr : Template.getConstraints()) {
571
Object Constraint;
572
Constraint["kind"] = Constr.Kind;
573
Constraint["lhs"] = Constr.LHS;
574
Constraint["rhs"] = Constr.RHS;
575
GenericConstraints.emplace_back(std::move(Constraint));
576
}
577
578
if (!GenericConstraints.empty())
579
Generics["constraints"] = std::move(GenericConstraints);
580
581
serializeObject(Paren, "swiftGenerics", Generics);
582
}
583
584
Array generateParentContexts(const SmallVectorImpl<SymbolReference> &Parents,
585
Language Lang) {
586
Array ParentContexts;
587
588
for (const auto &Parent : Parents) {
589
Object Elem;
590
Elem["usr"] = Parent.USR;
591
Elem["name"] = Parent.Name;
592
if (Parent.Record)
593
Elem["kind"] = serializeSymbolKind(Parent.Record->KindForDisplay,
594
Lang)["identifier"];
595
else
596
Elem["kind"] =
597
serializeSymbolKind(APIRecord::RK_Unknown, Lang)["identifier"];
598
ParentContexts.emplace_back(std::move(Elem));
599
}
600
601
return ParentContexts;
602
}
603
604
/// Walk the records parent information in reverse to generate a hierarchy
605
/// suitable for serialization.
606
SmallVector<SymbolReference, 8>
607
generateHierarchyFromRecord(const APIRecord *Record) {
608
SmallVector<SymbolReference, 8> ReverseHierarchy;
609
for (const auto *Current = Record; Current != nullptr;
610
Current = Current->Parent.Record)
611
ReverseHierarchy.emplace_back(Current);
612
613
return SmallVector<SymbolReference, 8>(
614
std::make_move_iterator(ReverseHierarchy.rbegin()),
615
std::make_move_iterator(ReverseHierarchy.rend()));
616
}
617
618
SymbolReference getHierarchyReference(const APIRecord *Record,
619
const APISet &API) {
620
// If the parent is a category extended from internal module then we need to
621
// pretend this belongs to the associated interface.
622
if (auto *CategoryRecord = dyn_cast_or_null<ObjCCategoryRecord>(Record)) {
623
return CategoryRecord->Interface;
624
// FIXME: TODO generate path components correctly for categories extending
625
// an external module.
626
}
627
628
return SymbolReference(Record);
629
}
630
631
} // namespace
632
633
Object *ExtendedModule::addSymbol(Object &&Symbol) {
634
Symbols.emplace_back(std::move(Symbol));
635
return Symbols.back().getAsObject();
636
}
637
638
void ExtendedModule::addRelationship(Object &&Relationship) {
639
Relationships.emplace_back(std::move(Relationship));
640
}
641
642
/// Defines the format version emitted by SymbolGraphSerializer.
643
const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3};
644
645
Object SymbolGraphSerializer::serializeMetadata() const {
646
Object Metadata;
647
serializeObject(Metadata, "formatVersion",
648
serializeSemanticVersion(FormatVersion));
649
Metadata["generator"] = clang::getClangFullVersion();
650
return Metadata;
651
}
652
653
Object
654
SymbolGraphSerializer::serializeModuleObject(StringRef ModuleName) const {
655
Object Module;
656
Module["name"] = ModuleName;
657
serializeObject(Module, "platform", serializePlatform(API.getTarget()));
658
return Module;
659
}
660
661
bool SymbolGraphSerializer::shouldSkip(const APIRecord *Record) const {
662
if (!Record)
663
return true;
664
665
// Skip unconditionally unavailable symbols
666
if (Record->Availability.isUnconditionallyUnavailable())
667
return true;
668
669
// Filter out symbols without a name as we can generate correct symbol graphs
670
// for them. In practice these are anonymous record types that aren't attached
671
// to a declaration.
672
if (auto *Tag = dyn_cast<TagRecord>(Record)) {
673
if (Tag->IsEmbeddedInVarDeclarator)
674
return true;
675
}
676
677
// Filter out symbols prefixed with an underscored as they are understood to
678
// be symbols clients should not use.
679
if (Record->Name.starts_with("_"))
680
return true;
681
682
// Skip explicitly ignored symbols.
683
if (IgnoresList.shouldIgnore(Record->Name))
684
return true;
685
686
return false;
687
}
688
689
ExtendedModule &SymbolGraphSerializer::getModuleForCurrentSymbol() {
690
if (!ForceEmitToMainModule && ModuleForCurrentSymbol)
691
return *ModuleForCurrentSymbol;
692
693
return MainModule;
694
}
695
696
Array SymbolGraphSerializer::serializePathComponents(
697
const APIRecord *Record) const {
698
return Array(map_range(Hierarchy, [](auto Elt) { return Elt.Name; }));
699
}
700
701
StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) {
702
switch (Kind) {
703
case RelationshipKind::MemberOf:
704
return "memberOf";
705
case RelationshipKind::InheritsFrom:
706
return "inheritsFrom";
707
case RelationshipKind::ConformsTo:
708
return "conformsTo";
709
case RelationshipKind::ExtensionTo:
710
return "extensionTo";
711
}
712
llvm_unreachable("Unhandled relationship kind");
713
}
714
715
void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,
716
const SymbolReference &Source,
717
const SymbolReference &Target,
718
ExtendedModule &Into) {
719
Object Relationship;
720
SmallString<64> TestRelLabel;
721
if (EmitSymbolLabelsForTesting) {
722
llvm::raw_svector_ostream OS(TestRelLabel);
723
OS << SymbolGraphSerializer::getRelationshipString(Kind) << " $ "
724
<< Source.USR << " $ ";
725
if (Target.USR.empty())
726
OS << Target.Name;
727
else
728
OS << Target.USR;
729
Relationship["!testRelLabel"] = TestRelLabel;
730
}
731
Relationship["source"] = Source.USR;
732
Relationship["target"] = Target.USR;
733
Relationship["targetFallback"] = Target.Name;
734
Relationship["kind"] = SymbolGraphSerializer::getRelationshipString(Kind);
735
736
if (ForceEmitToMainModule)
737
MainModule.addRelationship(std::move(Relationship));
738
else
739
Into.addRelationship(std::move(Relationship));
740
}
741
742
StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) {
743
switch (Kind) {
744
case ConstraintKind::Conformance:
745
return "conformance";
746
case ConstraintKind::ConditionalConformance:
747
return "conditionalConformance";
748
}
749
llvm_unreachable("Unhandled constraint kind");
750
}
751
752
void SymbolGraphSerializer::serializeAPIRecord(const APIRecord *Record) {
753
Object Obj;
754
755
// If we need symbol labels for testing emit the USR as the value and the key
756
// starts with '!'' to ensure it ends up at the top of the object.
757
if (EmitSymbolLabelsForTesting)
758
Obj["!testLabel"] = Record->USR;
759
760
serializeObject(Obj, "identifier",
761
serializeIdentifier(*Record, API.getLanguage()));
762
serializeObject(Obj, "kind", serializeSymbolKind(*Record, API.getLanguage()));
763
serializeObject(Obj, "names", serializeNames(Record));
764
serializeObject(
765
Obj, "location",
766
serializeSourceLocation(Record->Location, /*IncludeFileURI=*/true));
767
serializeArray(Obj, "availability",
768
serializeAvailability(Record->Availability));
769
serializeObject(Obj, "docComment", serializeDocComment(Record->Comment));
770
serializeArray(Obj, "declarationFragments",
771
serializeDeclarationFragments(Record->Declaration));
772
773
Obj["pathComponents"] = serializePathComponents(Record);
774
Obj["accessLevel"] = Record->Access.getAccess();
775
776
ExtendedModule &Module = getModuleForCurrentSymbol();
777
// If the hierarchy has at least one parent and child.
778
if (Hierarchy.size() >= 2)
779
serializeRelationship(MemberOf, Hierarchy.back(),
780
Hierarchy[Hierarchy.size() - 2], Module);
781
782
CurrentSymbol = Module.addSymbol(std::move(Obj));
783
}
784
785
bool SymbolGraphSerializer::traverseAPIRecord(const APIRecord *Record) {
786
if (!Record)
787
return true;
788
if (shouldSkip(Record))
789
return true;
790
Hierarchy.push_back(getHierarchyReference(Record, API));
791
// Defer traversal mechanics to APISetVisitor base implementation
792
auto RetVal = Base::traverseAPIRecord(Record);
793
Hierarchy.pop_back();
794
return RetVal;
795
}
796
797
bool SymbolGraphSerializer::visitAPIRecord(const APIRecord *Record) {
798
serializeAPIRecord(Record);
799
return true;
800
}
801
802
bool SymbolGraphSerializer::visitGlobalFunctionRecord(
803
const GlobalFunctionRecord *Record) {
804
if (!CurrentSymbol)
805
return true;
806
807
serializeFunctionSignatureMixin(*CurrentSymbol, *Record);
808
return true;
809
}
810
811
bool SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord *Record) {
812
if (!CurrentSymbol)
813
return true;
814
815
for (const auto &Base : Record->Bases)
816
serializeRelationship(RelationshipKind::InheritsFrom, Record, Base,
817
getModuleForCurrentSymbol());
818
return true;
819
}
820
821
bool SymbolGraphSerializer::visitClassTemplateRecord(
822
const ClassTemplateRecord *Record) {
823
if (!CurrentSymbol)
824
return true;
825
826
serializeTemplateMixin(*CurrentSymbol, *Record);
827
return true;
828
}
829
830
bool SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord(
831
const ClassTemplatePartialSpecializationRecord *Record) {
832
if (!CurrentSymbol)
833
return true;
834
835
serializeTemplateMixin(*CurrentSymbol, *Record);
836
return true;
837
}
838
839
bool SymbolGraphSerializer::visitCXXMethodRecord(
840
const CXXMethodRecord *Record) {
841
if (!CurrentSymbol)
842
return true;
843
844
serializeFunctionSignatureMixin(*CurrentSymbol, *Record);
845
return true;
846
}
847
848
bool SymbolGraphSerializer::visitCXXMethodTemplateRecord(
849
const CXXMethodTemplateRecord *Record) {
850
if (!CurrentSymbol)
851
return true;
852
853
serializeTemplateMixin(*CurrentSymbol, *Record);
854
return true;
855
}
856
857
bool SymbolGraphSerializer::visitCXXFieldTemplateRecord(
858
const CXXFieldTemplateRecord *Record) {
859
if (!CurrentSymbol)
860
return true;
861
862
serializeTemplateMixin(*CurrentSymbol, *Record);
863
return true;
864
}
865
866
bool SymbolGraphSerializer::visitConceptRecord(const ConceptRecord *Record) {
867
if (!CurrentSymbol)
868
return true;
869
870
serializeTemplateMixin(*CurrentSymbol, *Record);
871
return true;
872
}
873
874
bool SymbolGraphSerializer::visitGlobalVariableTemplateRecord(
875
const GlobalVariableTemplateRecord *Record) {
876
if (!CurrentSymbol)
877
return true;
878
879
serializeTemplateMixin(*CurrentSymbol, *Record);
880
return true;
881
}
882
883
bool SymbolGraphSerializer::
884
visitGlobalVariableTemplatePartialSpecializationRecord(
885
const GlobalVariableTemplatePartialSpecializationRecord *Record) {
886
if (!CurrentSymbol)
887
return true;
888
889
serializeTemplateMixin(*CurrentSymbol, *Record);
890
return true;
891
}
892
893
bool SymbolGraphSerializer::visitGlobalFunctionTemplateRecord(
894
const GlobalFunctionTemplateRecord *Record) {
895
if (!CurrentSymbol)
896
return true;
897
898
serializeTemplateMixin(*CurrentSymbol, *Record);
899
return true;
900
}
901
902
bool SymbolGraphSerializer::visitObjCContainerRecord(
903
const ObjCContainerRecord *Record) {
904
if (!CurrentSymbol)
905
return true;
906
907
for (const auto &Protocol : Record->Protocols)
908
serializeRelationship(ConformsTo, Record, Protocol,
909
getModuleForCurrentSymbol());
910
911
return true;
912
}
913
914
bool SymbolGraphSerializer::visitObjCInterfaceRecord(
915
const ObjCInterfaceRecord *Record) {
916
if (!CurrentSymbol)
917
return true;
918
919
if (!Record->SuperClass.empty())
920
serializeRelationship(InheritsFrom, Record, Record->SuperClass,
921
getModuleForCurrentSymbol());
922
return true;
923
}
924
925
bool SymbolGraphSerializer::traverseObjCCategoryRecord(
926
const ObjCCategoryRecord *Record) {
927
if (SkipSymbolsInCategoriesToExternalTypes &&
928
!API.findRecordForUSR(Record->Interface.USR))
929
return true;
930
931
auto *CurrentModule = ModuleForCurrentSymbol;
932
if (Record->isExtendingExternalModule())
933
ModuleForCurrentSymbol = &ExtendedModules[Record->Interface.Source];
934
935
if (!walkUpFromObjCCategoryRecord(Record))
936
return false;
937
938
bool RetVal = traverseRecordContext(Record);
939
ModuleForCurrentSymbol = CurrentModule;
940
return RetVal;
941
}
942
943
bool SymbolGraphSerializer::walkUpFromObjCCategoryRecord(
944
const ObjCCategoryRecord *Record) {
945
return visitObjCCategoryRecord(Record);
946
}
947
948
bool SymbolGraphSerializer::visitObjCCategoryRecord(
949
const ObjCCategoryRecord *Record) {
950
// If we need to create a record for the category in the future do so here,
951
// otherwise everything is set up to pretend that the category is in fact the
952
// interface it extends.
953
for (const auto &Protocol : Record->Protocols)
954
serializeRelationship(ConformsTo, Record->Interface, Protocol,
955
getModuleForCurrentSymbol());
956
957
return true;
958
}
959
960
bool SymbolGraphSerializer::visitObjCMethodRecord(
961
const ObjCMethodRecord *Record) {
962
if (!CurrentSymbol)
963
return true;
964
965
serializeFunctionSignatureMixin(*CurrentSymbol, *Record);
966
return true;
967
}
968
969
bool SymbolGraphSerializer::visitObjCInstanceVariableRecord(
970
const ObjCInstanceVariableRecord *Record) {
971
// FIXME: serialize ivar access control here.
972
return true;
973
}
974
975
bool SymbolGraphSerializer::walkUpFromTypedefRecord(
976
const TypedefRecord *Record) {
977
// Short-circuit walking up the class hierarchy and handle creating typedef
978
// symbol objects manually as there are additional symbol dropping rules to
979
// respect.
980
return visitTypedefRecord(Record);
981
}
982
983
bool SymbolGraphSerializer::visitTypedefRecord(const TypedefRecord *Record) {
984
// Typedefs of anonymous types have their entries unified with the underlying
985
// type.
986
bool ShouldDrop = Record->UnderlyingType.Name.empty();
987
// enums declared with `NS_OPTION` have a named enum and a named typedef, with
988
// the same name
989
ShouldDrop |= (Record->UnderlyingType.Name == Record->Name);
990
if (ShouldDrop)
991
return true;
992
993
// Create the symbol record if the other symbol droppping rules permit it.
994
serializeAPIRecord(Record);
995
if (!CurrentSymbol)
996
return true;
997
998
(*CurrentSymbol)["type"] = Record->UnderlyingType.USR;
999
1000
return true;
1001
}
1002
1003
void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) {
1004
switch (Record->getKind()) {
1005
// dispatch to the relevant walkUpFromMethod
1006
#define CONCRETE_RECORD(CLASS, BASE, KIND) \
1007
case APIRecord::KIND: { \
1008
walkUpFrom##CLASS(static_cast<const CLASS *>(Record)); \
1009
break; \
1010
}
1011
#include "clang/ExtractAPI/APIRecords.inc"
1012
// otherwise fallback on the only behavior we can implement safely.
1013
case APIRecord::RK_Unknown:
1014
visitAPIRecord(Record);
1015
break;
1016
default:
1017
llvm_unreachable("API Record with uninstantiable kind");
1018
}
1019
}
1020
1021
Object SymbolGraphSerializer::serializeGraph(StringRef ModuleName,
1022
ExtendedModule &&EM) {
1023
Object Root;
1024
serializeObject(Root, "metadata", serializeMetadata());
1025
serializeObject(Root, "module", serializeModuleObject(ModuleName));
1026
1027
Root["symbols"] = std::move(EM.Symbols);
1028
Root["relationships"] = std::move(EM.Relationships);
1029
1030
return Root;
1031
}
1032
1033
void SymbolGraphSerializer::serializeGraphToStream(
1034
raw_ostream &OS, SymbolGraphSerializerOption Options, StringRef ModuleName,
1035
ExtendedModule &&EM) {
1036
Object Root = serializeGraph(ModuleName, std::move(EM));
1037
if (Options.Compact)
1038
OS << formatv("{0}", json::Value(std::move(Root))) << "\n";
1039
else
1040
OS << formatv("{0:2}", json::Value(std::move(Root))) << "\n";
1041
}
1042
1043
void SymbolGraphSerializer::serializeMainSymbolGraph(
1044
raw_ostream &OS, const APISet &API, const APIIgnoresList &IgnoresList,
1045
SymbolGraphSerializerOption Options) {
1046
SymbolGraphSerializer Serializer(
1047
API, IgnoresList, Options.EmitSymbolLabelsForTesting,
1048
/*ForceEmitToMainModule=*/true,
1049
/*SkipSymbolsInCategoriesToExternalTypes=*/true);
1050
1051
Serializer.traverseAPISet();
1052
Serializer.serializeGraphToStream(OS, Options, API.ProductName,
1053
std::move(Serializer.MainModule));
1054
// FIXME: TODO handle extended modules here
1055
}
1056
1057
void SymbolGraphSerializer::serializeWithExtensionGraphs(
1058
raw_ostream &MainOutput, const APISet &API,
1059
const APIIgnoresList &IgnoresList,
1060
llvm::function_ref<std::unique_ptr<llvm::raw_pwrite_stream>(Twine BaseName)>
1061
CreateOutputStream,
1062
SymbolGraphSerializerOption Options) {
1063
SymbolGraphSerializer Serializer(API, IgnoresList,
1064
Options.EmitSymbolLabelsForTesting);
1065
Serializer.traverseAPISet();
1066
1067
Serializer.serializeGraphToStream(MainOutput, Options, API.ProductName,
1068
std::move(Serializer.MainModule));
1069
1070
for (auto &ExtensionSGF : Serializer.ExtendedModules) {
1071
if (auto ExtensionOS =
1072
CreateOutputStream(ExtensionSGF.getKey() + "@" + API.ProductName))
1073
Serializer.serializeGraphToStream(*ExtensionOS, Options,
1074
ExtensionSGF.getKey(),
1075
std::move(ExtensionSGF.getValue()));
1076
}
1077
}
1078
1079
std::optional<Object>
1080
SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR,
1081
const APISet &API) {
1082
APIRecord *Record = API.findRecordForUSR(USR);
1083
if (!Record)
1084
return {};
1085
1086
Object Root;
1087
APIIgnoresList EmptyIgnores;
1088
SymbolGraphSerializer Serializer(API, EmptyIgnores,
1089
/*EmitSymbolLabelsForTesting*/ false,
1090
/*ForceEmitToMainModule*/ true);
1091
1092
// Set up serializer parent chain
1093
Serializer.Hierarchy = generateHierarchyFromRecord(Record);
1094
1095
Serializer.serializeSingleRecord(Record);
1096
serializeObject(Root, "symbolGraph",
1097
Serializer.serializeGraph(API.ProductName,
1098
std::move(Serializer.MainModule)));
1099
1100
Language Lang = API.getLanguage();
1101
serializeArray(Root, "parentContexts",
1102
generateParentContexts(Serializer.Hierarchy, Lang));
1103
1104
Array RelatedSymbols;
1105
1106
for (const auto &Fragment : Record->Declaration.getFragments()) {
1107
// If we don't have a USR there isn't much we can do.
1108
if (Fragment.PreciseIdentifier.empty())
1109
continue;
1110
1111
APIRecord *RelatedRecord = API.findRecordForUSR(Fragment.PreciseIdentifier);
1112
1113
// If we can't find the record let's skip.
1114
if (!RelatedRecord)
1115
continue;
1116
1117
Object RelatedSymbol;
1118
RelatedSymbol["usr"] = RelatedRecord->USR;
1119
RelatedSymbol["declarationLanguage"] = getLanguageName(Lang);
1120
RelatedSymbol["accessLevel"] = RelatedRecord->Access.getAccess();
1121
RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename();
1122
RelatedSymbol["moduleName"] = API.ProductName;
1123
RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader;
1124
1125
serializeArray(RelatedSymbol, "parentContexts",
1126
generateParentContexts(
1127
generateHierarchyFromRecord(RelatedRecord), Lang));
1128
1129
RelatedSymbols.push_back(std::move(RelatedSymbol));
1130
}
1131
1132
serializeArray(Root, "relatedSymbols", RelatedSymbols);
1133
return Root;
1134
}
1135
1136