11 #include "clang/AST/Comment.h" 12 #include "clang/Index/USRGeneration.h" 13 #include "llvm/ADT/Hashing.h" 14 #include "llvm/ADT/StringExtras.h" 15 #include "llvm/Support/SHA1.h" 17 using clang::comments::FullComment;
24 return llvm::SHA1::hash(arrayRefFromStringRef(USR));
30 const T *
D,
bool &IsAnonymousNamespace);
45 llvm::SmallString<128>
48 llvm::SmallString<128>
Path;
49 for (
auto R = Namespaces.rbegin(), E = Namespaces.rend(); R != E; ++R)
50 llvm::sys::path::append(Path, R->Name);
55 llvm::SmallVector<Reference, 4> Namespaces;
83 std::string getCommandName(
unsigned CommandID)
const;
84 bool isWhitespaceOnly(StringRef S)
const;
90 CurrentCI.
Kind = C->getCommentKindName();
92 for (comments::Comment *Child :
93 llvm::make_range(C->child_begin(), C->child_end())) {
94 CurrentCI.
Children.emplace_back(llvm::make_unique<CommentInfo>());
101 if (!isWhitespaceOnly(C->getText()))
102 CurrentCI.
Text = C->getText();
106 const InlineCommandComment *C) {
107 CurrentCI.
Name = getCommandName(C->getCommandID());
108 for (
unsigned I = 0, E = C->getNumArgs(); I != E; ++I)
109 CurrentCI.
Args.push_back(C->getArgText(I));
113 const HTMLStartTagComment *C) {
114 CurrentCI.
Name = C->getTagName();
116 for (
unsigned I = 0, E = C->getNumAttrs(); I < E; ++I) {
117 const HTMLStartTagComment::Attribute &Attr = C->getAttr(I);
118 CurrentCI.
AttrKeys.push_back(Attr.Name);
124 const HTMLEndTagComment *C) {
125 CurrentCI.
Name = C->getTagName();
130 const BlockCommandComment *C) {
131 CurrentCI.
Name = getCommandName(C->getCommandID());
132 for (
unsigned I = 0, E = C->getNumArgs(); I < E; ++I)
133 CurrentCI.
Args.push_back(C->getArgText(I));
137 const ParamCommandComment *C) {
139 ParamCommandComment::getDirectionAsString(C->getDirection());
140 CurrentCI.
Explicit = C->isDirectionExplicit();
141 if (C->hasParamName())
142 CurrentCI.
ParamName = C->getParamNameAsWritten();
146 const TParamCommandComment *C) {
147 if (C->hasParamName())
148 CurrentCI.
ParamName = C->getParamNameAsWritten();
152 const VerbatimBlockComment *C) {
153 CurrentCI.
Name = getCommandName(C->getCommandID());
158 const VerbatimBlockLineComment *C) {
159 if (!isWhitespaceOnly(C->getText()))
160 CurrentCI.
Text = C->getText();
164 const VerbatimLineComment *C) {
165 if (!isWhitespaceOnly(C->getText()))
166 CurrentCI.
Text = C->getText();
169 bool ClangDocCommentVisitor::isWhitespaceOnly(llvm::StringRef S)
const {
170 return std::all_of(S.begin(), S.end(), isspace);
173 std::string ClangDocCommentVisitor::getCommandName(
unsigned CommandID)
const {
174 const CommandInfo *
Info = CommandTraits::getBuiltinCommandInfo(CommandID);
178 return "<not a builtin command>";
183 template <
typename T>
static std::string
serialize(T &I) {
184 SmallString<2048> Buffer;
185 llvm::BitstreamWriter Stream(Buffer);
188 return Buffer.str().str();
194 return serialize(*static_cast<NamespaceInfo *>(I.get()));
196 return serialize(*static_cast<RecordInfo *>(I.get()));
198 return serialize(*static_cast<EnumInfo *>(I.get()));
200 return serialize(*static_cast<FunctionInfo *>(I.get()));
212 llvm::SmallString<128> USR;
213 if (index::generateUSRForDecl(D, USR))
219 if (
const RecordDecl *D = T->getAsRecordDecl())
220 return D->getDefinition();
224 static bool isPublic(
const clang::AccessSpecifier AS,
225 const clang::Linkage Link) {
226 if (AS == clang::AccessSpecifier::AS_private)
228 else if ((Link == clang::Linkage::ModuleLinkage) ||
229 (Link == clang::Linkage::ExternalLinkage))
235 for (
const FieldDecl *F : D->fields()) {
236 if (PublicOnly && !
isPublic(F->getAccessUnsafe(), F->getLinkageInternal()))
238 if (
const auto *T =
getDeclForType(F->getTypeSourceInfo()->getType())) {
241 if (
const auto *N = dyn_cast<EnumDecl>(T)) {
244 F->getNameAsString(), N->getAccessUnsafe());
246 }
else if (
const auto *N = dyn_cast<RecordDecl>(T)) {
249 F->getNameAsString(), N->getAccessUnsafe());
253 I.
Members.emplace_back(F->getTypeSourceInfo()->getType().getAsString(),
254 F->getNameAsString(), F->getAccessUnsafe());
259 for (
const EnumConstantDecl *E : D->enumerators())
260 I.
Members.emplace_back(E->getNameAsString());
264 for (
const ParmVarDecl *P : D->parameters()) {
266 if (
const auto *N = dyn_cast<EnumDecl>(T)) {
269 P->getNameAsString());
271 }
else if (
const auto *N = dyn_cast<RecordDecl>(T)) {
274 P->getNameAsString());
278 I.
Params.emplace_back(P->getOriginalType().getAsString(),
279 P->getNameAsString());
285 if (!D->isThisDeclarationADefinition())
287 for (
const CXXBaseSpecifier &B : D->bases()) {
290 if (
const auto *Ty = B.getType()->getAs<TemplateSpecializationType>()) {
291 const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl();
298 I.
Parents.emplace_back(B.getType().getAsString());
300 for (
const CXXBaseSpecifier &B : D->vbases()) {
310 template <
typename T>
313 const T *D,
bool &IsInAnonymousNamespace) {
314 const auto *DC = dyn_cast<DeclContext>(
D);
315 while ((DC = DC->getParent())) {
316 if (
const auto *N = dyn_cast<NamespaceDecl>(DC)) {
317 std::string Namespace;
318 if (N->isAnonymousNamespace()) {
319 Namespace =
"@nonymous_namespace";
320 IsInAnonymousNamespace =
true;
322 Namespace = N->getNameAsString();
325 }
else if (
const auto *N = dyn_cast<RecordDecl>(DC))
326 Namespaces.emplace_back(
getUSRForDecl(N), N->getNameAsString(),
328 else if (
const auto *N = dyn_cast<FunctionDecl>(DC))
329 Namespaces.emplace_back(
getUSRForDecl(N), N->getNameAsString(),
331 else if (
const auto *N = dyn_cast<EnumDecl>(DC))
332 Namespaces.emplace_back(
getUSRForDecl(N), N->getNameAsString(),
337 template <
typename T>
339 bool &IsInAnonymousNamespace) {
341 I.
Name = D->getNameAsString();
349 template <
typename T>
352 bool &IsInAnonymousNamespace) {
354 if (D->isThisDeclarationADefinition())
355 I.
DefLoc.emplace(LineNumber, Filename);
357 I.
Loc.emplace_back(LineNumber, Filename);
361 const FullComment *FC,
int LineNumber,
363 bool &IsInAnonymousNamespace) {
366 if (dyn_cast<EnumDecl>(T))
369 else if (dyn_cast<RecordDecl>(T))
378 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
379 emitInfo(
const NamespaceDecl *D,
const FullComment *FC,
int LineNumber,
381 auto I = llvm::make_unique<NamespaceInfo>();
382 bool IsInAnonymousNamespace =
false;
384 if (PublicOnly && ((IsInAnonymousNamespace || D->isAnonymousNamespace()) ||
385 !
isPublic(D->getAccess(), D->getLinkageInternal())))
387 I->Name = D->isAnonymousNamespace()
388 ? llvm::SmallString<16>(
"@nonymous_namespace")
391 if (I->Namespace.empty() && I->USR ==
SymbolID())
392 return {std::unique_ptr<Info>{std::move(I)},
nullptr};
394 auto ParentI = llvm::make_unique<NamespaceInfo>();
395 ParentI->USR = I->Namespace.empty() ?
SymbolID() : I->Namespace[0].USR;
396 ParentI->ChildNamespaces.emplace_back(I->USR, I->Name,
398 if (I->Namespace.empty())
400 return {std::unique_ptr<Info>{std::move(I)},
401 std::unique_ptr<Info>{std::move(ParentI)}};
404 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
405 emitInfo(
const RecordDecl *D,
const FullComment *FC,
int LineNumber,
407 auto I = llvm::make_unique<RecordInfo>();
408 bool IsInAnonymousNamespace =
false;
410 if (PublicOnly && ((IsInAnonymousNamespace ||
411 !
isPublic(D->getAccess(), D->getLinkageInternal()))))
414 I->TagType = D->getTagKind();
416 if (
const auto *C = dyn_cast<CXXRecordDecl>(D)) {
417 if (
const TypedefNameDecl *TD = C->getTypedefNameForAnonDecl()) {
418 I->Name = TD->getNameAsString();
425 if (I->Namespace.empty()) {
426 auto ParentI = llvm::make_unique<NamespaceInfo>();
430 return {std::unique_ptr<Info>{std::move(I)},
431 std::unique_ptr<Info>{std::move(ParentI)}};
434 switch (I->Namespace[0].RefType) {
436 auto ParentI = llvm::make_unique<NamespaceInfo>();
437 ParentI->USR = I->Namespace[0].USR;
439 return {std::unique_ptr<Info>{std::move(I)},
440 std::unique_ptr<Info>{std::move(ParentI)}};
443 auto ParentI = llvm::make_unique<RecordInfo>();
444 ParentI->USR = I->Namespace[0].USR;
446 return {std::unique_ptr<Info>{std::move(I)},
447 std::unique_ptr<Info>{std::move(ParentI)}};
450 llvm_unreachable(
"Invalid reference type for parent namespace");
454 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
455 emitInfo(
const FunctionDecl *D,
const FullComment *FC,
int LineNumber,
458 bool IsInAnonymousNamespace =
false;
460 if (PublicOnly && ((IsInAnonymousNamespace ||
461 !
isPublic(D->getAccess(), D->getLinkageInternal()))))
464 Func.
Access = clang::AccessSpecifier::AS_none;
467 auto ParentI = llvm::make_unique<NamespaceInfo>();
474 ParentI->ChildFunctions.emplace_back(std::move(Func));
476 return {
nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
479 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
480 emitInfo(
const CXXMethodDecl *D,
const FullComment *FC,
int LineNumber,
483 bool IsInAnonymousNamespace =
false;
485 if (PublicOnly && ((IsInAnonymousNamespace ||
486 !
isPublic(D->getAccess(), D->getLinkageInternal()))))
491 const NamedDecl *Parent =
nullptr;
493 dyn_cast<ClassTemplateSpecializationDecl>(D->getParent()))
494 Parent = SD->getSpecializedTemplate();
496 Parent = D->getParent();
501 Func.
Access = D->getAccess();
504 auto ParentI = llvm::make_unique<RecordInfo>();
505 ParentI->USR = ParentUSR;
508 ParentI->ChildFunctions.emplace_back(std::move(Func));
510 return {
nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
513 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
514 emitInfo(
const EnumDecl *D,
const FullComment *FC,
int LineNumber,
517 bool IsInAnonymousNamespace =
false;
519 if (PublicOnly && ((IsInAnonymousNamespace ||
520 !
isPublic(D->getAccess(), D->getLinkageInternal()))))
523 Enum.
Scoped = D->isScoped();
528 auto ParentI = llvm::make_unique<NamespaceInfo>();
530 ParentI->ChildEnums.emplace_back(std::move(Enum));
534 return {
nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
540 auto ParentI = llvm::make_unique<NamespaceInfo>();
542 ParentI->ChildEnums.emplace_back(std::move(Enum));
545 return {
nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
548 auto ParentI = llvm::make_unique<RecordInfo>();
550 ParentI->ChildEnums.emplace_back(std::move(Enum));
553 return {
nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
556 llvm_unreachable(
"Invalid reference type for parent namespace");
llvm::SmallVector< Reference, 4 > Namespace
static void parseFullComment(const FullComment *C, CommentInfo &CI)
static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D, const FullComment *FC, int LineNumber, StringRef Filename, bool &IsInAnonymousNamespace)
void emitBlock(const NamespaceInfo &I)
llvm::Optional< Location > DefLoc
llvm::SmallVector< Location, 2 > Loc
llvm::SmallString< 128 > getInfoRelativePath(const llvm::SmallVectorImpl< doc::Reference > &Namespaces)
static void parseBases(RecordInfo &I, const CXXRecordDecl *D)
static RecordDecl * getDeclForType(const QualType &T)
std::vector< HeaderHandle > Path
std::string serialize(std::unique_ptr< Info > &I)
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)
llvm::SmallVector< Reference, 4 > VirtualParents
std::pair< std::unique_ptr< Info >, std::unique_ptr< Info > > emitInfo(const NamespaceDecl *D, const FullComment *FC, int LineNumber, llvm::StringRef File, bool PublicOnly)
llvm::SmallVector< FieldTypeInfo, 4 > Params
static void parseEnumerators(EnumInfo &I, const EnumDecl *D)
std::string Filename
Filename as a string.
llvm::SmallVector< SmallString< 16 >, 4 > Members
std::vector< CommentInfo > Description
static void populateParentNamespaces(llvm::SmallVector< Reference, 4 > &Namespaces, const T *D, bool &IsAnonymousNamespace)
llvm::SmallVector< Reference, 4 > Parents
static bool isPublic(const clang::AccessSpecifier AS, const clang::Linkage Link)
static void parseParameters(FunctionInfo &I, const FunctionDecl *D)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static SymbolID getUSRForDecl(const Decl *D)
llvm::SmallVector< MemberTypeInfo, 4 > Members
static void populateInfo(Info &I, const T *D, const FullComment *C, bool &IsInAnonymousNamespace)
std::array< uint8_t, 20 > SymbolID
SymbolID hashUSR(llvm::StringRef USR)
static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C, int LineNumber, StringRef Filename, bool &IsInAnonymousNamespace)
static void parseFields(RecordInfo &I, const RecordDecl *D, bool PublicOnly)