2#include "clang/Basic/Specifiers.h"
3#include "llvm/Support/JSON.h"
6using namespace llvm::json;
19 llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
21 std::string DirName)
override;
32 const std::optional<StringRef> &RepositoryLinePrefix);
36template <
typename Container,
typename SerializationFunc>
38 const std::string &Key,
39 SerializationFunc SerializeInfo);
77 llvm_unreachable(
"Unknown InfoType encountered.");
83 const std::optional<StringRef> RepositoryLinePrefix) {
84 Object LocationObj = Object();
86 LocationObj[
"Filename"] = Loc.
Filename;
91 sys::path::append(FileURL, sys::path::Style::posix, Loc.
Filename);
93 std::string LinePrefix;
94 if (!RepositoryLinePrefix)
97 LinePrefix = *RepositoryLinePrefix;
100 LocationObj[
"FileURL"] = FileURL;
112 if (
auto *Obj = Comment.getAsObject()) {
113 if (
auto *Children = Obj->getArray(
"Children");
114 Children && Children->empty())
118 else if (
auto *Array = Comment.getAsArray(); Array && Array->empty()) {
122 auto DescriptionIt = Description.find(Key);
124 if (DescriptionIt == Description.end()) {
125 auto CommentsArray = json::Array();
126 CommentsArray.push_back(Comment);
127 Description[Key] = std::move(CommentsArray);
128 Description[
"Has" + Key.str()] =
true;
130 DescriptionIt->getSecond().getAsArray()->push_back(Comment);
138 if (!ParagraphComment)
139 return json::Value(
nullptr);
140 json::Value *Children = ParagraphComment->get(
"Children");
142 return json::Value(
nullptr);
143 auto ChildrenArray = *Children->getAsArray();
144 auto ChildrenIt = ChildrenArray.begin();
145 while (ChildrenIt != ChildrenArray.end()) {
146 auto *ChildObj = ChildrenIt->getAsObject();
147 assert(ChildObj &&
"Invalid JSON object in Comment");
148 auto TextComment = ChildObj->getString(
"TextComment");
149 if (!TextComment || TextComment->empty()) {
150 ChildrenIt = ChildrenArray.erase(ChildrenIt);
155 return ChildrenArray;
159 json::Value TextArray = json::Array();
160 auto &TextArrayRef = *TextArray.getAsArray();
161 for (
auto &Line : VerbatimLines)
162 TextArrayRef.push_back(*Line.getAsObject()
163 ->get(
"VerbatimBlockLineComment")
172 Object Obj = Object();
174 json::Value ChildVal = Object();
175 Object &Child = *ChildVal.getAsObject();
177 json::Value ChildArr = Array();
178 auto &CARef = *ChildArr.getAsArray();
192 if (I.
Name ==
"brief")
193 insertComment(Description, TextCommentsArray,
"BriefComments");
194 else if (I.
Name ==
"return")
195 insertComment(Description, TextCommentsArray,
"ReturnComments");
196 else if (I.
Name ==
"throws" || I.
Name ==
"throw") {
197 json::Value ThrowsVal = Object();
198 auto &ThrowsObj = *ThrowsVal.getAsObject();
199 ThrowsObj[
"Exception"] = I.
Args.front();
200 ThrowsObj[
"Children"] = TextCommentsArray;
207 json::Value ArgsArr = Array();
208 auto &ARef = *ArgsArr.getAsArray();
209 ARef.reserve(I.
Args.size());
210 for (
const auto &Arg : I.
Args)
211 ARef.emplace_back(Arg);
212 Child.insert({
"Command", I.
Name});
213 Child.insert({
"Args", ArgsArr});
214 Child.insert({
"Children", ChildArr});
221 Child.insert({
"ParamName", I.
ParamName});
222 Child.insert({
"Direction", I.
Direction});
223 Child.insert({
"Explicit", I.
Explicit});
225 Child.insert({
"Children", TextCommentsArray});
237 insertComment(Description, TextCommentsArray,
"CodeComments");
245 Child.insert({
"Text", I.
Text});
246 Child.insert({
"Children", ChildArr});
252 json::Value AttrKeysArray = json::Array();
253 json::Value AttrValuesArray = json::Array();
254 auto &KeyArr = *AttrKeysArray.getAsArray();
255 auto &ValArr = *AttrValuesArray.getAsArray();
259 KeyArr.emplace_back(K);
261 ValArr.emplace_back(V);
262 Child.insert({
"Name", I.
Name});
264 Child.insert({
"AttrKeys", AttrKeysArray});
265 Child.insert({
"AttrValues", AttrValuesArray});
266 Child.insert({
"Children", ChildArr});
272 Child.insert({
"Name", I.
Name});
273 Child.insert({
"Children", ChildArr});
280 Child.insert({
"Children", ChildArr});
281 Child[
"ParagraphComment"] =
true;
290 llvm_unreachable(
"Unknown comment kind encountered.");
295 json::Value ContextArray = json::Array();
296 auto &ContextArrayRef = *ContextArray.getAsArray();
297 ContextArrayRef.reserve(I.
Contexts.size());
299 std::string CurrentRelativePath;
300 bool PreviousRecord =
false;
301 for (
const auto &Current : I.
Contexts) {
302 json::Value ContextVal = Object();
303 Object &
Context = *ContextVal.getAsObject();
307 if (Current.DocumentationFileName ==
"index") {
310 PreviousRecord =
false;
311 Context[
"RelativePath"] =
"./";
315 PreviousRecord =
true;
316 CurrentRelativePath +=
"../";
317 Context[
"RelativePath"] = CurrentRelativePath;
319 ContextArrayRef.push_back(ContextVal);
323 if (PreviousRecord && (Current.DocumentationFileName ==
"index")) {
326 PreviousRecord =
false;
327 }
else if (Current.DocumentationFileName !=
"index") {
330 PreviousRecord =
true;
331 CurrentRelativePath +=
"../";
334 PreviousRecord =
false;
335 CurrentRelativePath +=
"../";
338 if (Current.QualName ==
"GlobalNamespace" && Current.RelativePath !=
"./")
339 Context[
"DocumentationFileName"] =
340 SmallString<16>(
"GlobalNamespace/index");
342 Context[
"RelativePath"] = CurrentRelativePath;
343 ContextArrayRef.insert(ContextArrayRef.begin(), ContextVal);
346 ContextArrayRef.back().getAsObject()->insert({
"End",
true});
347 Obj[
"Contexts"] = ContextArray;
348 Obj[
"HasContexts"] =
true;
354 const std::optional<StringRef> RepositoryLinePrefix) {
356 Obj[
"USR"] = toHex(toStringRef(I.
USR));
365 Obj[
"Namespace"] = json::Array();
367 Obj[
"Namespace"].getAsArray()->push_back(NS.Name);
371 Object Description = Object();
378 if (
auto *ParagraphComment = Comment.getAsObject();
379 ParagraphComment->get(
"ParagraphComment")) {
381 if (TextCommentsArray.kind() == json::Value::Null ||
382 TextCommentsArray.getAsArray()->empty())
384 insertComment(Description, TextCommentsArray,
"ParagraphComments");
387 Obj[
"Description"] = std::move(Description);
392 const auto *Symbol =
static_cast<const SymbolInfo *
>(&I);
395 RepositoryLinePrefix);
404 ReferenceObj[
"Name"] = Ref.
Name;
405 ReferenceObj[
"QualName"] = Ref.
QualName;
406 ReferenceObj[
"USR"] = toHex(toStringRef(Ref.
USR));
412 if (Ref.
Path !=
"GlobalNamespace" && !Ref.
Path.empty())
413 ReferenceObj[
"PathStem"] = sys::path::stem(Ref.
Path);
422 const std::optional<StringRef> RepositoryLinePrefix) {
423 static auto SerializeInfo =
428 if (!Children.Enums.empty()) {
430 Obj[
"HasEnums"] =
true;
433 if (!Children.Typedefs.empty()) {
434 serializeArray(Children.Typedefs, Obj,
"Typedefs", SerializeInfo);
435 Obj[
"HasTypedefs"] =
true;
438 if (!Children.Records.empty()) {
440 Obj[
"HasRecords"] =
true;
444template <
typename Container,
typename SerializationFunc>
446 const std::string &Key,
447 SerializationFunc SerializeInfo) {
448 json::Value RecordsArray = Array();
449 auto &RecordsArrayRef = *RecordsArray.getAsArray();
450 RecordsArrayRef.reserve(Records.size());
452 json::Value ItemVal = Object();
453 auto &ItemObj = *ItemVal.getAsObject();
454 SerializeInfo(Records[
Index], ItemObj);
455 if (
Index == Records.size() - 1)
456 ItemObj[
"End"] =
true;
457 RecordsArrayRef.push_back(ItemVal);
459 Obj[Key] = RecordsArray;
469 json::Value ParamsArray = Array();
470 auto &ParamsArrayRef = *ParamsArray.getAsArray();
471 ParamsArrayRef.reserve(Params.size());
472 for (
size_t Idx = 0; Idx < Params.size(); ++Idx) {
473 json::Value ParamObjVal = Object();
474 Object &ParamObj = *ParamObjVal.getAsObject();
476 ParamObj[
"Param"] = Params[Idx].Contents;
477 if (Idx == Params.size() - 1)
478 ParamObj[
"End"] =
true;
479 ParamsArrayRef.push_back(ParamObjVal);
481 Obj[
"Parameters"] = ParamsArray;
485 json::Value TemplateVal = Object();
486 auto &TemplateObj = *TemplateVal.getAsObject();
488 if (Template.Specialization) {
489 json::Value TemplateSpecializationVal = Object();
490 auto &TemplateSpecializationObj = *TemplateSpecializationVal.getAsObject();
491 TemplateSpecializationObj[
"SpecializationOf"] =
492 toHex(toStringRef(Template.Specialization->SpecializationOf));
493 if (!Template.Specialization->Params.empty())
494 serializeInfo(Template.Specialization->Params, TemplateSpecializationObj);
495 TemplateObj[
"Specialization"] = TemplateSpecializationVal;
498 if (!Template.Params.empty())
501 if (!Template.Constraints.empty())
505 Obj[
"Template"] = TemplateVal;
510 const std::optional<StringRef> &RepositoryLine) {
520 Obj[
"USR"] = toHex(toStringRef(I.
Type.
USR));
526 Obj[
"Name"] = I.
Name;
528 json::Value ReferenceVal = Object();
529 Object &ReferenceObj = *ReferenceVal.getAsObject();
531 Obj[
"Type"] = ReferenceVal;
535 const std::optional<StringRef> RepositoryURL,
536 const std::optional<StringRef> RepositoryLine) {
540 auto ReturnTypeObj = Object();
542 Obj[
"ReturnType"] = std::move(ReturnTypeObj);
552 Obj[
"Name"] = I.
Name;
556 Obj[
"Value"] = I.
Value;
561 const std::optional<StringRef> &RepositoryLine) {
566 json::Value BaseTypeVal = Object();
567 auto &BaseTypeObj = *BaseTypeVal.getAsObject();
568 BaseTypeObj[
"Name"] = I.
BaseType->Type.Name;
569 BaseTypeObj[
"QualName"] = I.
BaseType->Type.QualName;
570 BaseTypeObj[
"USR"] = toHex(toStringRef(I.
BaseType->Type.USR));
571 Obj[
"BaseType"] = BaseTypeVal;
581 const std::optional<StringRef> &RepositoryLinePrefix) {
585 json::Value TypeVal = Object();
586 auto &TypeObj = *TypeVal.getAsObject();
588 Obj[
"Underlying"] = TypeVal;
596 const std::optional<StringRef> &RepositoryLinePrefix) {
598 RepositoryLinePrefix);
600 Obj[
"Access"] = getAccessSpelling(I.
Access);
605 auto FriendRef = Object();
607 Obj[
"Reference"] = std::move(FriendRef);
614 auto ReturnTypeObj = Object();
616 Obj[
"ReturnType"] = std::move(ReturnTypeObj);
621static void insertArray(Object &Obj, json::Value &Array, StringRef Key) {
623 Obj[
"Has" + Key.str()] =
true;
629 const std::optional<StringRef> &RepositoryLinePrefix) {
636 json::Value PubFunctionsArray = Array();
637 json::Array &PubFunctionsArrayRef = *PubFunctionsArray.getAsArray();
638 json::Value ProtFunctionsArray = Array();
639 json::Array &ProtFunctionsArrayRef = *ProtFunctionsArray.getAsArray();
642 json::Value FunctionVal = Object();
643 auto &FunctionObj = *FunctionVal.getAsObject();
645 AccessSpecifier Access = Function.Access;
646 if (Access == AccessSpecifier::AS_public)
647 PubFunctionsArrayRef.push_back(FunctionVal);
648 else if (Access == AccessSpecifier::AS_protected)
649 ProtFunctionsArrayRef.push_back(FunctionVal);
652 if (!PubFunctionsArrayRef.empty())
653 insertArray(Obj, PubFunctionsArray,
"PublicMethods");
654 if (!ProtFunctionsArrayRef.empty())
655 insertArray(Obj, ProtFunctionsArray,
"ProtectedMethods");
659 json::Value PublicMembersArray = Array();
660 json::Array &PubMembersArrayRef = *PublicMembersArray.getAsArray();
661 json::Value ProtectedMembersArray = Array();
662 json::Array &ProtMembersArrayRef = *ProtectedMembersArray.getAsArray();
663 json::Value PrivateMembersArray = Array();
664 json::Array &PrivateMembersArrayRef = *PrivateMembersArray.getAsArray();
667 json::Value MemberVal = Object();
668 auto &MemberObj = *MemberVal.getAsObject();
669 MemberObj[
"Name"] = Member.
Name;
670 MemberObj[
"Type"] = Member.
Type.
Name;
671 MemberObj[
"IsStatic"] = Member.
IsStatic;
673 if (Member.
Access == AccessSpecifier::AS_public)
674 PubMembersArrayRef.push_back(MemberVal);
675 else if (Member.
Access == AccessSpecifier::AS_protected)
676 ProtMembersArrayRef.push_back(MemberVal);
677 else if (Member.
Access == AccessSpecifier::AS_private)
678 PrivateMembersArrayRef.push_back(MemberVal);
681 if (!PubMembersArrayRef.empty())
682 insertArray(Obj, PublicMembersArray,
"PublicMembers");
683 if (!ProtMembersArrayRef.empty())
684 insertArray(Obj, ProtectedMembersArray,
"ProtectedMembers");
685 if (!PrivateMembersArrayRef.empty())
686 insertArray(Obj, PrivateMembersArray,
"PrivateMembers");
689 if (!I.
Bases.empty())
693 serializeInfo(Base, BaseObj, RepositoryUrl,
694 RepositoryLinePrefix);
699 Obj[
"HasParents"] =
true;
705 Obj[
"HasVirtualParents"] =
true;
713 Obj[
"HasFriends"] =
true;
722 const std::optional<StringRef> RepositoryUrlLinePrefix) {
725 auto TypeObj = Object();
727 Obj[
"Type"] = std::move(TypeObj);
732 const std::optional<StringRef> RepositoryLinePrefix) {
735 Obj[
"Name"] =
"Global Namespace";
740 Obj[
"HasNamespaces"] =
true;
743 static auto SerializeInfo =
750 Obj[
"HasFunctions"] =
true;
755 Obj[
"HasConcepts"] =
true;
760 Obj[
"HasVariables"] =
true;
767 SmallString<16> FileName;
769 auto *RecordSymbolInfo =
static_cast<SymbolInfo *
>(I);
775 sys::path::append(Path, FileName +
".json");
784 return Error::success();
786 json::Value ObjVal = Object();
787 Object &Obj = *ObjVal.getAsObject();
790 auto IndexCopy = CDCtx.
Idx;
792 json::Value IndexArray = json::Array();
793 auto &IndexArrayRef = *IndexArray.getAsArray();
795 if (IndexCopy.Children.empty()) {
803 for (
auto &Idx : IndexCopy.Children) {
804 if (Idx.Children.empty())
807 json::Value IdxVal = Object();
808 auto &IdxObj = *IdxVal.getAsObject();
810 IndexArrayRef.push_back(IdxVal);
812 Obj[
"Index"] = IndexArray;
814 SmallString<128> IndexFilePath(RootDir);
815 sys::path::append(IndexFilePath,
"/json/index.json");
816 std::error_code FileErr;
817 raw_fd_ostream RootOS(IndexFilePath, FileErr, sys::fs::OF_Text);
819 return createFileError(
"cannot open file " + IndexFilePath, FileErr);
820 RootOS << llvm::formatv(
"{0:2}", ObjVal);
821 return Error::success();
825 StringMap<std::unique_ptr<Info>> &Infos) {
831 auto &ParentInfo = Infos.at(llvm::toHex(ParentUSR));
834 Context GlobalRef(ParentInfo->USR,
"Global Namespace",
836 SmallString<16>(
"index"));
841 Context ParentRef(*ParentInfo);
843 ParentUSR = ParentInfo->ParentUSR;
848 StringRef RootDir, llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
850 StringSet<> CreatedDirs;
851 StringMap<std::vector<doc::Info *>> FileToInfos;
852 for (
const auto &Group : Infos) {
853 Info *
Info = Group.getValue().get();
855 SmallString<128> Path;
856 auto RootDirStr = RootDir.str() +
"/json";
857 StringRef JSONDir = StringRef(RootDirStr);
858 sys::path::native(JSONDir, Path);
860 if (!CreatedDirs.contains(Path)) {
861 if (std::error_code Err = sys::fs::create_directories(Path);
862 Err != std::error_code())
863 return createFileError(Twine(Path), Err);
864 CreatedDirs.insert(Path);
868 if (FileToInfos.contains(Path))
870 FileToInfos[Path].push_back(
Info);
874 for (
const auto &Group : FileToInfos) {
875 std::error_code FileErr;
876 raw_fd_ostream InfoOS(Group.getKey(), FileErr, sys::fs::OF_Text);
878 return createFileError(
"cannot open file " + Group.getKey(), FileErr);
880 for (
const auto &
Info : Group.getValue()) {
893 json::Object Obj = Object();
912 return createStringError(inconvertibleErrorCode(),
"unexpected info type");
914 OS << llvm::formatv(
"{0:2}", llvm::json::Value(std::move(Obj)));
915 return Error::success();
919 return Error::success();
923 "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 void serializeCommonChildren(const ScopeChildren &Children, json::Object &Obj, const std::optional< StringRef > RepositoryUrl, const std::optional< StringRef > RepositoryLinePrefix)
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 GeneratorRegistry::Add< JSONGenerator > JSON(JSONGenerator::Format, "Generator for JSON output.")
static json::Object serializeLocation(const Location &Loc, const std::optional< StringRef > RepositoryUrl, const std::optional< StringRef > RepositoryLinePrefix)
static auto SerializeInfoLambda
static SmallString< 16 > determineFileName(Info *I, SmallString< 128 > &Path)
constexpr SymbolID GlobalNamespaceID
static void serializeCommonAttributes(const Info &I, json::Object &Obj, const std::optional< StringRef > RepositoryUrl, const std::optional< StringRef > RepositoryLinePrefix)
static json::Value extractVerbatimComments(json::Array VerbatimLines)
static void insertNonEmpty(StringRef Key, StringRef Value, Object &Obj)
static Error serializeIndex(const ClangDocContext &CDCtx, StringRef RootDir)
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
std::optional< std::string > RepositoryLinePrefix
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