clang-tools 23.0.0git
Representation.cpp
Go to the documentation of this file.
1///===-- Representation.cpp - ClangDoc Representation -----------*- 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// This file defines the merging of different types of infos. The data in the
10// calling Info is preserved during a merge unless that field is empty or
11// default. In that case, the data from the parameter Info is used to replace
12// the empty or default data.
13//
14// For most fields, the first decl seen provides the data. Exceptions to this
15// include the location and description fields, which are collections of data on
16// all decls related to a given definition. All other fields are ignored in new
17// decls unless the first seen decl didn't, for whatever reason, incorporate
18// data on that field (e.g. a forward declared class wouldn't have information
19// on members on the forward declaration, but would have the class name).
20//
21//===----------------------------------------------------------------------===//
22#include "Representation.h"
23#include "llvm/ADT/STLExtras.h"
24#include "llvm/ADT/StringMap.h"
25#include "llvm/Support/Error.h"
26#include "llvm/Support/Path.h"
27
28namespace clang {
29namespace doc {
30
31// Thread local arenas usable in each thread pool
32llvm::BumpPtrAllocator &getTransientArena() {
33 thread_local llvm::BumpPtrAllocator TransientArena;
34 return TransientArena;
35}
36
37llvm::BumpPtrAllocator &getPersistentArena() {
38 thread_local llvm::BumpPtrAllocator PersistentArena;
39 return PersistentArena;
40}
41
43 static ConcurrentStringPool GlobalPool;
44 return GlobalPool;
45}
46
47CommentKind stringToCommentKind(llvm::StringRef KindStr) {
48 static const llvm::StringMap<CommentKind> KindMap = {
49 {"FullComment", CommentKind::CK_FullComment},
50 {"ParagraphComment", CommentKind::CK_ParagraphComment},
51 {"TextComment", CommentKind::CK_TextComment},
52 {"InlineCommandComment", CommentKind::CK_InlineCommandComment},
53 {"HTMLStartTagComment", CommentKind::CK_HTMLStartTagComment},
54 {"HTMLEndTagComment", CommentKind::CK_HTMLEndTagComment},
55 {"BlockCommandComment", CommentKind::CK_BlockCommandComment},
56 {"ParamCommandComment", CommentKind::CK_ParamCommandComment},
57 {"TParamCommandComment", CommentKind::CK_TParamCommandComment},
58 {"VerbatimBlockComment", CommentKind::CK_VerbatimBlockComment},
59 {"VerbatimBlockLineComment", CommentKind::CK_VerbatimBlockLineComment},
60 {"VerbatimLineComment", CommentKind::CK_VerbatimLineComment},
61 };
62
63 auto It = KindMap.find(KindStr);
64 if (It != KindMap.end()) {
65 return It->second;
66 }
68}
69
70llvm::StringRef commentKindToString(CommentKind Kind) {
71 switch (Kind) {
73 return "FullComment";
75 return "ParagraphComment";
77 return "TextComment";
79 return "InlineCommandComment";
81 return "HTMLStartTagComment";
83 return "HTMLEndTagComment";
85 return "BlockCommandComment";
87 return "ParamCommandComment";
89 return "TParamCommandComment";
91 return "VerbatimBlockComment";
93 return "VerbatimBlockLineComment";
95 return "VerbatimLineComment";
97 return "Unknown";
98 }
99 llvm_unreachable("Unhandled CommentKind");
100}
101
103
104template <typename T>
105static llvm::Expected<Info *> reduce(SmallVectorImpl<Info *> &Values) {
106 if (Values.empty() || !Values[0])
107 return llvm::createStringError(llvm::inconvertibleErrorCode(),
108 "no value to reduce");
109 T *Merged = allocateTransient<T>(Values[0]->USR);
110 for (auto &I : Values)
111 Merged->merge(std::move(*cast<T>(I)));
112 return Merged;
113}
114
115template <typename T>
116static void reduceChildren(DocList<T> &Children, DocList<T> &&ChildrenToMerge) {
117 while (!ChildrenToMerge.empty()) {
118 T *Ptr = ChildrenToMerge.front().Ptr;
119 ChildrenToMerge.pop_front();
120
121 auto It = llvm::find_if(
122 Children, [Ptr](const auto &C) { return C.Ptr->USR == Ptr->USR; });
123
124 if (It == Children.end()) {
125 InfoNode<T> *NewNode = allocateListNodePersistent<T>(Ptr->USR);
126 NewNode->Ptr->merge(std::move(*Ptr));
127 Children.push_back(*NewNode);
128 } else {
129 It->Ptr->merge(std::move(*Ptr));
130 }
131 }
132}
133
134template <>
136 DocList<Reference> &&ChildrenToMerge) {
137 while (!ChildrenToMerge.empty()) {
138 Reference *Ptr = ChildrenToMerge.front().Ptr;
139 ChildrenToMerge.pop_front();
140
141 auto It = llvm::find_if(
142 Children, [Ptr](const auto &C) { return C.Ptr->USR == Ptr->USR; });
143 if (It == Children.end()) {
145 NewNode->Ptr->USR = Ptr->USR;
146 NewNode->Ptr->RefType = Ptr->RefType;
147 NewNode->Ptr->merge(std::move(*Ptr));
148 Children.push_back(*NewNode);
149 } else {
150 It->Ptr->merge(std::move(*Ptr));
151 }
152 }
153}
154
155template <typename T>
156static void mergeUnkeyed(DocList<T> &Target, DocList<T> &&Source) {
157 while (!Source.empty()) {
158 T *Ptr = Source.front().Ptr;
159 Source.pop_front();
160
161 if (!llvm::any_of(Target,
162 [Ptr](const auto &E) { return *E.Ptr == *Ptr; })) {
163 Target.push_back(*allocateListNodePersistent<T>(*Ptr));
164 }
165 }
166}
167
168template <>
170 DocList<CommentInfo> &&Source) {
171 while (!Source.empty()) {
172 CommentInfo *Ptr = Source.front().Ptr;
173 Source.pop_front();
174
175 if (llvm::none_of(Target,
176 [Ptr](const auto &E) { return *E.Ptr == *Ptr; })) {
177 Target.push_back(
179 }
180 }
181}
182
183template <typename T>
184static llvm::Error mergeTypedInfo(Info *&Reduced, Info *NewInfo,
185 llvm::BumpPtrAllocator &Arena) {
186 if (!Reduced)
187 Reduced = allocatePtr<T>(Arena, NewInfo->USR);
188 cast<T>(Reduced)->merge(std::move(*cast<T>(NewInfo)));
189 return llvm::Error::success();
190}
191
192llvm::Error mergeSingleInfo(doc::Info *&Reduced, doc::Info *NewInfo,
193 llvm::BumpPtrAllocator &Arena) {
194 if (Reduced && Reduced->IT != NewInfo->IT)
195 return llvm::createStringError(llvm::inconvertibleErrorCode(),
196 "info types mismatch");
197
198 switch (NewInfo->IT) {
200 return mergeTypedInfo<NamespaceInfo>(Reduced, NewInfo, Arena);
202 return mergeTypedInfo<RecordInfo>(Reduced, NewInfo, Arena);
204 return mergeTypedInfo<EnumInfo>(Reduced, NewInfo, Arena);
206 return mergeTypedInfo<FunctionInfo>(Reduced, NewInfo, Arena);
208 return mergeTypedInfo<TypedefInfo>(Reduced, NewInfo, Arena);
210 return mergeTypedInfo<ConceptInfo>(Reduced, NewInfo, Arena);
212 return mergeTypedInfo<VarInfo>(Reduced, NewInfo, Arena);
214 return mergeTypedInfo<FriendInfo>(Reduced, NewInfo, Arena);
215 default:
216 return llvm::createStringError(llvm::inconvertibleErrorCode(),
217 "unknown info type");
218 }
219
220 return llvm::Error::success();
221}
222
223// Dispatch function.
224llvm::Expected<Info *> mergeInfos(SmallVectorImpl<Info *> &Values) {
225 if (Values.empty() || !Values[0])
226 return llvm::createStringError(llvm::inconvertibleErrorCode(),
227 "no info values to merge");
228
229 switch (Values[0]->IT) {
231 return reduce<NamespaceInfo>(Values);
233 return reduce<RecordInfo>(Values);
235 return reduce<EnumInfo>(Values);
237 return reduce<FunctionInfo>(Values);
239 return reduce<TypedefInfo>(Values);
241 return reduce<ConceptInfo>(Values);
243 return reduce<VarInfo>(Values);
245 return reduce<FriendInfo>(Values);
247 return llvm::createStringError(llvm::inconvertibleErrorCode(),
248 "unexpected info type");
249 }
250 llvm_unreachable("unhandled enumerator");
251}
252
254 const TemplateSpecializationInfo &Other, llvm::BumpPtrAllocator &Arena)
256 Params = allocateArray(Other.Params, Arena);
257}
258
260 llvm::BumpPtrAllocator &Arena) {
261 Params = allocateArray(Other.Params, Arena);
262 if (Other.Specialization)
264 Constraints = allocateArray(Other.Constraints, Arena);
265}
266
267bool CommentInfo::operator==(const CommentInfo &Other) const {
268 auto FirstCI = std::tie(Kind, Text, Name, Direction, ParamName, CloseName,
270 auto SecondCI =
271 std::tie(Other.Kind, Other.Text, Other.Name, Other.Direction,
272 Other.ParamName, Other.CloseName, Other.SelfClosing,
273 Other.Explicit, Other.AttrKeys, Other.AttrValues, Other.Args);
274
275 if (FirstCI != SecondCI || Children.size() != Other.Children.size())
276 return false;
277
278 return llvm::equal(Children, Other.Children);
279}
280
281bool CommentInfo::operator<(const CommentInfo &Other) const {
282 auto FirstCI = std::tie(Kind, Text, Name, Direction, ParamName, CloseName,
284 auto SecondCI =
285 std::tie(Other.Kind, Other.Text, Other.Name, Other.Direction,
286 Other.ParamName, Other.CloseName, Other.SelfClosing,
287 Other.Explicit, Other.AttrKeys, Other.AttrValues, Other.Args);
288
289 if (FirstCI < SecondCI)
290 return true;
291
292 if (FirstCI == SecondCI) {
293 return std::lexicographical_compare(Children.begin(), Children.end(),
294 Other.Children.begin(),
295 Other.Children.end());
296 }
297
298 return false;
299}
300
302 llvm::BumpPtrAllocator &Arena) {
303 Kind = Other.Kind;
304 Direction = Other.Direction;
305 Name = Other.Name;
306 ParamName = Other.ParamName;
307 CloseName = Other.CloseName;
308 SelfClosing = Other.SelfClosing;
309 Explicit = Other.Explicit;
310 Text = Other.Text;
311 AttrKeys = allocateArray(Other.AttrKeys, Arena);
312 AttrValues = allocateArray(Other.AttrValues, Arena);
313 Args = allocateArray(Other.Args, Arena);
314 if (!Other.Children.empty()) {
315 CommentInfo *NewArray = Arena.Allocate<CommentInfo>(Other.Children.size());
316 for (size_t Idx = 0; Idx < Other.Children.size(); ++Idx) {
317 new (NewArray + Idx) CommentInfo(Other.Children[Idx], Arena);
318 }
319 Children = llvm::ArrayRef<CommentInfo>(NewArray, Other.Children.size());
320 }
321}
322
323static llvm::SmallString<64>
324calculateRelativeFilePath(const InfoType &Type, const StringRef &Path,
325 const StringRef &Name, const StringRef &CurrentPath) {
326 llvm::SmallString<64> FilePath;
327
328 if (CurrentPath != Path) {
329 // iterate back to the top
330 for (llvm::sys::path::const_iterator I =
331 llvm::sys::path::begin(CurrentPath);
332 I != llvm::sys::path::end(CurrentPath); ++I)
333 llvm::sys::path::append(FilePath, "..");
334 llvm::sys::path::append(FilePath, Path);
335 }
336
337 // Namespace references have a Path to the parent namespace, but
338 // the file is actually in the subdirectory for the namespace.
339 if (Type == doc::InfoType::IT_namespace)
340 llvm::sys::path::append(FilePath, Name);
341
342 return llvm::sys::path::relative_path(FilePath);
343}
344
345StringRef Reference::getRelativeFilePath(const StringRef &CurrentPath) const {
346 return internString(
348}
349
350StringRef Reference::getFileBaseName() const {
352 return "index";
353
354 return Name;
355}
356
357StringRef Info::getRelativeFilePath(const StringRef &CurrentPath) const {
358 return internString(
359 calculateRelativeFilePath(IT, Path, extractName(), CurrentPath));
360}
361
362StringRef Info::getFileBaseName() const {
364 return "index";
365
366 return extractName();
367}
368
369bool Reference::mergeable(const Reference &Other) {
370 return RefType == Other.RefType && USR == Other.USR;
371}
372
374 assert(mergeable(Other));
375 assert(RefType != InfoType::IT_default &&
376 "Merging reference with default InfoType");
377 if (Name.empty())
378 Name = Other.Name;
379 if (Path.empty())
380 Path = Other.Path;
381 if (QualName.empty())
382 QualName = Other.QualName;
383 if (DocumentationFileName.empty())
384 DocumentationFileName = Other.DocumentationFileName;
385}
386
388 return Ref.USR == Other.Ref.USR && Ref.Name == Other.Ref.Name;
389}
390
392 assert(mergeable(Other));
393 Ref.merge(std::move(Other.Ref));
394 SymbolInfo::merge(std::move(Other));
395}
396
397FriendInfo::FriendInfo(const FriendInfo &Other, llvm::BumpPtrAllocator &Arena)
398 : SymbolInfo(Other, Arena) {
399 Ref = Other.Ref;
400 if (Other.Template)
401 Template.emplace(*Other.Template, Arena);
402 if (Other.ReturnType)
403 ReturnType = Other.ReturnType;
404 if (!Other.Params.empty())
405 Params = allocateArray(Other.Params, Arena);
406 IsClass = Other.IsClass;
407}
408
409Info::Info(const Info &Other, llvm::BumpPtrAllocator &Arena)
410 : Path(Other.Path), Name(Other.Name),
412 ParentUSR(Other.ParentUSR), IT(Other.IT) {
413 Namespace = allocateArray(Other.Namespace, Arena);
414 if (!Other.Description.empty()) {
415 for (const auto &Desc : Other.Description) {
416 CommentInfo *NewDesc = allocatePtr<CommentInfo>(Arena, Desc, Arena);
417 Description.push_back(*allocateListNode<CommentInfo>(Arena, NewDesc));
418 }
419 }
420}
421
422void Info::mergeBase(Info &&Other) {
423 assert(mergeable(Other));
424 assert(IT != InfoType::IT_default && "Merging info with default InfoType");
425 if (USR == EmptySID)
426 USR = Other.USR;
427 if (Name == "")
428 Name = Other.Name;
429 if (Path == "")
430 Path = Other.Path;
431 if (Namespace.empty() && !Other.Namespace.empty())
432 Namespace = allocateArray(Other.Namespace, getPersistentArena());
433 // Unconditionally extend the description, since each decl may have a comment.
434 mergeUnkeyed(Description, std::move(Other.Description));
435 if (ParentUSR == EmptySID)
436 ParentUSR = Other.ParentUSR;
437 if (DocumentationFileName.empty())
438 DocumentationFileName = Other.DocumentationFileName;
439}
440
441bool Info::mergeable(const Info &Other) {
442 return IT == Other.IT && USR == Other.USR;
443}
444
445SymbolInfo::SymbolInfo(const SymbolInfo &Other, llvm::BumpPtrAllocator &Arena)
446 : Info(Other, Arena), DefLoc(Other.DefLoc), MangledName(Other.MangledName),
447 IsStatic(Other.IsStatic) {
448 if (!Other.Loc.empty()) {
449 for (const auto &L : Other.Loc) {
450 Location *NewL = allocatePtr<Location>(Arena, L);
451 Loc.push_back(*allocateListNode<Location>(Arena, NewL));
452 }
453 }
454}
455
456void SymbolInfo::merge(SymbolInfo &&Other) {
457 assert(mergeable(Other));
458 if (!DefLoc)
459 DefLoc = std::move(Other.DefLoc);
460 if (MangledName.empty())
461 MangledName = std::move(Other.MangledName);
462 // Unconditionally extend the list of locations, since we want all of them.
463 mergeUnkeyed(Loc, std::move(Other.Loc));
464 mergeBase(std::move(Other));
465 if (!IsStatic)
466 IsStatic = Other.IsStatic;
467}
468
471
473 assert(mergeable(Other));
474 // Reduce children if necessary.
475 reduceChildren(Children.Namespaces, std::move(Other.Children.Namespaces));
476 reduceChildren(Children.Records, std::move(Other.Children.Records));
477 reduceChildren(Children.Functions, std::move(Other.Children.Functions));
478 reduceChildren(Children.Enums, std::move(Other.Children.Enums));
479 reduceChildren(Children.Typedefs, std::move(Other.Children.Typedefs));
480 reduceChildren(Children.Concepts, std::move(Other.Children.Concepts));
481 reduceChildren(Children.Variables, std::move(Other.Children.Variables));
482 mergeBase(std::move(Other));
483}
484
487
488RecordInfo::RecordInfo(const RecordInfo &Other, llvm::BumpPtrAllocator &Arena)
489 : SymbolInfo(Other, Arena), TagType(Other.TagType),
490 IsTypeDef(Other.IsTypeDef) {
491 Members = deepCopyArray(Other.Members, Arena);
492 Parents = allocateArray(Other.Parents, Arena);
494 Bases = deepCopyArray(Other.Bases, Arena);
495 Friends = deepCopyArray(Other.Friends, Arena);
496}
497
499 llvm::BumpPtrAllocator &Arena)
500 : FieldTypeInfo(Other), Access(Other.Access), IsStatic(Other.IsStatic) {
501 if (!Other.Description.empty()) {
502 for (const auto &Desc : Other.Description) {
503 CommentInfo *NewDesc = allocatePtr<CommentInfo>(Arena, Desc, Arena);
504 Description.push_back(*allocateListNode<CommentInfo>(Arena, NewDesc));
505 }
506 }
507}
508
510 assert(mergeable(Other));
511 if (!llvm::to_underlying(TagType))
512 TagType = Other.TagType;
513 IsTypeDef = IsTypeDef || Other.IsTypeDef;
514 if (Members.empty() && !Other.Members.empty())
515 Members = deepCopyArray(Other.Members, getPersistentArena());
516 if (Bases.empty() && !Other.Bases.empty())
517 Bases = deepCopyArray(Other.Bases, getPersistentArena());
518 if (Parents.empty() && !Other.Parents.empty())
519 Parents = allocateArray(Other.Parents, getPersistentArena());
520 if (VirtualParents.empty() && !Other.VirtualParents.empty())
521 VirtualParents = allocateArray(Other.VirtualParents, getPersistentArena());
522 if (Friends.empty() && !Other.Friends.empty())
523 Friends = deepCopyArray(Other.Friends, getPersistentArena());
524 // Reduce children if necessary.
525 reduceChildren(Children.Records, std::move(Other.Children.Records));
526 reduceChildren(Children.Functions, std::move(Other.Children.Functions));
527 reduceChildren(Children.Enums, std::move(Other.Children.Enums));
528 reduceChildren(Children.Typedefs, std::move(Other.Children.Typedefs));
529 if (!Template && Other.Template)
530 Template = TemplateInfo(*Other.Template, getPersistentArena());
531 SymbolInfo::merge(std::move(Other));
532}
533
535 llvm::BumpPtrAllocator &Arena)
536 : Name(Other.Name), Value(Other.Value), ValueExpr(Other.ValueExpr) {
537 if (!Other.Description.empty()) {
538 for (const auto &Desc : Other.Description) {
539 CommentInfo *NewDesc = allocatePtr<CommentInfo>(Arena, Desc, Arena);
540 Description.push_back(*allocateListNode<CommentInfo>(Arena, NewDesc));
541 }
542 }
543}
544
546 assert(mergeable(Other));
547 if (!Scoped)
548 Scoped = Other.Scoped;
549 if (!BaseType && Other.BaseType)
550 BaseType = std::move(Other.BaseType);
551 if (Members.empty() && !Other.Members.empty())
552 Members = deepCopyArray(Other.Members, getPersistentArena());
553 SymbolInfo::merge(std::move(Other));
554}
555
557 assert(mergeable(Other));
558 if (!IsMethod)
559 IsMethod = Other.IsMethod;
560 if (!Access)
561 Access = Other.Access;
562 if (ReturnType.Type.USR == EmptySID && ReturnType.Type.Name == "")
563 ReturnType = std::move(Other.ReturnType);
564 if (Parent.USR == EmptySID && Parent.Name == "")
565 Parent = std::move(Other.Parent);
566 if (Params.empty() && !Other.Params.empty())
567 Params = allocateArray(Other.Params, getPersistentArena());
568 if (!Template && Other.Template)
569 Template = TemplateInfo(*Other.Template, getPersistentArena());
570 SymbolInfo::merge(std::move(Other));
571}
572
574 assert(mergeable(Other));
575 if (!IsUsing)
576 IsUsing = Other.IsUsing;
577 if (Underlying.Type.Name == "")
578 Underlying = Other.Underlying;
579 if (!Template && Other.Template)
580 Template = TemplateInfo(*Other.Template, getPersistentArena());
581 SymbolInfo::merge(std::move(Other));
582}
583
585 assert(mergeable(Other));
586 if (!IsType)
587 IsType = Other.IsType;
588 if (ConstraintExpression.empty())
589 ConstraintExpression = std::move(Other.ConstraintExpression);
590 if (Template.Constraints.empty() && !Other.Template.Constraints.empty())
591 Template.Constraints =
592 allocateArray(Other.Template.Constraints, getPersistentArena());
593 if (Template.Params.empty() && !Other.Template.Params.empty())
594 Template.Params =
595 allocateArray(Other.Template.Params, getPersistentArena());
596 SymbolInfo::merge(std::move(Other));
597}
598
599void VarInfo::merge(VarInfo &&Other) {
600 assert(mergeable(Other));
601 if (!IsStatic)
602 IsStatic = Other.IsStatic;
603 if (Type.Type.USR == EmptySID && Type.Type.Name == "")
604 Type = std::move(Other.Type);
605 SymbolInfo::merge(std::move(Other));
606}
607
609
611 llvm::BumpPtrAllocator &Arena)
612 : RecordInfo(Other, Arena), Access(Other.Access),
613 IsVirtual(Other.IsVirtual), IsParent(Other.IsParent) {}
614
616 bool IsVirtual, AccessSpecifier Access,
617 bool IsParent)
620
621StringRef Info::extractName() const {
622 if (!Name.empty())
623 return Name;
624
625 switch (IT) {
627 // Cover the case where the project contains a base namespace called
628 // 'GlobalNamespace' (i.e. a namespace at the same level as the global
629 // namespace, which would conflict with the hard-coded global namespace name
630 // below.)
631 if (Name == "GlobalNamespace" && Namespace.empty())
632 return "@GlobalNamespace";
633 // The case of anonymous namespaces is taken care of in serialization,
634 // so here we can safely assume an unnamed namespace is the global
635 // one.
636 return "GlobalNamespace";
638 return internString("@nonymous_record_" + toHex(llvm::toStringRef(USR)));
640 return internString("@nonymous_enum_" + toHex(llvm::toStringRef(USR)));
642 return internString("@nonymous_typedef_" + toHex(llvm::toStringRef(USR)));
644 return internString("@nonymous_function_" + toHex(llvm::toStringRef(USR)));
646 return internString("@nonymous_concept_" + toHex(llvm::toStringRef(USR)));
648 return internString("@nonymous_variable_" + toHex(llvm::toStringRef(USR)));
650 return internString("@nonymous_friend_" + toHex(llvm::toStringRef(USR)));
652 return internString("@nonymous_" + toHex(llvm::toStringRef(USR)));
653 }
654 llvm_unreachable("Invalid InfoType.");
655 return "";
656}
657
658// Order is based on the Name attribute: case insensitive order
659bool Index::operator<(const Index &Other) const {
660 // Start with case-insensitive (e.g., 'apple' < 'Zebra').
661 // This prevents 'Zebra' from appearing before 'apple' due to ASCII values,
662 // where uppercase letters have a lower numeric value than lowercase.
663 int Cmp = Name.compare_insensitive(Other.Name);
664 if (Cmp != 0)
665 return Cmp < 0;
666
667 // If names are identical, we fall back to standard string comparison where
668 // uppercase precedes lowercase (e.g., 'Apple' < 'apple').
669 return Name < Other.Name;
670}
671
672std::vector<const Index *> Index::getSortedChildren() const {
673 std::vector<const Index *> SortedChildren;
674 SortedChildren.reserve(Children.size());
675 for (const auto &[_, C] : Children)
676 SortedChildren.push_back(&C);
677 llvm::sort(SortedChildren,
678 [](const Index *A, const Index *B) { return *A < *B; });
679 return SortedChildren;
680}
681
683 for (auto &[_, C] : Children)
684 C.sort();
685}
686
688 tooling::ExecutionContext *ECtx, StringRef ProjectName, bool PublicOnly,
689 StringRef OutDirectory, StringRef SourceRoot, StringRef RepositoryUrl,
690 StringRef RepositoryLinePrefix, StringRef Base,
691 std::vector<std::string> UserStylesheets, clang::DiagnosticsEngine &Diags,
697 llvm::SmallString<128> SourceRootDir(SourceRoot);
698 if (SourceRoot.empty())
699 // If no SourceRoot was provided the current path is used as the default
700 llvm::sys::fs::current_path(SourceRootDir);
701 this->SourceRoot = std::string(SourceRootDir);
702 if (!RepositoryUrl.empty()) {
703 this->RepositoryUrl = std::string(RepositoryUrl);
704 if (!RepositoryUrl.empty() && !RepositoryUrl.starts_with("http://") &&
705 !RepositoryUrl.starts_with("https://"))
706 this->RepositoryUrl->insert(0, "https://");
707
708 if (!RepositoryLinePrefix.empty())
709 this->RepositoryLinePrefix = std::string(RepositoryLinePrefix);
710 }
711}
712
714 Namespaces.sort();
715 Records.sort();
716 Functions.sort();
717 Enums.sort();
718 Typedefs.sort();
719 Concepts.sort();
720 Variables.sort();
721}
722} // namespace doc
723} // namespace clang
static llvm::Error mergeTypedInfo(Info *&Reduced, Info *NewInfo, llvm::BumpPtrAllocator &Arena)
T * allocatePtr(llvm::BumpPtrAllocator &Alloc, Args &&...args)
void reduceChildren< Reference >(DocList< Reference > &Children, DocList< Reference > &&ChildrenToMerge)
static void mergeUnkeyed(DocList< T > &Target, DocList< T > &&Source)
static llvm::SmallString< 64 > calculateRelativeFilePath(const InfoType &Type, const StringRef &Path, const StringRef &Name, const StringRef &CurrentPath)
llvm::simple_ilist< InfoNode< T > > DocList
llvm::BumpPtrAllocator & getPersistentArena()
T * allocateTransient(Args &&...args)
void mergeUnkeyed< CommentInfo >(DocList< CommentInfo > &Target, DocList< CommentInfo > &&Source)
ConcurrentStringPool & getGlobalStringPool()
CommentKind stringToCommentKind(llvm::StringRef KindStr)
llvm::ArrayRef< T > deepCopyArray(llvm::ArrayRef< T > V, llvm::BumpPtrAllocator &Alloc)
InfoNode< T > * allocateListNodePersistent(Args &&...args)
InfoNode< T > * allocateListNode(llvm::BumpPtrAllocator &Alloc, Args &&...args)
StringRef internString(const Twine &T)
llvm::ArrayRef< T > allocateArray(llvm::SmallVectorImpl< T > &V, llvm::BumpPtrAllocator &Alloc)
llvm::Expected< Info * > mergeInfos(SmallVectorImpl< Info * > &Values)
static void reduceChildren(DocList< T > &Children, DocList< T > &&ChildrenToMerge)
static llvm::Expected< Info * > reduce(SmallVectorImpl< Info * > &Values)
llvm::BumpPtrAllocator & getTransientArena()
std::array< uint8_t, 20 > SymbolID
llvm::StringRef commentKindToString(CommentKind Kind)
llvm::Error mergeSingleInfo(doc::Info *&Reduced, doc::Info *NewInfo, llvm::BumpPtrAllocator &Arena)
const SymbolID EmptySID
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::optional< std::string > RepositoryUrl
std::vector< std::string > UserStylesheets
tooling::ExecutionContext * ECtx
clang::DiagnosticsEngine & Diags
ClangDocContext(tooling::ExecutionContext *ECtx, StringRef ProjectName, bool PublicOnly, StringRef OutDirectory, StringRef SourceRoot, StringRef RepositoryUrl, StringRef RepositoryCodeLinePrefix, StringRef Base, std::vector< std::string > UserStylesheets, clang::DiagnosticsEngine &Diags, OutputFormatTy Format, bool FTimeTrace=false, bool Pretty=false)
std::optional< std::string > RepositoryLinePrefix
ArrayRef< StringRef > Args
bool operator<(const CommentInfo &Other) const
bool operator==(const CommentInfo &Other) const
ArrayRef< CommentInfo > Children
ArrayRef< StringRef > AttrKeys
ArrayRef< StringRef > AttrValues
void merge(ConceptInfo &&I)
llvm::ArrayRef< EnumValueInfo > Members
void merge(EnumInfo &&I)
std::optional< TypeInfo > BaseType
DocList< CommentInfo > Description
Comment description of this field.
EnumValueInfo(StringRef Name=StringRef(), StringRef Value=StringRef("0"), StringRef ValueExpr=StringRef())
std::optional< TypeInfo > ReturnType
void merge(FriendInfo &&Other)
llvm::ArrayRef< FieldTypeInfo > Params
std::optional< TemplateInfo > Template
bool mergeable(const FriendInfo &Other)
FunctionInfo(SymbolID USR=SymbolID())
llvm::ArrayRef< FieldTypeInfo > Params
void merge(FunctionInfo &&I)
std::optional< TemplateInfo > Template
bool operator<(const Index &Other) const
llvm::StringMap< Index > Children
std::vector< const Index * > getSortedChildren() const
A base struct for Infos.
StringRef getRelativeFilePath(const StringRef &CurrentPath) const
Returns the file path for this Info relative to CurrentPath.
Info(InfoType IT=InfoType::IT_default, SymbolID USR=SymbolID(), StringRef Name=StringRef(), StringRef Path=StringRef())
bool mergeable(const Info &Other)
DocList< CommentInfo > Description
llvm::ArrayRef< Reference > Namespace
StringRef extractName() const
StringRef DocumentationFileName
void mergeBase(Info &&I)
StringRef getFileBaseName() const
Returns the basename that should be used for this Info.
DocList< CommentInfo > Description
NamespaceInfo(SymbolID USR=SymbolID(), StringRef Name=StringRef(), StringRef Path=StringRef())
void merge(NamespaceInfo &&I)
llvm::ArrayRef< BaseRecordInfo > Bases
llvm::ArrayRef< FriendInfo > Friends
RecordInfo(SymbolID USR=SymbolID(), StringRef Name=StringRef(), StringRef Path=StringRef())
llvm::ArrayRef< Reference > VirtualParents
std::optional< TemplateInfo > Template
llvm::ArrayRef< Reference > Parents
llvm::ArrayRef< MemberTypeInfo > Members
void merge(RecordInfo &&I)
void merge(Reference &&I)
Reference(SymbolID USR=SymbolID(), StringRef Name=StringRef(), InfoType IT=InfoType::IT_default)
bool mergeable(const Reference &Other)
StringRef getFileBaseName() const
Returns the basename that should be used for this Reference.
StringRef getRelativeFilePath(const StringRef &CurrentPath) const
Returns the path for this Reference relative to CurrentPath.
DocList< Reference > Records
DocList< EnumInfo > Enums
DocList< ConceptInfo > Concepts
DocList< VarInfo > Variables
DocList< FunctionInfo > Functions
DocList< Reference > Namespaces
DocList< TypedefInfo > Typedefs
SymbolInfo(InfoType IT, SymbolID USR=SymbolID(), StringRef Name=StringRef(), StringRef Path=StringRef())
DocList< Location > Loc
std::optional< Location > DefLoc
llvm::ArrayRef< TemplateParamInfo > Params
llvm::ArrayRef< ConstraintInfo > Constraints
std::optional< TemplateSpecializationInfo > Specialization
llvm::ArrayRef< TemplateParamInfo > Params
void merge(TypedefInfo &&I)
std::optional< TemplateInfo > Template
TypedefInfo(SymbolID USR=SymbolID())
void merge(VarInfo &&I)