xref: /llvm-project/clang-tools-extra/clang-doc/Representation.cpp (revision 5ef2456a438578b0783241a2744efc62d47e5ab6)
1d0f9a872SJulie Hockett ///===-- Representation.cpp - ClangDoc Representation -----------*- C++ -*-===//
2d0f9a872SJulie Hockett //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d0f9a872SJulie Hockett //
7d0f9a872SJulie Hockett //===----------------------------------------------------------------------===//
8d0f9a872SJulie Hockett //
9d0f9a872SJulie Hockett // This file defines the merging of different types of infos. The data in the
10d0f9a872SJulie Hockett // calling Info is preserved during a merge unless that field is empty or
11d0f9a872SJulie Hockett // default. In that case, the data from the parameter Info is used to replace
12d0f9a872SJulie Hockett // the empty or default data.
13d0f9a872SJulie Hockett //
14d0f9a872SJulie Hockett // For most fields, the first decl seen provides the data. Exceptions to this
15d0f9a872SJulie Hockett // include the location and description fields, which are collections of data on
16d0f9a872SJulie Hockett // all decls related to a given definition. All other fields are ignored in new
17d0f9a872SJulie Hockett // decls unless the first seen decl didn't, for whatever reason, incorporate
18d0f9a872SJulie Hockett // data on that field (e.g. a forward declared class wouldn't have information
19d0f9a872SJulie Hockett // on members on the forward declaration, but would have the class name).
20d0f9a872SJulie Hockett //
21d0f9a872SJulie Hockett //===----------------------------------------------------------------------===//
22d0f9a872SJulie Hockett #include "Representation.h"
23d0f9a872SJulie Hockett #include "llvm/Support/Error.h"
24d900ef0aSJulie Hockett #include "llvm/Support/Path.h"
25d0f9a872SJulie Hockett 
26d0f9a872SJulie Hockett namespace clang {
27d0f9a872SJulie Hockett namespace doc {
28d0f9a872SJulie Hockett 
298899c29bSJulie Hockett namespace {
308899c29bSJulie Hockett 
318899c29bSJulie Hockett const SymbolID EmptySID = SymbolID();
32d0f9a872SJulie Hockett 
33d0f9a872SJulie Hockett template <typename T>
348899c29bSJulie Hockett llvm::Expected<std::unique_ptr<Info>>
358899c29bSJulie Hockett reduce(std::vector<std::unique_ptr<Info>> &Values) {
3630360d88SPaul Kirth   if (Values.empty() || !Values[0])
3718038065SFangrui Song     return llvm::createStringError(llvm::inconvertibleErrorCode(),
3818038065SFangrui Song                                    "no value to reduce");
391c705d9cSJonas Devlieghere   std::unique_ptr<Info> Merged = std::make_unique<T>(Values[0]->USR);
40d0f9a872SJulie Hockett   T *Tmp = static_cast<T *>(Merged.get());
41d0f9a872SJulie Hockett   for (auto &I : Values)
42d0f9a872SJulie Hockett     Tmp->merge(std::move(*static_cast<T *>(I.get())));
438899c29bSJulie Hockett   return std::move(Merged);
44d0f9a872SJulie Hockett }
45d0f9a872SJulie Hockett 
468899c29bSJulie Hockett // Return the index of the matching child in the vector, or -1 if merge is not
478899c29bSJulie Hockett // necessary.
488899c29bSJulie Hockett template <typename T>
498899c29bSJulie Hockett int getChildIndexIfExists(std::vector<T> &Children, T &ChildToMerge) {
508899c29bSJulie Hockett   for (unsigned long I = 0; I < Children.size(); I++) {
518899c29bSJulie Hockett     if (ChildToMerge.USR == Children[I].USR)
528899c29bSJulie Hockett       return I;
538899c29bSJulie Hockett   }
548899c29bSJulie Hockett   return -1;
558899c29bSJulie Hockett }
568899c29bSJulie Hockett 
579470de65SPaul Kirth template <typename T>
589470de65SPaul Kirth void reduceChildren(std::vector<T> &Children,
599470de65SPaul Kirth                     std::vector<T> &&ChildrenToMerge) {
608899c29bSJulie Hockett   for (auto &ChildToMerge : ChildrenToMerge) {
619470de65SPaul Kirth     int MergeIdx = getChildIndexIfExists(Children, ChildToMerge);
629470de65SPaul Kirth     if (MergeIdx == -1) {
638899c29bSJulie Hockett       Children.push_back(std::move(ChildToMerge));
64e27f778aSDiego Astiazaran       continue;
65e27f778aSDiego Astiazaran     }
669470de65SPaul Kirth     Children[MergeIdx].merge(std::move(ChildToMerge));
6721fb70c6SBrett Wilson   }
6821fb70c6SBrett Wilson }
6921fb70c6SBrett Wilson 
708899c29bSJulie Hockett } // namespace
718899c29bSJulie Hockett 
72d0f9a872SJulie Hockett // Dispatch function.
73d0f9a872SJulie Hockett llvm::Expected<std::unique_ptr<Info>>
74d0f9a872SJulie Hockett mergeInfos(std::vector<std::unique_ptr<Info>> &Values) {
7530360d88SPaul Kirth   if (Values.empty() || !Values[0])
7618038065SFangrui Song     return llvm::createStringError(llvm::inconvertibleErrorCode(),
7718038065SFangrui Song                                    "no info values to merge");
78d0f9a872SJulie Hockett 
79d0f9a872SJulie Hockett   switch (Values[0]->IT) {
80d0f9a872SJulie Hockett   case InfoType::IT_namespace:
81d0f9a872SJulie Hockett     return reduce<NamespaceInfo>(Values);
82d0f9a872SJulie Hockett   case InfoType::IT_record:
83d0f9a872SJulie Hockett     return reduce<RecordInfo>(Values);
84d0f9a872SJulie Hockett   case InfoType::IT_enum:
85d0f9a872SJulie Hockett     return reduce<EnumInfo>(Values);
86d0f9a872SJulie Hockett   case InfoType::IT_function:
87d0f9a872SJulie Hockett     return reduce<FunctionInfo>(Values);
8821fb70c6SBrett Wilson   case InfoType::IT_typedef:
8921fb70c6SBrett Wilson     return reduce<TypedefInfo>(Values);
90d0f9a872SJulie Hockett   default:
9118038065SFangrui Song     return llvm::createStringError(llvm::inconvertibleErrorCode(),
9218038065SFangrui Song                                    "unexpected info type");
93d0f9a872SJulie Hockett   }
94d0f9a872SJulie Hockett }
95d0f9a872SJulie Hockett 
96f88c6b91SJens Massberg bool CommentInfo::operator==(const CommentInfo &Other) const {
97f88c6b91SJens Massberg   auto FirstCI = std::tie(Kind, Text, Name, Direction, ParamName, CloseName,
98f88c6b91SJens Massberg                           SelfClosing, Explicit, AttrKeys, AttrValues, Args);
99f88c6b91SJens Massberg   auto SecondCI =
100f88c6b91SJens Massberg       std::tie(Other.Kind, Other.Text, Other.Name, Other.Direction,
101f88c6b91SJens Massberg                Other.ParamName, Other.CloseName, Other.SelfClosing,
102f88c6b91SJens Massberg                Other.Explicit, Other.AttrKeys, Other.AttrValues, Other.Args);
103f88c6b91SJens Massberg 
104f88c6b91SJens Massberg   if (FirstCI != SecondCI || Children.size() != Other.Children.size())
105f88c6b91SJens Massberg     return false;
106f88c6b91SJens Massberg 
107f88c6b91SJens Massberg   return std::equal(Children.begin(), Children.end(), Other.Children.begin(),
108f88c6b91SJens Massberg                     llvm::deref<std::equal_to<>>{});
109f88c6b91SJens Massberg }
110f88c6b91SJens Massberg 
111f88c6b91SJens Massberg bool CommentInfo::operator<(const CommentInfo &Other) const {
112f88c6b91SJens Massberg   auto FirstCI = std::tie(Kind, Text, Name, Direction, ParamName, CloseName,
113f88c6b91SJens Massberg                           SelfClosing, Explicit, AttrKeys, AttrValues, Args);
114f88c6b91SJens Massberg   auto SecondCI =
115f88c6b91SJens Massberg       std::tie(Other.Kind, Other.Text, Other.Name, Other.Direction,
116f88c6b91SJens Massberg                Other.ParamName, Other.CloseName, Other.SelfClosing,
117f88c6b91SJens Massberg                Other.Explicit, Other.AttrKeys, Other.AttrValues, Other.Args);
118f88c6b91SJens Massberg 
119f88c6b91SJens Massberg   if (FirstCI < SecondCI)
120f88c6b91SJens Massberg     return true;
121f88c6b91SJens Massberg 
122f88c6b91SJens Massberg   if (FirstCI == SecondCI) {
123f88c6b91SJens Massberg     return std::lexicographical_compare(
124f88c6b91SJens Massberg         Children.begin(), Children.end(), Other.Children.begin(),
125f88c6b91SJens Massberg         Other.Children.end(), llvm::deref<std::less<>>());
126f88c6b91SJens Massberg   }
127f88c6b91SJens Massberg 
128f88c6b91SJens Massberg   return false;
129f88c6b91SJens Massberg }
130f88c6b91SJens Massberg 
1317003f64cSPetr Hosek static llvm::SmallString<64>
1327003f64cSPetr Hosek calculateRelativeFilePath(const InfoType &Type, const StringRef &Path,
1337003f64cSPetr Hosek                           const StringRef &Name, const StringRef &CurrentPath) {
1347003f64cSPetr Hosek   llvm::SmallString<64> FilePath;
1357003f64cSPetr Hosek 
1367003f64cSPetr Hosek   if (CurrentPath != Path) {
1377003f64cSPetr Hosek     // iterate back to the top
1387003f64cSPetr Hosek     for (llvm::sys::path::const_iterator I =
1397003f64cSPetr Hosek              llvm::sys::path::begin(CurrentPath);
1407003f64cSPetr Hosek          I != llvm::sys::path::end(CurrentPath); ++I)
1417003f64cSPetr Hosek       llvm::sys::path::append(FilePath, "..");
1427003f64cSPetr Hosek     llvm::sys::path::append(FilePath, Path);
1437003f64cSPetr Hosek   }
1447003f64cSPetr Hosek 
1457003f64cSPetr Hosek   // Namespace references have a Path to the parent namespace, but
1467003f64cSPetr Hosek   // the file is actually in the subdirectory for the namespace.
1477003f64cSPetr Hosek   if (Type == doc::InfoType::IT_namespace)
1487003f64cSPetr Hosek     llvm::sys::path::append(FilePath, Name);
1497003f64cSPetr Hosek 
1507003f64cSPetr Hosek   return llvm::sys::path::relative_path(FilePath);
1517003f64cSPetr Hosek }
1527003f64cSPetr Hosek 
1537003f64cSPetr Hosek llvm::SmallString<64>
1547003f64cSPetr Hosek Reference::getRelativeFilePath(const StringRef &CurrentPath) const {
1557003f64cSPetr Hosek   return calculateRelativeFilePath(RefType, Path, Name, CurrentPath);
1567003f64cSPetr Hosek }
1577003f64cSPetr Hosek 
1587003f64cSPetr Hosek llvm::SmallString<16> Reference::getFileBaseName() const {
1597003f64cSPetr Hosek   if (RefType == InfoType::IT_namespace)
1607003f64cSPetr Hosek     return llvm::SmallString<16>("index");
1617003f64cSPetr Hosek 
1627003f64cSPetr Hosek   return Name;
1637003f64cSPetr Hosek }
1647003f64cSPetr Hosek 
1657003f64cSPetr Hosek llvm::SmallString<64>
1667003f64cSPetr Hosek Info::getRelativeFilePath(const StringRef &CurrentPath) const {
1677003f64cSPetr Hosek   return calculateRelativeFilePath(IT, Path, extractName(), CurrentPath);
1687003f64cSPetr Hosek }
1697003f64cSPetr Hosek 
1707003f64cSPetr Hosek llvm::SmallString<16> Info::getFileBaseName() const {
1717003f64cSPetr Hosek   if (IT == InfoType::IT_namespace)
1727003f64cSPetr Hosek     return llvm::SmallString<16>("index");
1737003f64cSPetr Hosek 
1747003f64cSPetr Hosek   return extractName();
1757003f64cSPetr Hosek }
1767003f64cSPetr Hosek 
177e27f778aSDiego Astiazaran bool Reference::mergeable(const Reference &Other) {
178e27f778aSDiego Astiazaran   return RefType == Other.RefType && USR == Other.USR;
179e27f778aSDiego Astiazaran }
180e27f778aSDiego Astiazaran 
181e27f778aSDiego Astiazaran void Reference::merge(Reference &&Other) {
182e27f778aSDiego Astiazaran   assert(mergeable(Other));
183e27f778aSDiego Astiazaran   if (Name.empty())
184e27f778aSDiego Astiazaran     Name = Other.Name;
185e27f778aSDiego Astiazaran   if (Path.empty())
186e27f778aSDiego Astiazaran     Path = Other.Path;
187e27f778aSDiego Astiazaran }
188e27f778aSDiego Astiazaran 
189d0f9a872SJulie Hockett void Info::mergeBase(Info &&Other) {
190d0f9a872SJulie Hockett   assert(mergeable(Other));
191d0f9a872SJulie Hockett   if (USR == EmptySID)
192d0f9a872SJulie Hockett     USR = Other.USR;
193d0f9a872SJulie Hockett   if (Name == "")
194d0f9a872SJulie Hockett     Name = Other.Name;
1952c1c9a24SJulie Hockett   if (Path == "")
1962c1c9a24SJulie Hockett     Path = Other.Path;
197d0f9a872SJulie Hockett   if (Namespace.empty())
198d0f9a872SJulie Hockett     Namespace = std::move(Other.Namespace);
199d0f9a872SJulie Hockett   // Unconditionally extend the description, since each decl may have a comment.
200d0f9a872SJulie Hockett   std::move(Other.Description.begin(), Other.Description.end(),
201d0f9a872SJulie Hockett             std::back_inserter(Description));
2024065e921SBenjamin Kramer   llvm::sort(Description);
20393a290fdSJulie Hockett   auto Last = std::unique(Description.begin(), Description.end());
20493a290fdSJulie Hockett   Description.erase(Last, Description.end());
205d0f9a872SJulie Hockett }
206d0f9a872SJulie Hockett 
207d0f9a872SJulie Hockett bool Info::mergeable(const Info &Other) {
2088899c29bSJulie Hockett   return IT == Other.IT && USR == Other.USR;
209d0f9a872SJulie Hockett }
210d0f9a872SJulie Hockett 
211d0f9a872SJulie Hockett void SymbolInfo::merge(SymbolInfo &&Other) {
212d0f9a872SJulie Hockett   assert(mergeable(Other));
213d0f9a872SJulie Hockett   if (!DefLoc)
214d0f9a872SJulie Hockett     DefLoc = std::move(Other.DefLoc);
215d0f9a872SJulie Hockett   // Unconditionally extend the list of locations, since we want all of them.
216d0f9a872SJulie Hockett   std::move(Other.Loc.begin(), Other.Loc.end(), std::back_inserter(Loc));
2174065e921SBenjamin Kramer   llvm::sort(Loc);
21893a290fdSJulie Hockett   auto Last = std::unique(Loc.begin(), Loc.end());
21993a290fdSJulie Hockett   Loc.erase(Last, Loc.end());
220d0f9a872SJulie Hockett   mergeBase(std::move(Other));
221d0f9a872SJulie Hockett }
222d0f9a872SJulie Hockett 
223f88c6b91SJens Massberg NamespaceInfo::NamespaceInfo(SymbolID USR, StringRef Name, StringRef Path)
224f88c6b91SJens Massberg     : Info(InfoType::IT_namespace, USR, Name, Path) {}
225f88c6b91SJens Massberg 
226d0f9a872SJulie Hockett void NamespaceInfo::merge(NamespaceInfo &&Other) {
227d0f9a872SJulie Hockett   assert(mergeable(Other));
2288899c29bSJulie Hockett   // Reduce children if necessary.
22921fb70c6SBrett Wilson   reduceChildren(Children.Namespaces, std::move(Other.Children.Namespaces));
23021fb70c6SBrett Wilson   reduceChildren(Children.Records, std::move(Other.Children.Records));
23121fb70c6SBrett Wilson   reduceChildren(Children.Functions, std::move(Other.Children.Functions));
23221fb70c6SBrett Wilson   reduceChildren(Children.Enums, std::move(Other.Children.Enums));
23321fb70c6SBrett Wilson   reduceChildren(Children.Typedefs, std::move(Other.Children.Typedefs));
234d0f9a872SJulie Hockett   mergeBase(std::move(Other));
235d0f9a872SJulie Hockett }
236d0f9a872SJulie Hockett 
237f88c6b91SJens Massberg RecordInfo::RecordInfo(SymbolID USR, StringRef Name, StringRef Path)
238f88c6b91SJens Massberg     : SymbolInfo(InfoType::IT_record, USR, Name, Path) {}
239f88c6b91SJens Massberg 
240d0f9a872SJulie Hockett void RecordInfo::merge(RecordInfo &&Other) {
241d0f9a872SJulie Hockett   assert(mergeable(Other));
242edd690b0SVlad Serebrennikov   if (!llvm::to_underlying(TagType))
243d0f9a872SJulie Hockett     TagType = Other.TagType;
24468266828SBrett Wilson   IsTypeDef = IsTypeDef || Other.IsTypeDef;
245d0f9a872SJulie Hockett   if (Members.empty())
246d0f9a872SJulie Hockett     Members = std::move(Other.Members);
247ba3d595fSDiego Astiazaran   if (Bases.empty())
248ba3d595fSDiego Astiazaran     Bases = std::move(Other.Bases);
249d0f9a872SJulie Hockett   if (Parents.empty())
250d0f9a872SJulie Hockett     Parents = std::move(Other.Parents);
251d0f9a872SJulie Hockett   if (VirtualParents.empty())
252d0f9a872SJulie Hockett     VirtualParents = std::move(Other.VirtualParents);
2538899c29bSJulie Hockett   // Reduce children if necessary.
25421fb70c6SBrett Wilson   reduceChildren(Children.Records, std::move(Other.Children.Records));
25521fb70c6SBrett Wilson   reduceChildren(Children.Functions, std::move(Other.Children.Functions));
25621fb70c6SBrett Wilson   reduceChildren(Children.Enums, std::move(Other.Children.Enums));
25721fb70c6SBrett Wilson   reduceChildren(Children.Typedefs, std::move(Other.Children.Typedefs));
258d0f9a872SJulie Hockett   SymbolInfo::merge(std::move(Other));
2594a68babdSBrett Wilson   if (!Template)
2604a68babdSBrett Wilson     Template = Other.Template;
261d0f9a872SJulie Hockett }
262d0f9a872SJulie Hockett 
263d0f9a872SJulie Hockett void EnumInfo::merge(EnumInfo &&Other) {
264d0f9a872SJulie Hockett   assert(mergeable(Other));
265d0f9a872SJulie Hockett   if (!Scoped)
266d0f9a872SJulie Hockett     Scoped = Other.Scoped;
267d0f9a872SJulie Hockett   if (Members.empty())
268d0f9a872SJulie Hockett     Members = std::move(Other.Members);
269d0f9a872SJulie Hockett   SymbolInfo::merge(std::move(Other));
270d0f9a872SJulie Hockett }
271d0f9a872SJulie Hockett 
272d0f9a872SJulie Hockett void FunctionInfo::merge(FunctionInfo &&Other) {
273d0f9a872SJulie Hockett   assert(mergeable(Other));
274d0f9a872SJulie Hockett   if (!IsMethod)
275d0f9a872SJulie Hockett     IsMethod = Other.IsMethod;
276d0f9a872SJulie Hockett   if (!Access)
277d0f9a872SJulie Hockett     Access = Other.Access;
278d0f9a872SJulie Hockett   if (ReturnType.Type.USR == EmptySID && ReturnType.Type.Name == "")
279d0f9a872SJulie Hockett     ReturnType = std::move(Other.ReturnType);
280d0f9a872SJulie Hockett   if (Parent.USR == EmptySID && Parent.Name == "")
281d0f9a872SJulie Hockett     Parent = std::move(Other.Parent);
282d0f9a872SJulie Hockett   if (Params.empty())
283d0f9a872SJulie Hockett     Params = std::move(Other.Params);
284d0f9a872SJulie Hockett   SymbolInfo::merge(std::move(Other));
2854a68babdSBrett Wilson   if (!Template)
2864a68babdSBrett Wilson     Template = Other.Template;
287d0f9a872SJulie Hockett }
288d0f9a872SJulie Hockett 
28921fb70c6SBrett Wilson void TypedefInfo::merge(TypedefInfo &&Other) {
29021fb70c6SBrett Wilson   assert(mergeable(Other));
29121fb70c6SBrett Wilson   if (!IsUsing)
29221fb70c6SBrett Wilson     IsUsing = Other.IsUsing;
29321fb70c6SBrett Wilson   if (Underlying.Type.Name == "")
29421fb70c6SBrett Wilson     Underlying = Other.Underlying;
29521fb70c6SBrett Wilson   SymbolInfo::merge(std::move(Other));
29621fb70c6SBrett Wilson }
29721fb70c6SBrett Wilson 
298f88c6b91SJens Massberg BaseRecordInfo::BaseRecordInfo() : RecordInfo() {}
299f88c6b91SJens Massberg 
300f88c6b91SJens Massberg BaseRecordInfo::BaseRecordInfo(SymbolID USR, StringRef Name, StringRef Path,
301f88c6b91SJens Massberg                                bool IsVirtual, AccessSpecifier Access,
302f88c6b91SJens Massberg                                bool IsParent)
303f88c6b91SJens Massberg     : RecordInfo(USR, Name, Path), IsVirtual(IsVirtual), Access(Access),
304f88c6b91SJens Massberg       IsParent(IsParent) {}
305f88c6b91SJens Massberg 
3067dfe0bc3SDiego Astiazaran llvm::SmallString<16> Info::extractName() const {
307d900ef0aSJulie Hockett   if (!Name.empty())
308d900ef0aSJulie Hockett     return Name;
309d900ef0aSJulie Hockett 
310d900ef0aSJulie Hockett   switch (IT) {
311d900ef0aSJulie Hockett   case InfoType::IT_namespace:
312d900ef0aSJulie Hockett     // Cover the case where the project contains a base namespace called
313d900ef0aSJulie Hockett     // 'GlobalNamespace' (i.e. a namespace at the same level as the global
314d900ef0aSJulie Hockett     // namespace, which would conflict with the hard-coded global namespace name
315d900ef0aSJulie Hockett     // below.)
316d900ef0aSJulie Hockett     if (Name == "GlobalNamespace" && Namespace.empty())
317d900ef0aSJulie Hockett       return llvm::SmallString<16>("@GlobalNamespace");
318d900ef0aSJulie Hockett     // The case of anonymous namespaces is taken care of in serialization,
319d900ef0aSJulie Hockett     // so here we can safely assume an unnamed namespace is the global
320d900ef0aSJulie Hockett     // one.
321d900ef0aSJulie Hockett     return llvm::SmallString<16>("GlobalNamespace");
322d900ef0aSJulie Hockett   case InfoType::IT_record:
323d900ef0aSJulie Hockett     return llvm::SmallString<16>("@nonymous_record_" +
324d900ef0aSJulie Hockett                                  toHex(llvm::toStringRef(USR)));
325d900ef0aSJulie Hockett   case InfoType::IT_enum:
326d900ef0aSJulie Hockett     return llvm::SmallString<16>("@nonymous_enum_" +
327d900ef0aSJulie Hockett                                  toHex(llvm::toStringRef(USR)));
32821fb70c6SBrett Wilson   case InfoType::IT_typedef:
32921fb70c6SBrett Wilson     return llvm::SmallString<16>("@nonymous_typedef_" +
33021fb70c6SBrett Wilson                                  toHex(llvm::toStringRef(USR)));
331d900ef0aSJulie Hockett   case InfoType::IT_function:
332d900ef0aSJulie Hockett     return llvm::SmallString<16>("@nonymous_function_" +
333d900ef0aSJulie Hockett                                  toHex(llvm::toStringRef(USR)));
334d900ef0aSJulie Hockett   case InfoType::IT_default:
335d900ef0aSJulie Hockett     return llvm::SmallString<16>("@nonymous_" + toHex(llvm::toStringRef(USR)));
336d900ef0aSJulie Hockett   }
337d900ef0aSJulie Hockett   llvm_unreachable("Invalid InfoType.");
338d900ef0aSJulie Hockett   return llvm::SmallString<16>("");
339d900ef0aSJulie Hockett }
340d900ef0aSJulie Hockett 
341b7bb9fb2SDiego Astiazaran // Order is based on the Name attribute: case insensitive order
342b7bb9fb2SDiego Astiazaran bool Index::operator<(const Index &Other) const {
343b7bb9fb2SDiego Astiazaran   // Loop through each character of both strings
344b7bb9fb2SDiego Astiazaran   for (unsigned I = 0; I < Name.size() && I < Other.Name.size(); ++I) {
345b7bb9fb2SDiego Astiazaran     // Compare them after converting both to lower case
346b7bb9fb2SDiego Astiazaran     int D = tolower(Name[I]) - tolower(Other.Name[I]);
347b7bb9fb2SDiego Astiazaran     if (D == 0)
348b7bb9fb2SDiego Astiazaran       continue;
349b7bb9fb2SDiego Astiazaran     return D < 0;
350b7bb9fb2SDiego Astiazaran   }
351b7bb9fb2SDiego Astiazaran   // If both strings have the size it means they would be equal if changed to
352b7bb9fb2SDiego Astiazaran   // lower case. In here, lower case will be smaller than upper case
353b7bb9fb2SDiego Astiazaran   // Example: string < stRing = true
354b7bb9fb2SDiego Astiazaran   // This is the opposite of how operator < handles strings
355b7bb9fb2SDiego Astiazaran   if (Name.size() == Other.Name.size())
356b7bb9fb2SDiego Astiazaran     return Name > Other.Name;
357b7bb9fb2SDiego Astiazaran   // If they are not the same size; the shorter string is smaller
358b7bb9fb2SDiego Astiazaran   return Name.size() < Other.Name.size();
359b7bb9fb2SDiego Astiazaran }
360b7bb9fb2SDiego Astiazaran 
3617dfe0bc3SDiego Astiazaran void Index::sort() {
3624065e921SBenjamin Kramer   llvm::sort(Children);
3637dfe0bc3SDiego Astiazaran   for (auto &C : Children)
3647dfe0bc3SDiego Astiazaran     C.sort();
3657dfe0bc3SDiego Astiazaran }
3667dfe0bc3SDiego Astiazaran 
367665e9676SDiego Astiazaran ClangDocContext::ClangDocContext(tooling::ExecutionContext *ECtx,
3683550da79SDiego Astiazaran                                  StringRef ProjectName, bool PublicOnly,
3693550da79SDiego Astiazaran                                  StringRef OutDirectory, StringRef SourceRoot,
3703550da79SDiego Astiazaran                                  StringRef RepositoryUrl,
37180d1c6acSPeterChou1                                  std::vector<std::string> UserStylesheets)
3723550da79SDiego Astiazaran     : ECtx(ECtx), ProjectName(ProjectName), PublicOnly(PublicOnly),
37380d1c6acSPeterChou1       OutDirectory(OutDirectory), UserStylesheets(UserStylesheets) {
37477dc05b9SDiego Astiazaran   llvm::SmallString<128> SourceRootDir(SourceRoot);
37577dc05b9SDiego Astiazaran   if (SourceRoot.empty())
37677dc05b9SDiego Astiazaran     // If no SourceRoot was provided the current path is used as the default
37777dc05b9SDiego Astiazaran     llvm::sys::fs::current_path(SourceRootDir);
3782b00d449SKazu Hirata   this->SourceRoot = std::string(SourceRootDir);
379665e9676SDiego Astiazaran   if (!RepositoryUrl.empty()) {
380adcd0268SBenjamin Kramer     this->RepositoryUrl = std::string(RepositoryUrl);
3815232cec8SNicolas van Kempen     if (!RepositoryUrl.empty() && !RepositoryUrl.starts_with("http://") &&
3825232cec8SNicolas van Kempen         !RepositoryUrl.starts_with("https://"))
383665e9676SDiego Astiazaran       this->RepositoryUrl->insert(0, "https://");
384665e9676SDiego Astiazaran   }
385665e9676SDiego Astiazaran }
386665e9676SDiego Astiazaran 
387*3c9e3457SPeterChou1 void ScopeChildren::sort() {
388*3c9e3457SPeterChou1   llvm::sort(Namespaces.begin(), Namespaces.end());
389*3c9e3457SPeterChou1   llvm::sort(Records.begin(), Records.end());
390*3c9e3457SPeterChou1   llvm::sort(Functions.begin(), Functions.end());
391*3c9e3457SPeterChou1   llvm::sort(Enums.begin(), Enums.end());
392*3c9e3457SPeterChou1   llvm::sort(Typedefs.begin(), Typedefs.end());
393*3c9e3457SPeterChou1 }
394d0f9a872SJulie Hockett } // namespace doc
395d0f9a872SJulie Hockett } // namespace clang
396