clang-tools  8.0.0
Serialize.cpp
Go to the documentation of this file.
1 //===-- Serializer.cpp - ClangDoc Serializer --------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "Serialize.h"
11 #include "BitcodeWriter.h"
12 #include "clang/AST/Comment.h"
13 #include "clang/Index/USRGeneration.h"
14 #include "llvm/ADT/Hashing.h"
15 #include "llvm/ADT/StringExtras.h"
16 #include "llvm/Support/SHA1.h"
17 
18 using clang::comments::FullComment;
19 
20 namespace clang {
21 namespace doc {
22 namespace serialize {
23 
24 SymbolID hashUSR(llvm::StringRef USR) {
25  return llvm::SHA1::hash(arrayRefFromStringRef(USR));
26 }
27 
29  : public ConstCommentVisitor<ClangDocCommentVisitor> {
30 public:
31  ClangDocCommentVisitor(CommentInfo &CI) : CurrentCI(CI) {}
32 
33  void parseComment(const comments::Comment *C);
34 
35  void visitTextComment(const TextComment *C);
36  void visitInlineCommandComment(const InlineCommandComment *C);
37  void visitHTMLStartTagComment(const HTMLStartTagComment *C);
38  void visitHTMLEndTagComment(const HTMLEndTagComment *C);
39  void visitBlockCommandComment(const BlockCommandComment *C);
40  void visitParamCommandComment(const ParamCommandComment *C);
41  void visitTParamCommandComment(const TParamCommandComment *C);
42  void visitVerbatimBlockComment(const VerbatimBlockComment *C);
43  void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
44  void visitVerbatimLineComment(const VerbatimLineComment *C);
45 
46 private:
47  std::string getCommandName(unsigned CommandID) const;
48  bool isWhitespaceOnly(StringRef S) const;
49 
50  CommentInfo &CurrentCI;
51 };
52 
53 void ClangDocCommentVisitor::parseComment(const comments::Comment *C) {
54  CurrentCI.Kind = C->getCommentKindName();
56  for (comments::Comment *Child :
57  llvm::make_range(C->child_begin(), C->child_end())) {
58  CurrentCI.Children.emplace_back(llvm::make_unique<CommentInfo>());
59  ClangDocCommentVisitor Visitor(*CurrentCI.Children.back());
60  Visitor.parseComment(Child);
61  }
62 }
63 
64 void ClangDocCommentVisitor::visitTextComment(const TextComment *C) {
65  if (!isWhitespaceOnly(C->getText()))
66  CurrentCI.Text = C->getText();
67 }
68 
70  const InlineCommandComment *C) {
71  CurrentCI.Name = getCommandName(C->getCommandID());
72  for (unsigned I = 0, E = C->getNumArgs(); I != E; ++I)
73  CurrentCI.Args.push_back(C->getArgText(I));
74 }
75 
77  const HTMLStartTagComment *C) {
78  CurrentCI.Name = C->getTagName();
79  CurrentCI.SelfClosing = C->isSelfClosing();
80  for (unsigned I = 0, E = C->getNumAttrs(); I < E; ++I) {
81  const HTMLStartTagComment::Attribute &Attr = C->getAttr(I);
82  CurrentCI.AttrKeys.push_back(Attr.Name);
83  CurrentCI.AttrValues.push_back(Attr.Value);
84  }
85 }
86 
88  const HTMLEndTagComment *C) {
89  CurrentCI.Name = C->getTagName();
90  CurrentCI.SelfClosing = true;
91 }
92 
94  const BlockCommandComment *C) {
95  CurrentCI.Name = getCommandName(C->getCommandID());
96  for (unsigned I = 0, E = C->getNumArgs(); I < E; ++I)
97  CurrentCI.Args.push_back(C->getArgText(I));
98 }
99 
101  const ParamCommandComment *C) {
102  CurrentCI.Direction =
103  ParamCommandComment::getDirectionAsString(C->getDirection());
104  CurrentCI.Explicit = C->isDirectionExplicit();
105  if (C->hasParamName())
106  CurrentCI.ParamName = C->getParamNameAsWritten();
107 }
108 
110  const TParamCommandComment *C) {
111  if (C->hasParamName())
112  CurrentCI.ParamName = C->getParamNameAsWritten();
113 }
114 
116  const VerbatimBlockComment *C) {
117  CurrentCI.Name = getCommandName(C->getCommandID());
118  CurrentCI.CloseName = C->getCloseName();
119 }
120 
122  const VerbatimBlockLineComment *C) {
123  if (!isWhitespaceOnly(C->getText()))
124  CurrentCI.Text = C->getText();
125 }
126 
128  const VerbatimLineComment *C) {
129  if (!isWhitespaceOnly(C->getText()))
130  CurrentCI.Text = C->getText();
131 }
132 
133 bool ClangDocCommentVisitor::isWhitespaceOnly(llvm::StringRef S) const {
134  return std::all_of(S.begin(), S.end(), isspace);
135 }
136 
137 std::string ClangDocCommentVisitor::getCommandName(unsigned CommandID) const {
138  const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID);
139  if (Info)
140  return Info->Name;
141  // TODO: Add parsing for \file command.
142  return "<not a builtin command>";
143 }
144 
145 // Serializing functions.
146 
147 template <typename T> static std::string serialize(T &I) {
148  SmallString<2048> Buffer;
149  llvm::BitstreamWriter Stream(Buffer);
150  ClangDocBitcodeWriter Writer(Stream);
151  Writer.emitBlock(I);
152  return Buffer.str().str();
153 }
154 
155 std::string serialize(std::unique_ptr<Info> &I) {
156  switch (I->IT) {
158  return serialize(*static_cast<NamespaceInfo *>(I.get()));
159  case InfoType::IT_record:
160  return serialize(*static_cast<RecordInfo *>(I.get()));
161  case InfoType::IT_enum:
162  return serialize(*static_cast<EnumInfo *>(I.get()));
164  return serialize(*static_cast<FunctionInfo *>(I.get()));
165  default:
166  return "";
167  }
168 }
169 
170 static void parseFullComment(const FullComment *C, CommentInfo &CI) {
171  ClangDocCommentVisitor Visitor(CI);
172  Visitor.parseComment(C);
173 }
174 
175 static SymbolID getUSRForDecl(const Decl *D) {
176  llvm::SmallString<128> USR;
177  if (index::generateUSRForDecl(D, USR))
178  return SymbolID();
179  return hashUSR(USR);
180 }
181 
182 static RecordDecl *getDeclForType(const QualType &T) {
183  auto *Ty = T->getAs<RecordType>();
184  if (!Ty)
185  return nullptr;
186  return Ty->getDecl()->getDefinition();
187 }
188 
189 static bool isPublic(const clang::AccessSpecifier AS,
190  const clang::Linkage Link) {
191  if (AS == clang::AccessSpecifier::AS_private)
192  return false;
193  else if ((Link == clang::Linkage::ModuleLinkage) ||
194  (Link == clang::Linkage::ExternalLinkage))
195  return true;
196  return false; // otherwise, linkage is some form of internal linkage
197 }
198 
199 static void parseFields(RecordInfo &I, const RecordDecl *D, bool PublicOnly) {
200  for (const FieldDecl *F : D->fields()) {
201  if (PublicOnly && !isPublic(F->getAccessUnsafe(), F->getLinkageInternal()))
202  continue;
203  if (const auto *T = getDeclForType(F->getTypeSourceInfo()->getType())) {
204  // Use getAccessUnsafe so that we just get the default AS_none if it's not
205  // valid, as opposed to an assert.
206  if (const auto *N = dyn_cast<EnumDecl>(T)) {
207  I.Members.emplace_back(getUSRForDecl(T), N->getNameAsString(),
208  InfoType::IT_enum, F->getNameAsString(),
209  N->getAccessUnsafe());
210  continue;
211  } else if (const auto *N = dyn_cast<RecordDecl>(T)) {
212  I.Members.emplace_back(getUSRForDecl(T), N->getNameAsString(),
213  InfoType::IT_record, F->getNameAsString(),
214  N->getAccessUnsafe());
215  continue;
216  }
217  }
218  I.Members.emplace_back(F->getTypeSourceInfo()->getType().getAsString(),
219  F->getNameAsString(), F->getAccessUnsafe());
220  }
221 }
222 
223 static void parseEnumerators(EnumInfo &I, const EnumDecl *D) {
224  for (const EnumConstantDecl *E : D->enumerators())
225  I.Members.emplace_back(E->getNameAsString());
226 }
227 
228 static void parseParameters(FunctionInfo &I, const FunctionDecl *D) {
229  for (const ParmVarDecl *P : D->parameters()) {
230  if (const auto *T = getDeclForType(P->getOriginalType())) {
231  if (const auto *N = dyn_cast<EnumDecl>(T)) {
232  I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(),
233  InfoType::IT_enum, P->getNameAsString());
234  continue;
235  } else if (const auto *N = dyn_cast<RecordDecl>(T)) {
236  I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(),
237  InfoType::IT_record, P->getNameAsString());
238  continue;
239  }
240  }
241  I.Params.emplace_back(P->getOriginalType().getAsString(),
242  P->getNameAsString());
243  }
244 }
245 
246 static void parseBases(RecordInfo &I, const CXXRecordDecl *D) {
247  // Don't parse bases if this isn't a definition.
248  if (!D->isThisDeclarationADefinition())
249  return;
250  for (const CXXBaseSpecifier &B : D->bases()) {
251  if (B.isVirtual())
252  continue;
253  if (const auto *P = getDeclForType(B.getType()))
254  I.Parents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
256  else
257  I.Parents.emplace_back(B.getType().getAsString());
258  }
259  for (const CXXBaseSpecifier &B : D->vbases()) {
260  if (const auto *P = getDeclForType(B.getType()))
261  I.VirtualParents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
263  else
264  I.VirtualParents.emplace_back(B.getType().getAsString());
265  }
266 }
267 
268 template <typename T>
269 static void
270 populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
271  const T *D) {
272  const auto *DC = dyn_cast<DeclContext>(D);
273  while ((DC = DC->getParent())) {
274  if (const auto *N = dyn_cast<NamespaceDecl>(DC))
275  Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
277  else if (const auto *N = dyn_cast<RecordDecl>(DC))
278  Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
280  else if (const auto *N = dyn_cast<FunctionDecl>(DC))
281  Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
283  else if (const auto *N = dyn_cast<EnumDecl>(DC))
284  Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
286  }
287 }
288 
289 template <typename T>
290 static void populateInfo(Info &I, const T *D, const FullComment *C) {
291  I.USR = getUSRForDecl(D);
292  I.Name = D->getNameAsString();
294  if (C) {
295  I.Description.emplace_back();
296  parseFullComment(C, I.Description.back());
297  }
298 }
299 
300 template <typename T>
301 static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C,
302  int LineNumber, StringRef Filename) {
303  populateInfo(I, D, C);
304  if (D->isThisDeclarationADefinition())
305  I.DefLoc.emplace(LineNumber, Filename);
306  else
307  I.Loc.emplace_back(LineNumber, Filename);
308 }
309 
310 static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
311  const FullComment *FC, int LineNumber,
312  StringRef Filename) {
313  populateSymbolInfo(I, D, FC, LineNumber, Filename);
314  if (const auto *T = getDeclForType(D->getReturnType())) {
315  if (dyn_cast<EnumDecl>(T))
316  I.ReturnType =
317  TypeInfo(getUSRForDecl(T), T->getNameAsString(), InfoType::IT_enum);
318  else if (dyn_cast<RecordDecl>(T))
319  I.ReturnType =
320  TypeInfo(getUSRForDecl(T), T->getNameAsString(), InfoType::IT_record);
321  } else {
322  I.ReturnType = TypeInfo(D->getReturnType().getAsString());
323  }
324  parseParameters(I, D);
325 }
326 
327 std::unique_ptr<Info> emitInfo(const NamespaceDecl *D, const FullComment *FC,
328  int LineNumber, llvm::StringRef File,
329  bool PublicOnly) {
330  if (PublicOnly && ((D->isAnonymousNamespace()) ||
331  !isPublic(D->getAccess(), D->getLinkageInternal())))
332  return nullptr;
333  auto I = llvm::make_unique<NamespaceInfo>();
334  populateInfo(*I, D, FC);
335  return std::unique_ptr<Info>{std::move(I)};
336 }
337 
338 std::unique_ptr<Info> emitInfo(const RecordDecl *D, const FullComment *FC,
339  int LineNumber, llvm::StringRef File,
340  bool PublicOnly) {
341  if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal()))
342  return nullptr;
343  auto I = llvm::make_unique<RecordInfo>();
344  populateSymbolInfo(*I, D, FC, LineNumber, File);
345  I->TagType = D->getTagKind();
346  parseFields(*I, D, PublicOnly);
347  if (const auto *C = dyn_cast<CXXRecordDecl>(D))
348  parseBases(*I, C);
349  return std::unique_ptr<Info>{std::move(I)};
350 }
351 
352 std::unique_ptr<Info> emitInfo(const FunctionDecl *D, const FullComment *FC,
353  int LineNumber, llvm::StringRef File,
354  bool PublicOnly) {
355  if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal()))
356  return nullptr;
357  FunctionInfo Func;
358  populateFunctionInfo(Func, D, FC, LineNumber, File);
359  Func.Access = clang::AccessSpecifier::AS_none;
360 
361  // Wrap in enclosing scope
362  auto I = llvm::make_unique<NamespaceInfo>();
363  if (!Func.Namespace.empty())
364  I->USR = Func.Namespace[0].USR;
365  else
366  I->USR = SymbolID();
367  I->ChildFunctions.emplace_back(std::move(Func));
368  return std::unique_ptr<Info>{std::move(I)};
369 }
370 
371 std::unique_ptr<Info> emitInfo(const CXXMethodDecl *D, const FullComment *FC,
372  int LineNumber, llvm::StringRef File,
373  bool PublicOnly) {
374  if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal()))
375  return nullptr;
376  FunctionInfo Func;
377  populateFunctionInfo(Func, D, FC, LineNumber, File);
378  Func.IsMethod = true;
379 
380  SymbolID ParentUSR = getUSRForDecl(D->getParent());
381  Func.Parent = Reference{ParentUSR, D->getParent()->getNameAsString(),
383  Func.Access = D->getAccess();
384 
385  // Wrap in enclosing scope
386  auto I = llvm::make_unique<RecordInfo>();
387  I->USR = ParentUSR;
388  I->ChildFunctions.emplace_back(std::move(Func));
389  return std::unique_ptr<Info>{std::move(I)};
390 }
391 
392 std::unique_ptr<Info> emitInfo(const EnumDecl *D, const FullComment *FC,
393  int LineNumber, llvm::StringRef File,
394  bool PublicOnly) {
395  if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal()))
396  return nullptr;
397  EnumInfo Enum;
398  populateSymbolInfo(Enum, D, FC, LineNumber, File);
399  Enum.Scoped = D->isScoped();
400  parseEnumerators(Enum, D);
401 
402  // Wrap in enclosing scope
403  if (!Enum.Namespace.empty()) {
404  switch (Enum.Namespace[0].RefType) {
405  case InfoType::IT_namespace: {
406  auto I = llvm::make_unique<NamespaceInfo>();
407  I->USR = Enum.Namespace[0].USR;
408  I->ChildEnums.emplace_back(std::move(Enum));
409  return std::unique_ptr<Info>{std::move(I)};
410  }
411  case InfoType::IT_record: {
412  auto I = llvm::make_unique<RecordInfo>();
413  I->USR = Enum.Namespace[0].USR;
414  I->ChildEnums.emplace_back(std::move(Enum));
415  return std::unique_ptr<Info>{std::move(I)};
416  }
417  default:
418  break;
419  }
420  }
421 
422  // Put in global namespace
423  auto I = llvm::make_unique<NamespaceInfo>();
424  I->USR = SymbolID();
425  I->ChildEnums.emplace_back(std::move(Enum));
426  return std::unique_ptr<Info>{std::move(I)};
427 }
428 
429 } // namespace serialize
430 } // namespace doc
431 } // namespace clang
static void populateParentNamespaces(llvm::SmallVector< Reference, 4 > &Namespaces, const T *D)
Definition: Serialize.cpp:270
llvm::SmallVector< Reference, 4 > Namespace
static void parseFullComment(const FullComment *C, CommentInfo &CI)
Definition: Serialize.cpp:170
void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C)
Definition: Serialize.cpp:121
void visitParamCommandComment(const ParamCommandComment *C)
Definition: Serialize.cpp:100
void emitBlock(const NamespaceInfo &I)
llvm::Optional< Location > DefLoc
void visitVerbatimBlockComment(const VerbatimBlockComment *C)
Definition: Serialize.cpp:115
llvm::SmallVector< Location, 2 > Loc
static void parseBases(RecordInfo &I, const CXXRecordDecl *D)
Definition: Serialize.cpp:246
static RecordDecl * getDeclForType(const QualType &T)
Definition: Serialize.cpp:182
void parseComment(const comments::Comment *C)
Definition: Serialize.cpp:53
std::string serialize(std::unique_ptr< Info > &I)
Definition: Serialize.cpp:155
static llvm::cl::opt< bool > PublicOnly("public", llvm::cl::desc("Document only public declarations."), llvm::cl::init(false), llvm::cl::cat(ClangDocCategory))
static std::string serialize(T &I)
Definition: Serialize.cpp:147
llvm::SmallVector< Reference, 4 > VirtualParents
void visitHTMLStartTagComment(const HTMLStartTagComment *C)
Definition: Serialize.cpp:76
llvm::SmallVector< FieldTypeInfo, 4 > Params
static void parseEnumerators(EnumInfo &I, const EnumDecl *D)
Definition: Serialize.cpp:223
std::string Filename
Filename as a string.
llvm::SmallVector< SmallString< 16 >, 4 > Members
static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C, int LineNumber, StringRef Filename)
Definition: Serialize.cpp:301
llvm::SmallVector< SmallString< 16 >, 4 > AttrValues
std::vector< CommentInfo > Description
void visitHTMLEndTagComment(const HTMLEndTagComment *C)
Definition: Serialize.cpp:87
void visitTParamCommandComment(const TParamCommandComment *C)
Definition: Serialize.cpp:109
llvm::SmallVector< SmallString< 16 >, 4 > Args
SmallString< 16 > Name
const Decl * D
Definition: XRefs.cpp:79
A base struct for Infos.
llvm::SmallVector< Reference, 4 > Parents
void visitTextComment(const TextComment *C)
Definition: Serialize.cpp:64
static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D, const FullComment *FC, int LineNumber, StringRef Filename)
Definition: Serialize.cpp:310
SmallString< 16 > ParamName
static bool isPublic(const clang::AccessSpecifier AS, const clang::Linkage Link)
Definition: Serialize.cpp:189
llvm::SmallVector< SmallString< 16 >, 4 > AttrKeys
static void parseParameters(FunctionInfo &I, const FunctionDecl *D)
Definition: Serialize.cpp:228
SmallString< 16 > Name
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::unique_ptr< Info > emitInfo(const NamespaceDecl *D, const FullComment *FC, int LineNumber, llvm::StringRef File, bool PublicOnly)
Definition: Serialize.cpp:327
static SymbolID getUSRForDecl(const Decl *D)
Definition: Serialize.cpp:175
SmallString< 16 > CloseName
void visitBlockCommandComment(const BlockCommandComment *C)
Definition: Serialize.cpp:93
SmallString< 8 > Direction
void visitInlineCommandComment(const InlineCommandComment *C)
Definition: Serialize.cpp:69
llvm::SmallVector< MemberTypeInfo, 4 > Members
SmallString< 16 > Kind
static void populateInfo(Info &I, const T *D, const FullComment *C)
Definition: Serialize.cpp:290
std::vector< std::unique_ptr< CommentInfo > > Children
SmallString< 64 > Text
std::array< uint8_t, 20 > SymbolID
void visitVerbatimLineComment(const VerbatimLineComment *C)
Definition: Serialize.cpp:127
SymbolID hashUSR(llvm::StringRef USR)
Definition: Serialize.cpp:24
static void parseFields(RecordInfo &I, const RecordDecl *D, bool PublicOnly)
Definition: Serialize.cpp:199