clang-tools  7.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 static void parseFullComment(const FullComment *C, CommentInfo &CI) {
156  ClangDocCommentVisitor Visitor(CI);
157  Visitor.parseComment(C);
158 }
159 
160 static SymbolID getUSRForDecl(const Decl *D) {
161  llvm::SmallString<128> USR;
162  if (index::generateUSRForDecl(D, USR))
163  return SymbolID();
164  return hashUSR(USR);
165 }
166 
167 static RecordDecl *getDeclForType(const QualType &T) {
168  auto *Ty = T->getAs<RecordType>();
169  if (!Ty)
170  return nullptr;
171  return Ty->getDecl()->getDefinition();
172 }
173 
174 static bool isPublic(const clang::AccessSpecifier AS,
175  const clang::Linkage Link) {
176  if (AS == clang::AccessSpecifier::AS_private)
177  return false;
178  else if ((Link == clang::Linkage::ModuleLinkage) ||
179  (Link == clang::Linkage::ExternalLinkage))
180  return true;
181  return false; // otherwise, linkage is some form of internal linkage
182 }
183 
184 static void parseFields(RecordInfo &I, const RecordDecl *D, bool PublicOnly) {
185  for (const FieldDecl *F : D->fields()) {
186  if (PublicOnly && !isPublic(F->getAccessUnsafe(), F->getLinkageInternal()))
187  continue;
188  if (const auto *T = getDeclForType(F->getTypeSourceInfo()->getType())) {
189  // Use getAccessUnsafe so that we just get the default AS_none if it's not
190  // valid, as opposed to an assert.
191  if (const auto *N = dyn_cast<EnumDecl>(T)) {
192  I.Members.emplace_back(getUSRForDecl(T), N->getNameAsString(),
193  InfoType::IT_enum, F->getNameAsString(),
194  N->getAccessUnsafe());
195  continue;
196  } else if (const auto *N = dyn_cast<RecordDecl>(T)) {
197  I.Members.emplace_back(getUSRForDecl(T), N->getNameAsString(),
198  InfoType::IT_record, F->getNameAsString(),
199  N->getAccessUnsafe());
200  continue;
201  }
202  }
203  I.Members.emplace_back(F->getTypeSourceInfo()->getType().getAsString(),
204  F->getNameAsString(), F->getAccessUnsafe());
205  }
206 }
207 
208 static void parseEnumerators(EnumInfo &I, const EnumDecl *D) {
209  for (const EnumConstantDecl *E : D->enumerators())
210  I.Members.emplace_back(E->getNameAsString());
211 }
212 
213 static void parseParameters(FunctionInfo &I, const FunctionDecl *D) {
214  for (const ParmVarDecl *P : D->parameters()) {
215  if (const auto *T = getDeclForType(P->getOriginalType())) {
216  if (const auto *N = dyn_cast<EnumDecl>(T)) {
217  I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(),
218  InfoType::IT_enum, P->getNameAsString());
219  continue;
220  } else if (const auto *N = dyn_cast<RecordDecl>(T)) {
221  I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(),
222  InfoType::IT_record, P->getNameAsString());
223  continue;
224  }
225  }
226  I.Params.emplace_back(P->getOriginalType().getAsString(),
227  P->getNameAsString());
228  }
229 }
230 
231 static void parseBases(RecordInfo &I, const CXXRecordDecl *D) {
232  for (const CXXBaseSpecifier &B : D->bases()) {
233  if (B.isVirtual())
234  continue;
235  if (const auto *P = getDeclForType(B.getType()))
236  I.Parents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
238  else
239  I.Parents.emplace_back(B.getType().getAsString());
240  }
241  for (const CXXBaseSpecifier &B : D->vbases()) {
242  if (const auto *P = getDeclForType(B.getType()))
243  I.VirtualParents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
245  else
246  I.VirtualParents.emplace_back(B.getType().getAsString());
247  }
248 }
249 
250 template <typename T>
251 static void
252 populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
253  const T *D) {
254  const auto *DC = dyn_cast<DeclContext>(D);
255  while ((DC = DC->getParent())) {
256  if (const auto *N = dyn_cast<NamespaceDecl>(DC))
257  Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
259  else if (const auto *N = dyn_cast<RecordDecl>(DC))
260  Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
262  else if (const auto *N = dyn_cast<FunctionDecl>(DC))
263  Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
265  else if (const auto *N = dyn_cast<EnumDecl>(DC))
266  Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
268  }
269 }
270 
271 template <typename T>
272 static void populateInfo(Info &I, const T *D, const FullComment *C) {
273  I.USR = getUSRForDecl(D);
274  I.Name = D->getNameAsString();
276  if (C) {
277  I.Description.emplace_back();
278  parseFullComment(C, I.Description.back());
279  }
280 }
281 
282 template <typename T>
283 static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C,
284  int LineNumber, StringRef Filename) {
285  populateInfo(I, D, C);
286  if (D->isThisDeclarationADefinition())
287  I.DefLoc.emplace(LineNumber, Filename);
288  else
289  I.Loc.emplace_back(LineNumber, Filename);
290 }
291 
292 static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
293  const FullComment *FC, int LineNumber,
294  StringRef Filename) {
295  populateSymbolInfo(I, D, FC, LineNumber, Filename);
296  if (const auto *T = getDeclForType(D->getReturnType())) {
297  if (dyn_cast<EnumDecl>(T))
298  I.ReturnType =
299  TypeInfo(getUSRForDecl(T), T->getNameAsString(), InfoType::IT_enum);
300  else if (dyn_cast<RecordDecl>(T))
301  I.ReturnType =
302  TypeInfo(getUSRForDecl(T), T->getNameAsString(), InfoType::IT_record);
303  } else {
304  I.ReturnType = TypeInfo(D->getReturnType().getAsString());
305  }
306  parseParameters(I, D);
307 }
308 
309 std::string emitInfo(const NamespaceDecl *D, const FullComment *FC,
310  int LineNumber, llvm::StringRef File, bool PublicOnly) {
311  if (PublicOnly && ((D->isAnonymousNamespace()) ||
312  !isPublic(D->getAccess(), D->getLinkageInternal())))
313  return "";
314  NamespaceInfo I;
315  populateInfo(I, D, FC);
316  return serialize(I);
317 }
318 
319 std::string emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber,
320  llvm::StringRef File, bool PublicOnly) {
321  if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal()))
322  return "";
323  RecordInfo I;
324  populateSymbolInfo(I, D, FC, LineNumber, File);
325  I.TagType = D->getTagKind();
326  parseFields(I, D, PublicOnly);
327  if (const auto *C = dyn_cast<CXXRecordDecl>(D))
328  parseBases(I, C);
329  return serialize(I);
330 }
331 
332 std::string emitInfo(const FunctionDecl *D, const FullComment *FC,
333  int LineNumber, llvm::StringRef File, bool PublicOnly) {
334  if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal()))
335  return "";
336  FunctionInfo I;
337  populateFunctionInfo(I, D, FC, LineNumber, File);
338  I.Access = clang::AccessSpecifier::AS_none;
339  return serialize(I);
340 }
341 
342 std::string emitInfo(const CXXMethodDecl *D, const FullComment *FC,
343  int LineNumber, llvm::StringRef File, bool PublicOnly) {
344  if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal()))
345  return "";
346  FunctionInfo I;
347  populateFunctionInfo(I, D, FC, LineNumber, File);
348  I.IsMethod = true;
349  I.Parent = Reference{getUSRForDecl(D->getParent()),
350  D->getParent()->getNameAsString(), InfoType::IT_record};
351  I.Access = D->getAccess();
352  return serialize(I);
353 }
354 
355 std::string emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber,
356  llvm::StringRef File, bool PublicOnly) {
357  if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal()))
358  return "";
359  EnumInfo I;
360  populateSymbolInfo(I, D, FC, LineNumber, File);
361  I.Scoped = D->isScoped();
362  parseEnumerators(I, D);
363  return serialize(I);
364 }
365 
366 } // namespace serialize
367 } // namespace doc
368 } // namespace clang
static void populateParentNamespaces(llvm::SmallVector< Reference, 4 > &Namespaces, const T *D)
Definition: Serialize.cpp:252
llvm::SmallVector< Reference, 4 > Namespace
static void parseFullComment(const FullComment *C, CommentInfo &CI)
Definition: Serialize.cpp:155
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:231
static RecordDecl * getDeclForType(const QualType &T)
Definition: Serialize.cpp:167
void parseComment(const comments::Comment *C)
Definition: Serialize.cpp:53
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:208
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:283
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
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:292
SmallString< 16 > ParamName
static bool isPublic(const clang::AccessSpecifier AS, const clang::Linkage Link)
Definition: Serialize.cpp:174
llvm::SmallVector< SmallString< 16 >, 4 > AttrKeys
static void parseParameters(FunctionInfo &I, const FunctionDecl *D)
Definition: Serialize.cpp:213
SmallString< 16 > Name
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static SymbolID getUSRForDecl(const Decl *D)
Definition: Serialize.cpp:160
SmallString< 16 > CloseName
void visitBlockCommandComment(const BlockCommandComment *C)
Definition: Serialize.cpp:93
SmallString< 8 > Direction
std::string emitInfo(const NamespaceDecl *D, const FullComment *FC, int LineNumber, llvm::StringRef File, bool PublicOnly)
Definition: Serialize.cpp:309
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:272
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:184