2#include "clang/Basic/Specifiers.h"
3#include "llvm/Support/JSON.h"
6using namespace llvm::json;
16 llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
18 std::string DirName)
override;
32template <
typename Container,
typename SerializationFunc>
34 const std::string &Key,
35 SerializationFunc SerializeInfo);
73 llvm_unreachable(
"Unknown InfoType encountered.");
79 Object LocationObj = Object();
81 LocationObj[
"Filename"] = Loc.
Filename;
86 sys::path::append(FileURL, sys::path::Style::posix, Loc.
Filename);
88 LocationObj[
"FileURL"] = FileURL;
100 if (
auto *Obj = Comment.getAsObject()) {
101 if (
auto *Children = Obj->getArray(
"Children");
102 Children && Children->empty())
106 else if (
auto *Array = Comment.getAsArray(); Array && Array->empty()) {
110 auto DescriptionIt = Description.find(Key);
112 if (DescriptionIt == Description.end()) {
113 auto CommentsArray = json::Array();
114 CommentsArray.push_back(Comment);
115 Description[Key] = std::move(CommentsArray);
116 Description[
"Has" + Key.str()] =
true;
118 DescriptionIt->getSecond().getAsArray()->push_back(Comment);
126 if (!ParagraphComment)
127 return json::Value(
nullptr);
128 json::Value *Children = ParagraphComment->get(
"Children");
130 return json::Value(
nullptr);
131 auto ChildrenArray = *Children->getAsArray();
132 auto ChildrenIt = ChildrenArray.begin();
133 while (ChildrenIt != ChildrenArray.end()) {
134 auto *ChildObj = ChildrenIt->getAsObject();
135 assert(ChildObj &&
"Invalid JSON object in Comment");
136 auto TextComment = ChildObj->getString(
"TextComment");
137 if (!TextComment || TextComment->empty()) {
138 ChildrenIt = ChildrenArray.erase(ChildrenIt);
143 return ChildrenArray;
147 json::Value TextArray = json::Array();
148 auto &TextArrayRef = *TextArray.getAsArray();
149 for (
auto &Line : VerbatimLines)
150 TextArrayRef.push_back(*Line.getAsObject()
151 ->get(
"VerbatimBlockLineComment")
160 Object Obj = Object();
162 json::Value ChildVal = Object();
163 Object &Child = *ChildVal.getAsObject();
165 json::Value ChildArr = Array();
166 auto &CARef = *ChildArr.getAsArray();
180 if (I.
Name ==
"brief")
181 insertComment(Description, TextCommentsArray,
"BriefComments");
182 else if (I.
Name ==
"return")
183 insertComment(Description, TextCommentsArray,
"ReturnComments");
184 else if (I.
Name ==
"throws" || I.
Name ==
"throw") {
185 json::Value ThrowsVal = Object();
186 auto &ThrowsObj = *ThrowsVal.getAsObject();
187 ThrowsObj[
"Exception"] = I.
Args.front();
188 ThrowsObj[
"Children"] = TextCommentsArray;
195 json::Value ArgsArr = Array();
196 auto &ARef = *ArgsArr.getAsArray();
197 ARef.reserve(I.
Args.size());
198 for (
const auto &Arg : I.
Args)
199 ARef.emplace_back(Arg);
200 Child.insert({
"Command", I.
Name});
201 Child.insert({
"Args", ArgsArr});
202 Child.insert({
"Children", ChildArr});
209 Child.insert({
"ParamName", I.
ParamName});
210 Child.insert({
"Direction", I.
Direction});
211 Child.insert({
"Explicit", I.
Explicit});
213 Child.insert({
"Children", TextCommentsArray});
225 insertComment(Description, TextCommentsArray,
"CodeComments");
233 Child.insert({
"Text", I.
Text});
234 Child.insert({
"Children", ChildArr});
240 json::Value AttrKeysArray = json::Array();
241 json::Value AttrValuesArray = json::Array();
242 auto &KeyArr = *AttrKeysArray.getAsArray();
243 auto &ValArr = *AttrValuesArray.getAsArray();
247 KeyArr.emplace_back(K);
249 ValArr.emplace_back(V);
250 Child.insert({
"Name", I.
Name});
252 Child.insert({
"AttrKeys", AttrKeysArray});
253 Child.insert({
"AttrValues", AttrValuesArray});
254 Child.insert({
"Children", ChildArr});
260 Child.insert({
"Name", I.
Name});
261 Child.insert({
"Children", ChildArr});
268 Child.insert({
"Children", ChildArr});
269 Child[
"ParagraphComment"] =
true;
278 llvm_unreachable(
"Unknown comment kind encountered.");
283 json::Value ContextArray = json::Array();
284 auto &ContextArrayRef = *ContextArray.getAsArray();
285 ContextArrayRef.reserve(I.
Contexts.size());
287 std::string CurrentRelativePath;
288 bool PreviousRecord =
false;
289 for (
const auto &Current : I.
Contexts) {
290 json::Value ContextVal = Object();
291 Object &
Context = *ContextVal.getAsObject();
295 if (Current.DocumentationFileName ==
"index") {
298 PreviousRecord =
false;
299 Context[
"RelativePath"] =
"./";
303 PreviousRecord =
true;
304 CurrentRelativePath +=
"../";
305 Context[
"RelativePath"] = CurrentRelativePath;
307 ContextArrayRef.push_back(ContextVal);
311 if (PreviousRecord && (Current.DocumentationFileName ==
"index")) {
314 PreviousRecord =
false;
315 }
else if (Current.DocumentationFileName !=
"index") {
318 PreviousRecord =
true;
319 CurrentRelativePath +=
"../";
322 PreviousRecord =
false;
323 CurrentRelativePath +=
"../";
326 if (Current.QualName ==
"GlobalNamespace" && Current.RelativePath !=
"./")
327 Context[
"DocumentationFileName"] =
328 SmallString<16>(
"GlobalNamespace/index");
330 Context[
"RelativePath"] = CurrentRelativePath;
331 ContextArrayRef.insert(ContextArrayRef.begin(), ContextVal);
334 ContextArrayRef.back().getAsObject()->insert({
"End",
true});
335 Obj[
"Contexts"] = ContextArray;
336 Obj[
"HasContexts"] =
true;
343 Obj[
"USR"] = toHex(toStringRef(I.
USR));
352 Obj[
"Namespace"] = json::Array();
354 Obj[
"Namespace"].getAsArray()->push_back(NS.Name);
358 Object Description = Object();
365 if (
auto *ParagraphComment = Comment.getAsObject();
366 ParagraphComment->get(
"ParagraphComment")) {
368 if (TextCommentsArray.kind() == json::Value::Null ||
369 TextCommentsArray.getAsArray()->empty())
371 insertComment(Description, TextCommentsArray,
"ParagraphComments");
374 Obj[
"Description"] = std::move(Description);
379 const auto *Symbol =
static_cast<const SymbolInfo *
>(&I);
391 ReferenceObj[
"Name"] = Ref.
Name;
392 ReferenceObj[
"QualName"] = Ref.
QualName;
393 ReferenceObj[
"USR"] = toHex(toStringRef(Ref.
USR));
399 if (Ref.
Path !=
"GlobalNamespace" && !Ref.
Path.empty())
400 ReferenceObj[
"PathStem"] = sys::path::stem(Ref.
Path);
414 if (!Children.Enums.empty()) {
416 Obj[
"HasEnums"] =
true;
419 if (!Children.Typedefs.empty()) {
420 serializeArray(Children.Typedefs, Obj,
"Typedefs", SerializeInfo);
421 Obj[
"HasTypedefs"] =
true;
424 if (!Children.Records.empty()) {
426 Obj[
"HasRecords"] =
true;
430template <
typename Container,
typename SerializationFunc>
432 const std::string &Key,
433 SerializationFunc SerializeInfo) {
434 json::Value RecordsArray = Array();
435 auto &RecordsArrayRef = *RecordsArray.getAsArray();
436 RecordsArrayRef.reserve(Records.size());
438 json::Value ItemVal = Object();
439 auto &ItemObj = *ItemVal.getAsObject();
440 SerializeInfo(Records[
Index], ItemObj);
441 if (
Index == Records.size() - 1)
442 ItemObj[
"End"] =
true;
443 RecordsArrayRef.push_back(ItemVal);
445 Obj[Key] = RecordsArray;
455 json::Value ParamsArray = Array();
456 auto &ParamsArrayRef = *ParamsArray.getAsArray();
457 ParamsArrayRef.reserve(Params.size());
458 for (
size_t Idx = 0; Idx < Params.size(); ++Idx) {
459 json::Value ParamObjVal = Object();
460 Object &ParamObj = *ParamObjVal.getAsObject();
462 ParamObj[
"Param"] = Params[Idx].Contents;
463 if (Idx == Params.size() - 1)
464 ParamObj[
"End"] =
true;
465 ParamsArrayRef.push_back(ParamObjVal);
467 Obj[
"Parameters"] = ParamsArray;
471 json::Value TemplateVal = Object();
472 auto &TemplateObj = *TemplateVal.getAsObject();
474 if (Template.Specialization) {
475 json::Value TemplateSpecializationVal = Object();
476 auto &TemplateSpecializationObj = *TemplateSpecializationVal.getAsObject();
477 TemplateSpecializationObj[
"SpecializationOf"] =
478 toHex(toStringRef(Template.Specialization->SpecializationOf));
479 if (!Template.Specialization->Params.empty())
480 serializeInfo(Template.Specialization->Params, TemplateSpecializationObj);
481 TemplateObj[
"Specialization"] = TemplateSpecializationVal;
484 if (!Template.Params.empty())
487 if (!Template.Constraints.empty())
491 Obj[
"Template"] = TemplateVal;
505 Obj[
"USR"] = toHex(toStringRef(I.
Type.
USR));
511 Obj[
"Name"] = I.
Name;
513 json::Value ReferenceVal = Object();
514 Object &ReferenceObj = *ReferenceVal.getAsObject();
516 Obj[
"Type"] = ReferenceVal;
520 const std::optional<StringRef> RepositoryURL) {
524 auto ReturnTypeObj = Object();
526 Obj[
"ReturnType"] = std::move(ReturnTypeObj);
536 Obj[
"Name"] = I.
Name;
540 Obj[
"Value"] = I.
Value;
549 json::Value BaseTypeVal = Object();
550 auto &BaseTypeObj = *BaseTypeVal.getAsObject();
551 BaseTypeObj[
"Name"] = I.
BaseType->Type.Name;
552 BaseTypeObj[
"QualName"] = I.
BaseType->Type.QualName;
553 BaseTypeObj[
"USR"] = toHex(toStringRef(I.
BaseType->Type.USR));
554 Obj[
"BaseType"] = BaseTypeVal;
566 json::Value TypeVal = Object();
567 auto &TypeObj = *TypeVal.getAsObject();
569 Obj[
"Underlying"] = TypeVal;
578 Obj[
"Access"] = getAccessSpelling(I.
Access);
583 auto FriendRef = Object();
585 Obj[
"Reference"] = std::move(FriendRef);
592 auto ReturnTypeObj = Object();
594 Obj[
"ReturnType"] = std::move(ReturnTypeObj);
599static void insertArray(Object &Obj, json::Value &Array, StringRef Key) {
601 Obj[
"Has" + Key.str()] =
true;
612 json::Value PubFunctionsArray = Array();
613 json::Array &PubFunctionsArrayRef = *PubFunctionsArray.getAsArray();
614 json::Value ProtFunctionsArray = Array();
615 json::Array &ProtFunctionsArrayRef = *ProtFunctionsArray.getAsArray();
618 json::Value FunctionVal = Object();
619 auto &FunctionObj = *FunctionVal.getAsObject();
621 AccessSpecifier Access = Function.Access;
622 if (Access == AccessSpecifier::AS_public)
623 PubFunctionsArrayRef.push_back(FunctionVal);
624 else if (Access == AccessSpecifier::AS_protected)
625 ProtFunctionsArrayRef.push_back(FunctionVal);
628 if (!PubFunctionsArrayRef.empty())
629 insertArray(Obj, PubFunctionsArray,
"PublicFunctions");
630 if (!ProtFunctionsArrayRef.empty())
631 insertArray(Obj, ProtFunctionsArray,
"ProtectedFunctions");
635 json::Value PublicMembersArray = Array();
636 json::Array &PubMembersArrayRef = *PublicMembersArray.getAsArray();
637 json::Value ProtectedMembersArray = Array();
638 json::Array &ProtMembersArrayRef = *ProtectedMembersArray.getAsArray();
639 json::Value PrivateMembersArray = Array();
640 json::Array &PrivateMembersArrayRef = *PrivateMembersArray.getAsArray();
643 json::Value MemberVal = Object();
644 auto &MemberObj = *MemberVal.getAsObject();
645 MemberObj[
"Name"] = Member.
Name;
646 MemberObj[
"Type"] = Member.
Type.
Name;
647 MemberObj[
"IsStatic"] = Member.
IsStatic;
649 if (Member.
Access == AccessSpecifier::AS_public)
650 PubMembersArrayRef.push_back(MemberVal);
651 else if (Member.
Access == AccessSpecifier::AS_protected)
652 ProtMembersArrayRef.push_back(MemberVal);
653 else if (Member.
Access == AccessSpecifier::AS_private)
654 PrivateMembersArrayRef.push_back(MemberVal);
657 if (!PubMembersArrayRef.empty())
658 insertArray(Obj, PublicMembersArray,
"PublicMembers");
659 if (!ProtMembersArrayRef.empty())
660 insertArray(Obj, ProtectedMembersArray,
"ProtectedMembers");
661 if (!PrivateMembersArrayRef.empty())
662 insertArray(Obj, PrivateMembersArray,
"PrivateMembers");
665 if (!I.
Bases.empty())
667 I.
Bases, Obj,
"Bases",
669 serializeInfo(Base, BaseObj, RepositoryUrl);
674 Obj[
"HasParents"] =
true;
680 Obj[
"HasVirtualParents"] =
true;
688 Obj[
"HasFriends"] =
true;
698 auto TypeObj = Object();
700 Obj[
"Type"] = std::move(TypeObj);
707 Obj[
"Name"] =
"Global Namespace";
712 Obj[
"HasNamespaces"] =
true;
722 Obj[
"HasFunctions"] =
true;
727 Obj[
"HasConcepts"] =
true;
737 SmallString<16> FileName;
739 auto *RecordSymbolInfo =
static_cast<SymbolInfo *
>(I);
745 sys::path::append(Path, FileName +
".json");
754 return Error::success();
756 json::Value ObjVal = Object();
757 Object &Obj = *ObjVal.getAsObject();
760 auto IndexCopy = CDCtx.
Idx;
762 json::Value IndexArray = json::Array();
763 auto &IndexArrayRef = *IndexArray.getAsArray();
765 if (IndexCopy.Children.empty()) {
773 for (
auto &Idx : IndexCopy.Children) {
774 if (Idx.Children.empty())
777 json::Value IdxVal = Object();
778 auto &IdxObj = *IdxVal.getAsObject();
780 IndexArrayRef.push_back(IdxVal);
782 Obj[
"Index"] = IndexArray;
784 SmallString<128> IndexFilePath(RootDir);
785 sys::path::append(IndexFilePath,
"/json/index.json");
786 std::error_code FileErr;
787 raw_fd_ostream RootOS(IndexFilePath, FileErr, sys::fs::OF_Text);
789 return createFileError(
"cannot open file " + IndexFilePath, FileErr);
790 RootOS << llvm::formatv(
"{0:2}", ObjVal);
791 return Error::success();
795 StringMap<std::unique_ptr<Info>> &Infos) {
801 auto &ParentInfo = Infos.at(llvm::toHex(ParentUSR));
804 Context GlobalRef(ParentInfo->USR,
"Global Namespace",
806 SmallString<16>(
"index"));
811 Context ParentRef(*ParentInfo);
813 ParentUSR = ParentInfo->ParentUSR;
818 StringRef RootDir, llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
820 StringSet<> CreatedDirs;
821 StringMap<std::vector<doc::Info *>> FileToInfos;
822 for (
const auto &Group : Infos) {
823 Info *
Info = Group.getValue().get();
825 SmallString<128> Path;
826 auto RootDirStr = RootDir.str() +
"/json";
827 StringRef JSONDir = StringRef(RootDirStr);
828 sys::path::native(JSONDir, Path);
830 if (!CreatedDirs.contains(Path)) {
831 if (std::error_code Err = sys::fs::create_directories(Path);
832 Err != std::error_code())
833 return createFileError(Twine(Path), Err);
834 CreatedDirs.insert(Path);
838 if (FileToInfos.contains(Path))
840 FileToInfos[Path].push_back(
Info);
844 for (
const auto &Group : FileToInfos) {
845 std::error_code FileErr;
846 raw_fd_ostream InfoOS(Group.getKey(), FileErr, sys::fs::OF_Text);
848 return createFileError(
"cannot open file " + Group.getKey(), FileErr);
850 for (
const auto &
Info : Group.getValue()) {
863 json::Object Obj = Object();
880 return createStringError(inconvertibleErrorCode(),
"unexpected info type");
882 OS << llvm::formatv(
"{0:2}", llvm::json::Value(std::move(Obj)));
883 return Error::success();
887 return Error::success();
891 "Generator for JSON output.");
static llvm::cl::opt< std::string > RepositoryUrl("repository", llvm::cl::desc(R"(
URL of repository that hosts code.
Used for links to definition locations.)"), llvm::cl::cat(ClangDocCategory))
static const char * Format
Error generateDocForInfo(Info *I, llvm::raw_ostream &OS, const ClangDocContext &CDCtx) override
Error createResources(ClangDocContext &CDCtx) override
Error generateDocumentation(StringRef RootDir, llvm::StringMap< std::unique_ptr< doc::Info > > Infos, const ClangDocContext &CDCtx, std::string DirName) override
static std::string infoTypeToString(InfoType IT)
static json::Value extractTextComments(Object *ParagraphComment)
Takes the nested "Children" array from a comment Object.
static Object serializeComment(const CommentInfo &I, Object &Description)
std::string getTagType(TagTypeKind AS)
@ CK_InlineCommandComment
@ CK_VerbatimBlockLineComment
@ CK_VerbatimBlockComment
@ CK_TParamCommandComment
static void generateContext(const Info &I, Object &Obj)
Creates Contexts for namespaces and records to allow for navigation.
static void insertComment(Object &Description, json::Value &Comment, StringRef Key)
Insert comments into a key in the Description object.
static void serializeArray(const Container &Records, Object &Obj, const std::string &Key, SerializationFunc SerializeInfo)
static void serializeContexts(Info *I, StringMap< std::unique_ptr< Info > > &Infos)
volatile int JSONGeneratorAnchorSource
static auto SerializeReferenceLambda
static void serializeReference(const Reference &Ref, Object &ReferenceObj)
static void serializeInfo(const ConstraintInfo &I, Object &Obj)
static void serializeCommonAttributes(const Info &I, json::Object &Obj, const std::optional< StringRef > RepositoryUrl)
static GeneratorRegistry::Add< JSONGenerator > JSON(JSONGenerator::Format, "Generator for JSON output.")
static void serializeCommonChildren(const ScopeChildren &Children, json::Object &Obj, const std::optional< StringRef > RepositoryUrl)
static auto SerializeInfoLambda
static SmallString< 16 > determineFileName(Info *I, SmallString< 128 > &Path)
constexpr SymbolID GlobalNamespaceID
static json::Value extractVerbatimComments(json::Array VerbatimLines)
static void insertNonEmpty(StringRef Key, StringRef Value, Object &Obj)
static Error serializeIndex(const ClangDocContext &CDCtx, StringRef RootDir)
static json::Object serializeLocation(const Location &Loc, const std::optional< StringRef > RepositoryUrl)
llvm::StringRef commentKindToString(CommentKind Kind)
static void insertArray(Object &Obj, json::Value &Array, StringRef Key)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Some operations such as code completion produce a set of candidates.
std::optional< std::string > RepositoryUrl
SmallString< 16 > ConstraintExpression
SmallString< 16 > ConstraintExpr
llvm::SmallVector< EnumValueInfo, 4 > Members
std::optional< TypeInfo > BaseType
SmallString< 16 > ValueExpr
SmallString< 16 > DefaultValue
std::optional< TypeInfo > ReturnType
std::optional< SmallVector< FieldTypeInfo, 4 > > Params
std::optional< TemplateInfo > Template
llvm::SmallVector< FieldTypeInfo, 4 > Params
std::optional< TemplateInfo > Template
std::vector< Index > Children
SmallString< 16 > DocumentationFileName
std::vector< CommentInfo > Description
SmallVector< Context, 4 > Contexts
llvm::SmallString< 128 > Path
llvm::SmallString< 64 > getRelativeFilePath(const StringRef &CurrentPath) const
Returns the file path for this Info relative to CurrentPath.
llvm::SmallVector< Reference, 4 > Namespace
SmallString< 32 > Filename
llvm::SmallVector< MemberTypeInfo, 4 > Members
std::optional< TemplateInfo > Template
std::vector< FriendInfo > Friends
llvm::SmallVector< Reference, 4 > VirtualParents
llvm::SmallVector< Reference, 4 > Parents
std::vector< BaseRecordInfo > Bases
SmallString< 16 > QualName
llvm::SmallString< 128 > Path
SmallString< 16 > DocumentationFileName
std::vector< FunctionInfo > Functions
std::vector< Reference > Namespaces
std::vector< VarInfo > Variables
std::vector< ConceptInfo > Concepts
SmallString< 16 > MangledName
std::optional< TemplateInfo > Template
SmallString< 16 > TypeDeclaration