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