clang-tools  14.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/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::createStringError(llvm::inconvertibleErrorCode(),
38  "no value to reduce");
39  std::unique_ptr<Info> Merged = std::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 void reduceChildren(std::vector<Reference> &Children,
58  std::vector<Reference> &&ChildrenToMerge) {
59  for (auto &ChildToMerge : ChildrenToMerge) {
60  int mergeIdx = getChildIndexIfExists(Children, ChildToMerge);
61  if (mergeIdx == -1) {
62  Children.push_back(std::move(ChildToMerge));
63  continue;
64  }
65  Children[mergeIdx].merge(std::move(ChildToMerge));
66  }
67 }
68 
69 void reduceChildren(std::vector<FunctionInfo> &Children,
70  std::vector<FunctionInfo> &&ChildrenToMerge) {
71  for (auto &ChildToMerge : ChildrenToMerge) {
72  int mergeIdx = getChildIndexIfExists(Children, ChildToMerge);
73  if (mergeIdx == -1) {
74  Children.push_back(std::move(ChildToMerge));
75  continue;
76  }
77  Children[mergeIdx].merge(std::move(ChildToMerge));
78  }
79 }
80 
81 void reduceChildren(std::vector<EnumInfo> &Children,
82  std::vector<EnumInfo> &&ChildrenToMerge) {
83  for (auto &ChildToMerge : ChildrenToMerge) {
84  int mergeIdx = getChildIndexIfExists(Children, ChildToMerge);
85  if (mergeIdx == -1) {
86  Children.push_back(std::move(ChildToMerge));
87  continue;
88  }
89  Children[mergeIdx].merge(std::move(ChildToMerge));
90  }
91 }
92 
93 } // namespace
94 
95 // Dispatch function.
96 llvm::Expected<std::unique_ptr<Info>>
97 mergeInfos(std::vector<std::unique_ptr<Info>> &Values) {
98  if (Values.empty())
99  return llvm::createStringError(llvm::inconvertibleErrorCode(),
100  "no info values to merge");
101 
102  switch (Values[0]->IT) {
104  return reduce<NamespaceInfo>(Values);
105  case InfoType::IT_record:
106  return reduce<RecordInfo>(Values);
107  case InfoType::IT_enum:
108  return reduce<EnumInfo>(Values);
110  return reduce<FunctionInfo>(Values);
111  default:
112  return llvm::createStringError(llvm::inconvertibleErrorCode(),
113  "unexpected info type");
114  }
115 }
116 
117 static llvm::SmallString<64>
118 calculateRelativeFilePath(const InfoType &Type, const StringRef &Path,
119  const StringRef &Name, const StringRef &CurrentPath) {
120  llvm::SmallString<64> FilePath;
121 
122  if (CurrentPath != Path) {
123  // iterate back to the top
124  for (llvm::sys::path::const_iterator I =
125  llvm::sys::path::begin(CurrentPath);
126  I != llvm::sys::path::end(CurrentPath); ++I)
127  llvm::sys::path::append(FilePath, "..");
128  llvm::sys::path::append(FilePath, Path);
129  }
130 
131  // Namespace references have a Path to the parent namespace, but
132  // the file is actually in the subdirectory for the namespace.
134  llvm::sys::path::append(FilePath, Name);
135 
136  return llvm::sys::path::relative_path(FilePath);
137 }
138 
139 llvm::SmallString<64>
140 Reference::getRelativeFilePath(const StringRef &CurrentPath) const {
141  return calculateRelativeFilePath(RefType, Path, Name, CurrentPath);
142 }
143 
144 llvm::SmallString<16> Reference::getFileBaseName() const {
146  return llvm::SmallString<16>("index");
147 
148  return Name;
149 }
150 
151 llvm::SmallString<64>
152 Info::getRelativeFilePath(const StringRef &CurrentPath) const {
153  return calculateRelativeFilePath(IT, Path, extractName(), CurrentPath);
154 }
155 
156 llvm::SmallString<16> Info::getFileBaseName() const {
157  if (IT == InfoType::IT_namespace)
158  return llvm::SmallString<16>("index");
159 
160  return extractName();
161 }
162 
163 bool Reference::mergeable(const Reference &Other) {
164  return RefType == Other.RefType && USR == Other.USR;
165 }
166 
168  assert(mergeable(Other));
169  if (Name.empty())
170  Name = Other.Name;
171  if (Path.empty())
172  Path = Other.Path;
173  if (!IsInGlobalNamespace)
174  IsInGlobalNamespace = Other.IsInGlobalNamespace;
175 }
176 
177 void Info::mergeBase(Info &&Other) {
178  assert(mergeable(Other));
179  if (USR == EmptySID)
180  USR = Other.USR;
181  if (Name == "")
182  Name = Other.Name;
183  if (Path == "")
184  Path = Other.Path;
185  if (Namespace.empty())
186  Namespace = std::move(Other.Namespace);
187  // Unconditionally extend the description, since each decl may have a comment.
188  std::move(Other.Description.begin(), Other.Description.end(),
189  std::back_inserter(Description));
190  llvm::sort(Description);
191  auto Last = std::unique(Description.begin(), Description.end());
192  Description.erase(Last, Description.end());
193 }
194 
195 bool Info::mergeable(const Info &Other) {
196  return IT == Other.IT && USR == Other.USR;
197 }
198 
200  assert(mergeable(Other));
201  if (!DefLoc)
202  DefLoc = std::move(Other.DefLoc);
203  // Unconditionally extend the list of locations, since we want all of them.
204  std::move(Other.Loc.begin(), Other.Loc.end(), std::back_inserter(Loc));
205  llvm::sort(Loc);
206  auto Last = std::unique(Loc.begin(), Loc.end());
207  Loc.erase(Last, Loc.end());
208  mergeBase(std::move(Other));
209 }
210 
212  assert(mergeable(Other));
213  // Reduce children if necessary.
214  reduceChildren(ChildNamespaces, std::move(Other.ChildNamespaces));
215  reduceChildren(ChildRecords, std::move(Other.ChildRecords));
216  reduceChildren(ChildFunctions, std::move(Other.ChildFunctions));
217  reduceChildren(ChildEnums, std::move(Other.ChildEnums));
218  mergeBase(std::move(Other));
219 }
220 
222  assert(mergeable(Other));
223  if (!TagType)
224  TagType = Other.TagType;
225  if (Members.empty())
226  Members = std::move(Other.Members);
227  if (Bases.empty())
228  Bases = std::move(Other.Bases);
229  if (Parents.empty())
230  Parents = std::move(Other.Parents);
231  if (VirtualParents.empty())
232  VirtualParents = std::move(Other.VirtualParents);
233  // Reduce children if necessary.
234  reduceChildren(ChildRecords, std::move(Other.ChildRecords));
235  reduceChildren(ChildFunctions, std::move(Other.ChildFunctions));
236  reduceChildren(ChildEnums, std::move(Other.ChildEnums));
237  SymbolInfo::merge(std::move(Other));
238 }
239 
240 void EnumInfo::merge(EnumInfo &&Other) {
241  assert(mergeable(Other));
242  if (!Scoped)
243  Scoped = Other.Scoped;
244  if (Members.empty())
245  Members = std::move(Other.Members);
246  SymbolInfo::merge(std::move(Other));
247 }
248 
250  assert(mergeable(Other));
251  if (!IsMethod)
252  IsMethod = Other.IsMethod;
253  if (!Access)
254  Access = Other.Access;
255  if (ReturnType.Type.USR == EmptySID && ReturnType.Type.Name == "")
256  ReturnType = std::move(Other.ReturnType);
257  if (Parent.USR == EmptySID && Parent.Name == "")
258  Parent = std::move(Other.Parent);
259  if (Params.empty())
260  Params = std::move(Other.Params);
261  SymbolInfo::merge(std::move(Other));
262 }
263 
264 llvm::SmallString<16> Info::extractName() const {
265  if (!Name.empty())
266  return Name;
267 
268  switch (IT) {
270  // Cover the case where the project contains a base namespace called
271  // 'GlobalNamespace' (i.e. a namespace at the same level as the global
272  // namespace, which would conflict with the hard-coded global namespace name
273  // below.)
274  if (Name == "GlobalNamespace" && Namespace.empty())
275  return llvm::SmallString<16>("@GlobalNamespace");
276  // The case of anonymous namespaces is taken care of in serialization,
277  // so here we can safely assume an unnamed namespace is the global
278  // one.
279  return llvm::SmallString<16>("GlobalNamespace");
280  case InfoType::IT_record:
281  return llvm::SmallString<16>("@nonymous_record_" +
282  toHex(llvm::toStringRef(USR)));
283  case InfoType::IT_enum:
284  return llvm::SmallString<16>("@nonymous_enum_" +
285  toHex(llvm::toStringRef(USR)));
287  return llvm::SmallString<16>("@nonymous_function_" +
288  toHex(llvm::toStringRef(USR)));
290  return llvm::SmallString<16>("@nonymous_" + toHex(llvm::toStringRef(USR)));
291  }
292  llvm_unreachable("Invalid InfoType.");
293  return llvm::SmallString<16>("");
294 }
295 
296 // Order is based on the Name attribute: case insensitive order
297 bool Index::operator<(const Index &Other) const {
298  // Loop through each character of both strings
299  for (unsigned I = 0; I < Name.size() && I < Other.Name.size(); ++I) {
300  // Compare them after converting both to lower case
301  int D = tolower(Name[I]) - tolower(Other.Name[I]);
302  if (D == 0)
303  continue;
304  return D < 0;
305  }
306  // If both strings have the size it means they would be equal if changed to
307  // lower case. In here, lower case will be smaller than upper case
308  // Example: string < stRing = true
309  // This is the opposite of how operator < handles strings
310  if (Name.size() == Other.Name.size())
311  return Name > Other.Name;
312  // If they are not the same size; the shorter string is smaller
313  return Name.size() < Other.Name.size();
314 }
315 
316 void Index::sort() {
317  llvm::sort(Children);
318  for (auto &C : Children)
319  C.sort();
320 }
321 
322 ClangDocContext::ClangDocContext(tooling::ExecutionContext *ECtx,
323  StringRef ProjectName, bool PublicOnly,
324  StringRef OutDirectory, StringRef SourceRoot,
325  StringRef RepositoryUrl,
326  std::vector<std::string> UserStylesheets,
327  std::vector<std::string> JsScripts)
328  : ECtx(ECtx), ProjectName(ProjectName), PublicOnly(PublicOnly),
330  JsScripts(JsScripts) {
331  llvm::SmallString<128> SourceRootDir(SourceRoot);
332  if (SourceRoot.empty())
333  // If no SourceRoot was provided the current path is used as the default
334  llvm::sys::fs::current_path(SourceRootDir);
335  this->SourceRoot = std::string(SourceRootDir.str());
336  if (!RepositoryUrl.empty()) {
337  this->RepositoryUrl = std::string(RepositoryUrl);
338  if (!RepositoryUrl.empty() && RepositoryUrl.find("http://") != 0 &&
339  RepositoryUrl.find("https://") != 0)
340  this->RepositoryUrl->insert(0, "https://");
341  }
342 }
343 
344 } // namespace doc
345 } // namespace clang
clang::doc::Info::Description
std::vector< CommentInfo > Description
Definition: Representation.h:262
SourceRoot
static llvm::cl::opt< std::string > SourceRoot("source-root", llvm::cl::desc(R"( Directory where processed files are stored. Links to definition locations will only be generated if the file is in this dir.)"), llvm::cl::cat(ClangDocCategory))
clang::doc::Reference::merge
void merge(Reference &&I)
Definition: Representation.cpp:167
clang::doc::NamespaceInfo::ChildEnums
std::vector< EnumInfo > ChildEnums
Definition: Representation.h:300
clang::doc::Reference::getFileBaseName
llvm::SmallString< 16 > getFileBaseName() const
Returns the basename that should be used for this Reference.
Definition: Representation.cpp:144
clang::doc::InfoType::IT_enum
@ IT_enum
Type
NodeType Type
Definition: HTMLGenerator.cpp:73
clang::doc::Info::mergeBase
void mergeBase(Info &&I)
Definition: Representation.cpp:177
clang::doc::NamespaceInfo::ChildFunctions
std::vector< FunctionInfo > ChildFunctions
Definition: Representation.h:299
clang::doc::Info::Name
SmallString< 16 > Name
Definition: Representation.h:259
clang::doc::Index
Definition: Representation.h:401
clang::doc::InfoType::IT_namespace
@ IT_namespace
clang::doc::FunctionInfo
Definition: Representation.h:319
clang::doc::Reference::Path
llvm::SmallString< 128 > Path
Definition: Representation.h:151
clang::doc::InfoType
InfoType
Definition: Representation.h:37
clang::doc::NamespaceInfo::ChildNamespaces
std::vector< Reference > ChildNamespaces
Definition: Representation.h:297
clang::doc::Reference::Name
SmallString< 16 > Name
Definition: Representation.h:145
clang::doc::InfoType::IT_function
@ IT_function
clang::doc::ClangDocContext::RepositoryUrl
llvm::Optional< std::string > RepositoryUrl
Definition: Representation.h:441
clang::doc::EnumInfo
Definition: Representation.h:390
Representation.h
clang::doc::RecordInfo::VirtualParents
llvm::SmallVector< Reference, 4 > VirtualParents
Definition: Representation.h:359
clang::doc::ClangDocContext::SourceRoot
std::string SourceRoot
Definition: Representation.h:437
RepositoryUrl
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))
clang::doc::RecordInfo::Members
llvm::SmallVector< MemberTypeInfo, 4 > Members
Definition: Representation.h:354
clang::doc::RecordInfo::Bases
std::vector< BaseRecordInfo > Bases
Definition: Representation.h:362
UserStylesheets
static llvm::cl::list< std::string > UserStylesheets("stylesheets", llvm::cl::CommaSeparated, llvm::cl::desc("CSS stylesheets to extend the default styles."), llvm::cl::cat(ClangDocCategory))
clang::doc::Reference::mergeable
bool mergeable(const Reference &Other)
Definition: Representation.cpp:163
clang::doc::Info::Path
llvm::SmallString< 128 > Path
Definition: Representation.h:263
clang::doc::Info::extractName
llvm::SmallString< 16 > extractName() const
Definition: Representation.cpp:264
Children
std::vector< std::unique_ptr< HTMLNode > > Children
Definition: HTMLGenerator.cpp:91
clang::doc::InfoType::IT_record
@ IT_record
clang::doc::FunctionInfo::Parent
Reference Parent
Definition: Representation.h:326
ns1::ns2::D
@ D
Definition: CategoricalFeature.h:3
clang::doc::EnumInfo::Members
llvm::SmallVector< SmallString< 16 >, 4 > Members
Definition: Representation.h:398
clang::doc::EnumInfo::merge
void merge(EnumInfo &&I)
Definition: Representation.cpp:240
PublicOnly
static llvm::cl::opt< bool > PublicOnly("public", llvm::cl::desc("Document only public declarations."), llvm::cl::init(false), llvm::cl::cat(ClangDocCategory))
clang::doc::ClangDocContext::ClangDocContext
ClangDocContext()=default
clang::doc::SymbolInfo::Loc
llvm::SmallVector< Location, 2 > Loc
Definition: Representation.h:314
clang::doc::SymbolInfo::merge
void merge(SymbolInfo &&I)
Definition: Representation.cpp:199
clang::doc::calculateRelativeFilePath
static llvm::SmallString< 64 > calculateRelativeFilePath(const InfoType &Type, const StringRef &Path, const StringRef &Name, const StringRef &CurrentPath)
Definition: Representation.cpp:118
clang::doc::RecordInfo::Parents
llvm::SmallVector< Reference, 4 > Parents
Definition: Representation.h:355
clang::doc::Reference::getRelativeFilePath
llvm::SmallString< 64 > getRelativeFilePath(const StringRef &CurrentPath) const
Returns the path for this Reference relative to CurrentPath.
Definition: Representation.cpp:140
Name
static constexpr llvm::StringLiteral Name
Definition: UppercaseLiteralSuffixCheck.cpp:28
clang::doc::Reference::IsInGlobalNamespace
bool IsInGlobalNamespace
Definition: Representation.h:154
clang::doc::SymbolInfo
Definition: Representation.h:304
clang::doc::Info::USR
SymbolID USR
Definition: Representation.h:256
clang::doc::FunctionInfo::Access
AccessSpecifier Access
Definition: Representation.h:333
clang::doc::FunctionInfo::Params
llvm::SmallVector< FieldTypeInfo, 4 > Params
Definition: Representation.h:328
clang::doc::InfoType::IT_default
@ IT_default
clang::doc::SymbolID
std::array< uint8_t, 20 > SymbolID
Definition: Representation.h:30
clang::doc::RecordInfo
Definition: Representation.h:339
clang::doc::EmptySID
static const SymbolID EmptySID
Definition: BitcodeWriter.cpp:17
OutDirectory
static llvm::cl::opt< std::string > OutDirectory("output", llvm::cl::desc("Directory for outputting generated files."), llvm::cl::init("docs"), llvm::cl::cat(ClangDocCategory))
clang::doc::TypeInfo::Type
Reference Type
Definition: Representation.h:169
clang::doc::RecordInfo::ChildRecords
std::vector< Reference > ChildRecords
Definition: Representation.h:368
clang::doc::Info
A base struct for Infos.
Definition: Representation.h:243
clang::doc::Reference::USR
SymbolID USR
Definition: Representation.h:144
clang::doc::Reference
Definition: Representation.h:115
clang::doc::Info::IT
const InfoType IT
Definition: Representation.h:258
clang::doc::Index::operator<
bool operator<(const Index &Other) const
Definition: Representation.cpp:297
clang::doc::Reference::RefType
InfoType RefType
Definition: Representation.h:146
clang::doc::NamespaceInfo::merge
void merge(NamespaceInfo &&I)
Definition: Representation.cpp:211
C
const Criteria C
Definition: FunctionCognitiveComplexityCheck.cpp:93
clang::doc::RecordInfo::ChildFunctions
std::vector< FunctionInfo > ChildFunctions
Definition: Representation.h:369
clang::doc::FunctionInfo::ReturnType
TypeInfo ReturnType
Definition: Representation.h:327
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::doc::NamespaceInfo
Definition: Representation.h:283
clang::doc::NamespaceInfo::ChildRecords
std::vector< Reference > ChildRecords
Definition: Representation.h:298
clang::doc::FunctionInfo::merge
void merge(FunctionInfo &&I)
Definition: Representation.cpp:249
clang::doc::RecordInfo::merge
void merge(RecordInfo &&I)
Definition: Representation.cpp:221
clang::doc::RecordInfo::TagType
TagTypeKind TagType
Definition: Representation.h:349
ProjectName
static llvm::cl::opt< std::string > ProjectName("project-name", llvm::cl::desc("Name of project."), llvm::cl::cat(ClangDocCategory))
clang::doc::Info::mergeable
bool mergeable(const Info &Other)
Definition: Representation.cpp:195
clang::doc::RecordInfo::ChildEnums
std::vector< EnumInfo > ChildEnums
Definition: Representation.h:370
clang::doc::mergeInfos
llvm::Expected< std::unique_ptr< Info > > mergeInfos(std::vector< std::unique_ptr< Info >> &Values)
Definition: Representation.cpp:97
clang::doc::Index::sort
void sort()
Definition: Representation.cpp:316
clang::doc::SymbolInfo::DefLoc
llvm::Optional< Location > DefLoc
Definition: Representation.h:313
clang::doc::Info::Namespace
llvm::SmallVector< Reference, 4 > Namespace
Definition: Representation.h:261
clang::doc::Info::getRelativeFilePath
llvm::SmallString< 64 > getRelativeFilePath(const StringRef &CurrentPath) const
Returns the file path for this Info relative to CurrentPath.
Definition: Representation.cpp:152
clang::doc::EnumInfo::Scoped
bool Scoped
Definition: Representation.h:396
Path
std::vector< HeaderHandle > Path
Definition: PreprocessorTracker.cpp:525
clang::doc::FunctionInfo::IsMethod
bool IsMethod
Definition: Representation.h:325
clang::doc::Info::getFileBaseName
llvm::SmallString< 16 > getFileBaseName() const
Returns the basename that should be used for this Info.
Definition: Representation.cpp:156
clang::doc::Index::Children
std::vector< Index > Children
Definition: Representation.h:413