clang-tools  9.0.0
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/Support/Error.h"
24 #include "llvm/Support/Path.h"
25 
26 namespace clang {
27 namespace doc {
28 
29 namespace {
30 
31 const SymbolID EmptySID = SymbolID();
32 
33 template <typename T>
34 llvm::Expected<std::unique_ptr<Info>>
35 reduce(std::vector<std::unique_ptr<Info>> &Values) {
36  if (Values.empty())
37  return llvm::make_error<llvm::StringError>(" No values to reduce.\n",
38  llvm::inconvertibleErrorCode());
39  std::unique_ptr<Info> Merged = llvm::make_unique<T>(Values[0]->USR);
40  T *Tmp = static_cast<T *>(Merged.get());
41  for (auto &I : Values)
42  Tmp->merge(std::move(*static_cast<T *>(I.get())));
43  return std::move(Merged);
44 }
45 
46 // Return the index of the matching child in the vector, or -1 if merge is not
47 // necessary.
48 template <typename T>
49 int getChildIndexIfExists(std::vector<T> &Children, T &ChildToMerge) {
50  for (unsigned long I = 0; I < Children.size(); I++) {
51  if (ChildToMerge.USR == Children[I].USR)
52  return I;
53  }
54  return -1;
55 }
56 
57 // For References, we don't need to actually merge them, we just don't want
58 // duplicates.
59 void reduceChildren(std::vector<Reference> &Children,
60  std::vector<Reference> &&ChildrenToMerge) {
61  for (auto &ChildToMerge : ChildrenToMerge) {
62  if (getChildIndexIfExists(Children, ChildToMerge) == -1)
63  Children.push_back(std::move(ChildToMerge));
64  }
65 }
66 
67 void reduceChildren(std::vector<FunctionInfo> &Children,
68  std::vector<FunctionInfo> &&ChildrenToMerge) {
69  for (auto &ChildToMerge : ChildrenToMerge) {
70  int mergeIdx = getChildIndexIfExists(Children, ChildToMerge);
71  if (mergeIdx == -1) {
72  Children.push_back(std::move(ChildToMerge));
73  continue;
74  }
75  Children[mergeIdx].merge(std::move(ChildToMerge));
76  }
77 }
78 
79 void reduceChildren(std::vector<EnumInfo> &Children,
80  std::vector<EnumInfo> &&ChildrenToMerge) {
81  for (auto &ChildToMerge : ChildrenToMerge) {
82  int mergeIdx = getChildIndexIfExists(Children, ChildToMerge);
83  if (mergeIdx == -1) {
84  Children.push_back(std::move(ChildToMerge));
85  continue;
86  }
87  Children[mergeIdx].merge(std::move(ChildToMerge));
88  }
89 }
90 
91 } // namespace
92 
93 // Dispatch function.
94 llvm::Expected<std::unique_ptr<Info>>
95 mergeInfos(std::vector<std::unique_ptr<Info>> &Values) {
96  if (Values.empty())
97  return llvm::make_error<llvm::StringError>("No info values to merge.\n",
98  llvm::inconvertibleErrorCode());
99 
100  switch (Values[0]->IT) {
102  return reduce<NamespaceInfo>(Values);
103  case InfoType::IT_record:
104  return reduce<RecordInfo>(Values);
105  case InfoType::IT_enum:
106  return reduce<EnumInfo>(Values);
108  return reduce<FunctionInfo>(Values);
109  default:
110  return llvm::make_error<llvm::StringError>("Unexpected info type.\n",
111  llvm::inconvertibleErrorCode());
112  }
113 }
114 
115 void Info::mergeBase(Info &&Other) {
116  assert(mergeable(Other));
117  if (USR == EmptySID)
118  USR = Other.USR;
119  if (Name == "")
120  Name = Other.Name;
121  if (Path == "")
122  Path = Other.Path;
123  if (Namespace.empty())
124  Namespace = std::move(Other.Namespace);
125  // Unconditionally extend the description, since each decl may have a comment.
126  std::move(Other.Description.begin(), Other.Description.end(),
127  std::back_inserter(Description));
128  std::sort(Description.begin(), Description.end());
129  auto Last = std::unique(Description.begin(), Description.end());
130  Description.erase(Last, Description.end());
131 }
132 
133 bool Info::mergeable(const Info &Other) {
134  return IT == Other.IT && USR == Other.USR;
135 }
136 
138  assert(mergeable(Other));
139  if (!DefLoc)
140  DefLoc = std::move(Other.DefLoc);
141  // Unconditionally extend the list of locations, since we want all of them.
142  std::move(Other.Loc.begin(), Other.Loc.end(), std::back_inserter(Loc));
143  std::sort(Loc.begin(), Loc.end());
144  auto Last = std::unique(Loc.begin(), Loc.end());
145  Loc.erase(Last, Loc.end());
146  mergeBase(std::move(Other));
147 }
148 
150  assert(mergeable(Other));
151  // Reduce children if necessary.
152  reduceChildren(ChildNamespaces, std::move(Other.ChildNamespaces));
153  reduceChildren(ChildRecords, std::move(Other.ChildRecords));
154  reduceChildren(ChildFunctions, std::move(Other.ChildFunctions));
155  reduceChildren(ChildEnums, std::move(Other.ChildEnums));
156  mergeBase(std::move(Other));
157 }
158 
160  assert(mergeable(Other));
161  if (!TagType)
162  TagType = Other.TagType;
163  if (Members.empty())
164  Members = std::move(Other.Members);
165  if (Parents.empty())
166  Parents = std::move(Other.Parents);
167  if (VirtualParents.empty())
168  VirtualParents = std::move(Other.VirtualParents);
169  // Reduce children if necessary.
170  reduceChildren(ChildRecords, std::move(Other.ChildRecords));
171  reduceChildren(ChildFunctions, std::move(Other.ChildFunctions));
172  reduceChildren(ChildEnums, std::move(Other.ChildEnums));
173  SymbolInfo::merge(std::move(Other));
174 }
175 
176 void EnumInfo::merge(EnumInfo &&Other) {
177  assert(mergeable(Other));
178  if (!Scoped)
179  Scoped = Other.Scoped;
180  if (Members.empty())
181  Members = std::move(Other.Members);
182  SymbolInfo::merge(std::move(Other));
183 }
184 
186  assert(mergeable(Other));
187  if (!IsMethod)
188  IsMethod = Other.IsMethod;
189  if (!Access)
190  Access = Other.Access;
191  if (ReturnType.Type.USR == EmptySID && ReturnType.Type.Name == "")
192  ReturnType = std::move(Other.ReturnType);
193  if (Parent.USR == EmptySID && Parent.Name == "")
194  Parent = std::move(Other.Parent);
195  if (Params.empty())
196  Params = std::move(Other.Params);
197  SymbolInfo::merge(std::move(Other));
198 }
199 
200 llvm::SmallString<16> Info::extractName() {
201  if (!Name.empty())
202  return Name;
203 
204  switch (IT) {
206  // Cover the case where the project contains a base namespace called
207  // 'GlobalNamespace' (i.e. a namespace at the same level as the global
208  // namespace, which would conflict with the hard-coded global namespace name
209  // below.)
210  if (Name == "GlobalNamespace" && Namespace.empty())
211  return llvm::SmallString<16>("@GlobalNamespace");
212  // The case of anonymous namespaces is taken care of in serialization,
213  // so here we can safely assume an unnamed namespace is the global
214  // one.
215  return llvm::SmallString<16>("GlobalNamespace");
216  case InfoType::IT_record:
217  return llvm::SmallString<16>("@nonymous_record_" +
218  toHex(llvm::toStringRef(USR)));
219  case InfoType::IT_enum:
220  return llvm::SmallString<16>("@nonymous_enum_" +
221  toHex(llvm::toStringRef(USR)));
223  return llvm::SmallString<16>("@nonymous_function_" +
224  toHex(llvm::toStringRef(USR)));
226  return llvm::SmallString<16>("@nonymous_" + toHex(llvm::toStringRef(USR)));
227  }
228  llvm_unreachable("Invalid InfoType.");
229  return llvm::SmallString<16>("");
230 }
231 
232 } // namespace doc
233 } // namespace clang
SourceLocation Loc
&#39;#&#39; location in the include directive
llvm::SmallVector< Reference, 4 > Namespace
static const SymbolID EmptySID
llvm::SmallString< 16 > extractName()
void merge(NamespaceInfo &&I)
void merge(EnumInfo &&I)
bool mergeable(const Info &Other)
std::vector< CommentInfo > Description
llvm::Expected< std::unique_ptr< Info > > mergeInfos(std::vector< std::unique_ptr< Info >> &Values)
SmallString< 16 > Name
A base struct for Infos.
std::string ReturnType
llvm::SmallString< 128 > Path
void merge(SymbolInfo &&I)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
void merge(FunctionInfo &&I)
const InfoType IT
std::array< uint8_t, 20 > SymbolID
void merge(RecordInfo &&I)
void mergeBase(Info &&I)