11#include "clang/AST/Comment.h"
12#include "clang/Index/USRGeneration.h"
13#include "clang/Lex/Lexer.h"
14#include "llvm/ADT/Hashing.h"
15#include "llvm/ADT/StringExtras.h"
16#include "llvm/Support/SHA1.h"
18using clang::comments::FullComment;
25 return llvm::SHA1::hash(arrayRefFromStringRef(
USR));
31 const T *D,
bool &IsAnonymousNamespace);
50 llvm::SmallString<128>
Path;
51 for (
auto R = Namespaces.rbegin(),
E = Namespaces.rend(); R !=
E; ++R)
52 llvm::sys::path::append(
Path, R->Name);
57 llvm::SmallVector<Reference, 4> Namespaces;
85 std::string getCommandName(
unsigned CommandID)
const;
86 bool isWhitespaceOnly(StringRef S)
const;
92 CurrentCI.
Kind =
C->getCommentKindName();
94 for (comments::Comment *Child :
95 llvm::make_range(
C->child_begin(),
C->child_end())) {
96 CurrentCI.
Children.emplace_back(std::make_unique<CommentInfo>());
103 if (!isWhitespaceOnly(
C->getText()))
104 CurrentCI.
Text =
C->getText();
108 const InlineCommandComment *
C) {
109 CurrentCI.
Name = getCommandName(
C->getCommandID());
110 for (
unsigned I = 0,
E =
C->getNumArgs(); I !=
E; ++I)
111 CurrentCI.
Args.push_back(
C->getArgText(I));
115 const HTMLStartTagComment *
C) {
116 CurrentCI.
Name =
C->getTagName();
118 for (
unsigned I = 0,
E =
C->getNumAttrs(); I <
E; ++I) {
119 const HTMLStartTagComment::Attribute &Attr =
C->getAttr(I);
120 CurrentCI.
AttrKeys.push_back(Attr.Name);
126 const HTMLEndTagComment *
C) {
127 CurrentCI.
Name =
C->getTagName();
132 const BlockCommandComment *
C) {
133 CurrentCI.
Name = getCommandName(
C->getCommandID());
134 for (
unsigned I = 0,
E =
C->getNumArgs(); I <
E; ++I)
135 CurrentCI.
Args.push_back(
C->getArgText(I));
139 const ParamCommandComment *
C) {
141 ParamCommandComment::getDirectionAsString(
C->getDirection());
142 CurrentCI.
Explicit =
C->isDirectionExplicit();
143 if (
C->hasParamName())
144 CurrentCI.
ParamName =
C->getParamNameAsWritten();
148 const TParamCommandComment *
C) {
149 if (
C->hasParamName())
150 CurrentCI.
ParamName =
C->getParamNameAsWritten();
154 const VerbatimBlockComment *
C) {
155 CurrentCI.
Name = getCommandName(
C->getCommandID());
160 const VerbatimBlockLineComment *
C) {
161 if (!isWhitespaceOnly(
C->getText()))
162 CurrentCI.
Text =
C->getText();
166 const VerbatimLineComment *
C) {
167 if (!isWhitespaceOnly(
C->getText()))
168 CurrentCI.
Text =
C->getText();
171bool ClangDocCommentVisitor::isWhitespaceOnly(llvm::StringRef S)
const {
172 return llvm::all_of(S, isspace);
175std::string ClangDocCommentVisitor::getCommandName(
unsigned CommandID)
const {
176 const CommandInfo *
Info = CommandTraits::getBuiltinCommandInfo(CommandID);
180 return "<not a builtin command>";
186 return Lexer::getSourceText(CharSourceRange::getTokenRange(R),
187 D->getASTContext().getSourceManager(),
188 D->getASTContext().getLangOpts())
192template <
typename T>
static std::string
serialize(T &I) {
193 SmallString<2048> Buffer;
194 llvm::BitstreamWriter Stream(Buffer);
197 return Buffer.str().str();
221 llvm::SmallString<128>
USR;
222 if (index::generateUSRForDecl(D,
USR))
228 if (
const TagDecl *D = T->getAsTagDecl())
229 return D->getDefinition();
234 if (
const RecordDecl *D = T->getAsRecordDecl())
235 return D->getDefinition();
245 if (dyn_cast<EnumDecl>(TD)) {
247 }
else if (dyn_cast<RecordDecl>(TD)) {
256static bool isPublic(
const clang::AccessSpecifier AS,
257 const clang::Linkage Link) {
258 if (AS == clang::AccessSpecifier::AS_private)
260 else if ((Link == clang::Linkage::Module) ||
261 (Link == clang::Linkage::External))
267 const NamedDecl *D) {
268 bool IsAnonymousNamespace =
false;
269 if (
const auto *N = dyn_cast<NamespaceDecl>(D))
270 IsAnonymousNamespace = N->isAnonymousNamespace();
272 (!IsInAnonymousNamespace && !IsAnonymousNamespace &&
273 isPublic(D->getAccessUnsafe(), D->getLinkageInternal()));
318template <
typename ChildType>
320 if (Child.Namespace.empty()) {
322 auto ParentNS = std::make_unique<NamespaceInfo>();
323 InsertChild(ParentNS->Children, std::forward<ChildType>(Child));
327 switch (Child.Namespace[0].RefType) {
329 auto ParentNS = std::make_unique<NamespaceInfo>();
330 ParentNS->USR = Child.Namespace[0].USR;
331 InsertChild(ParentNS->Children, std::forward<ChildType>(Child));
335 auto ParentRec = std::make_unique<RecordInfo>();
336 ParentRec->USR = Child.Namespace[0].USR;
337 InsertChild(ParentRec->Children, std::forward<ChildType>(Child));
341 llvm_unreachable(
"Invalid reference type for parent namespace");
361 AccessSpecifier SecondAS) {
362 if (FirstAS == AccessSpecifier::AS_none ||
363 SecondAS == AccessSpecifier::AS_none)
364 return AccessSpecifier::AS_none;
365 if (FirstAS == AccessSpecifier::AS_private ||
366 SecondAS == AccessSpecifier::AS_private)
367 return AccessSpecifier::AS_private;
368 if (FirstAS == AccessSpecifier::AS_protected ||
369 SecondAS == AccessSpecifier::AS_protected)
370 return AccessSpecifier::AS_protected;
371 return AccessSpecifier::AS_public;
377 AccessSpecifier Access = AccessSpecifier::AS_public) {
378 for (
const FieldDecl *F : D->fields()) {
382 auto &LO = F->getLangOpts();
387 F->getNameAsString(),
394 for (
const EnumConstantDecl *
E : D->enumerators()) {
395 std::string ValueExpr;
396 if (
const Expr *InitExpr =
E->getInitExpr())
398 SmallString<16> ValueStr;
399 E->getInitVal().toString(ValueStr);
400 I.
Members.emplace_back(
E->getNameAsString(), ValueStr.str(), ValueExpr);
401 ASTContext &Context =
E->getASTContext();
402 if (RawComment *Comment =
403 E->getASTContext().getRawCommentForDeclNoCache(
E)) {
405 Comment->setAttached();
406 if (comments::FullComment *Fc = Comment->parse(Context,
nullptr,
E)) {
416 auto &LO = D->getLangOpts();
417 for (
const ParmVarDecl *P : D->parameters()) {
428 if (!D->isThisDeclarationADefinition())
430 for (
const CXXBaseSpecifier &B : D->bases()) {
433 if (
const auto *Ty = B.getType()->getAs<TemplateSpecializationType>()) {
434 const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl();
444 for (
const CXXBaseSpecifier &B : D->vbases()) {
457 const T *D,
bool &IsInAnonymousNamespace) {
458 const DeclContext *DC = D->getDeclContext();
460 if (
const auto *N = dyn_cast<NamespaceDecl>(DC)) {
461 std::string Namespace;
462 if (N->isAnonymousNamespace()) {
463 Namespace =
"@nonymous_namespace";
464 IsInAnonymousNamespace =
true;
466 Namespace = N->getNameAsString();
469 N->getQualifiedNameAsString());
470 }
else if (
const auto *N = dyn_cast<RecordDecl>(DC))
471 Namespaces.emplace_back(
getUSRForDecl(N), N->getNameAsString(),
473 N->getQualifiedNameAsString());
474 else if (
const auto *N = dyn_cast<FunctionDecl>(DC))
475 Namespaces.emplace_back(
getUSRForDecl(N), N->getNameAsString(),
477 N->getQualifiedNameAsString());
478 else if (
const auto *N = dyn_cast<EnumDecl>(DC))
479 Namespaces.emplace_back(
getUSRForDecl(N), N->getNameAsString(),
481 }
while ((DC = DC->getParent()));
486 if ((Namespaces.empty() && isa<RecordDecl>(D)) ||
488 Namespaces.emplace_back(
SymbolID(),
"GlobalNamespace",
493 const clang::Decl *D) {
494 if (
const TemplateParameterList *ParamList =
495 D->getDescribedTemplateParams()) {
499 for (
const NamedDecl *ND : *ParamList) {
507 const TemplateArgument &Arg) {
511 llvm::raw_string_ostream Stream(Str);
512 Arg.print(PrintingPolicy(D->getLangOpts()), Stream,
false);
518 bool &IsInAnonymousNamespace) {
520 I.
Name = D->getNameAsString();
531 bool IsFileInRootDir,
532 bool &IsInAnonymousNamespace) {
534 if (D->isThisDeclarationADefinition())
537 I.
Loc.emplace_back(LineNumber,
Filename, IsFileInRootDir);
541 const FullComment *FC,
int LineNumber,
542 StringRef
Filename,
bool IsFileInRootDir,
543 bool &IsInAnonymousNamespace) {
545 IsInAnonymousNamespace);
546 auto &LO = D->getLangOpts();
553 if (
const FunctionTemplateSpecializationInfo *FTSI =
554 D->getTemplateSpecializationInfo()) {
557 I.
Template->Specialization.emplace();
558 auto &Specialization = *I.
Template->Specialization;
560 Specialization.SpecializationOf =
getUSRForDecl(FTSI->getTemplate());
563 if (FTSI->TemplateArguments) {
564 for (
const TemplateArgument &Arg : FTSI->TemplateArguments->asArray()) {
572 assert(D &&
"Expect non-null FieldDecl in populateMemberTypeInfo");
574 ASTContext& Context = D->getASTContext();
577 RawComment *Comment = Context.getRawCommentForDeclNoCache(D);
581 Comment->setAttached();
582 if (comments::FullComment *fc = Comment->parse(Context,
nullptr, D)) {
591 AccessSpecifier ParentAccess = AccessSpecifier::AS_public) {
593 if (!D->isThisDeclarationADefinition())
595 for (
const CXXBaseSpecifier &B : D->bases()) {
596 if (
const RecordType *Ty = B.getType()->getAs<RecordType>()) {
597 if (
const CXXRecordDecl *Base =
598 cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition())) {
605 if (
const auto *Ty = B.getType()->getAs<TemplateSpecializationType>()) {
606 const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl();
608 BI.Name = B.getType().getAsString();
611 BI.Name = Base->getNameAsString();
614 for (
const auto &
Decl : Base->decls())
615 if (
const auto *
MD = dyn_cast<CXXMethodDecl>(
Decl)) {
617 if (
MD->getAccessUnsafe() == AccessSpecifier::AS_private ||
618 !
MD->isUserProvided())
625 bool IsInAnonymousNamespace;
628 IsInAnonymousNamespace);
631 BI.Children.Functions.emplace_back(std::move(FI));
633 I.
Bases.emplace_back(std::move(BI));
638 I.
Bases.back().Access);
644std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
645emitInfo(
const NamespaceDecl *D,
const FullComment *FC,
int LineNumber,
646 llvm::StringRef File,
bool IsFileInRootDir,
bool PublicOnly) {
647 auto I = std::make_unique<NamespaceInfo>();
648 bool IsInAnonymousNamespace =
false;
653 I->Name = D->isAnonymousNamespace()
654 ? llvm::SmallString<16>(
"@nonymous_namespace")
657 if (I->Namespace.empty() && I->USR ==
SymbolID())
658 return {std::unique_ptr<Info>{std::move(I)},
nullptr};
662 return {std::move(I), MakeAndInsertIntoParent<const NamespaceInfo &>(*I)};
665std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
666emitInfo(
const RecordDecl *D,
const FullComment *FC,
int LineNumber,
667 llvm::StringRef File,
bool IsFileInRootDir,
bool PublicOnly) {
668 auto I = std::make_unique<RecordInfo>();
669 bool IsInAnonymousNamespace =
false;
671 IsInAnonymousNamespace);
675 I->TagType = D->getTagKind();
677 if (
const auto *
C = dyn_cast<CXXRecordDecl>(D)) {
678 if (
const TypedefNameDecl *TD =
C->getTypedefNameForAnonDecl()) {
679 I->Name = TD->getNameAsString();
691 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
693 I->Template.emplace();
694 I->Template->Specialization.emplace();
695 auto &Specialization = *I->Template->Specialization;
698 auto SpecOf = CTSD->getSpecializedTemplateOrPartial();
699 if (
auto *CTD = dyn_cast<ClassTemplateDecl *>(SpecOf))
701 else if (
auto *CTPSD =
702 dyn_cast<ClassTemplatePartialSpecializationDecl *>(SpecOf))
710 if (
const ClassTemplatePartialSpecializationDecl *CTPSD =
711 dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) {
712 if (
const ASTTemplateArgumentListInfo *AsWritten =
713 CTPSD->getTemplateArgsAsWritten()) {
714 for (
unsigned i = 0; i < AsWritten->getNumTemplateArgs(); i++) {
715 Specialization.Params.emplace_back(
720 for (
const TemplateArgument &Arg : CTSD->getTemplateArgs().asArray()) {
728 auto Parent = MakeAndInsertIntoParent<const RecordInfo &>(*I);
729 return {std::move(I), std::move(
Parent)};
732std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
733emitInfo(
const FunctionDecl *D,
const FullComment *FC,
int LineNumber,
734 llvm::StringRef File,
bool IsFileInRootDir,
bool PublicOnly) {
736 bool IsInAnonymousNamespace =
false;
738 IsInAnonymousNamespace);
739 Func.
Access = clang::AccessSpecifier::AS_none;
744 return {
nullptr, MakeAndInsertIntoParent<FunctionInfo &&>(std::move(Func))};
747std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
748emitInfo(
const CXXMethodDecl *D,
const FullComment *FC,
int LineNumber,
749 llvm::StringRef File,
bool IsFileInRootDir,
bool PublicOnly) {
751 bool IsInAnonymousNamespace =
false;
753 IsInAnonymousNamespace);
759 const NamedDecl *
Parent =
nullptr;
761 dyn_cast<ClassTemplateSpecializationDecl>(D->getParent()))
762 Parent = SD->getSpecializedTemplate();
769 Parent->getQualifiedNameAsString()};
770 Func.
Access = D->getAccess();
773 return {
nullptr, MakeAndInsertIntoParent<FunctionInfo &&>(std::move(Func))};
776std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
777emitInfo(
const TypedefDecl *D,
const FullComment *FC,
int LineNumber,
778 StringRef File,
bool IsFileInRootDir,
bool PublicOnly) {
781 bool IsInAnonymousNamespace =
false;
786 Info.DefLoc.emplace(LineNumber, File, IsFileInRootDir);
787 auto &LO = D->getLangOpts();
789 if (
Info.Underlying.Type.
Name.empty()) {
795 Info.IsUsing =
false;
798 return {
nullptr, MakeAndInsertIntoParent<TypedefInfo &&>(std::move(
Info))};
803std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
804emitInfo(
const TypeAliasDecl *D,
const FullComment *FC,
int LineNumber,
805 StringRef File,
bool IsFileInRootDir,
bool PublicOnly) {
808 bool IsInAnonymousNamespace =
false;
813 Info.DefLoc.emplace(LineNumber, File, IsFileInRootDir);
814 auto &LO = D->getLangOpts();
819 return {
nullptr, MakeAndInsertIntoParent<TypedefInfo &&>(std::move(
Info))};
822std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
823emitInfo(
const EnumDecl *D,
const FullComment *FC,
int LineNumber,
824 llvm::StringRef File,
bool IsFileInRootDir,
bool PublicOnly) {
826 bool IsInAnonymousNamespace =
false;
828 IsInAnonymousNamespace);
832 Enum.Scoped = D->isScoped();
834 auto Name = D->getIntegerType().getAsString();
840 return {
nullptr, MakeAndInsertIntoParent<EnumInfo &&>(std::move(Enum))};
const FunctionDecl * Decl
llvm::SmallString< 256U > Name
static llvm::cl::opt< bool > PublicOnly("public", llvm::cl::desc("Document only public declarations."), llvm::cl::init(false), llvm::cl::cat(ClangDocCategory))
std::string Filename
Filename as a string.
std::vector< HeaderHandle > Path
std::unique_ptr< CompilerInvocation > CI
void emitBlock(const NamespaceInfo &I)
static void parseFields(RecordInfo &I, const RecordDecl *D, bool PublicOnly, AccessSpecifier Access=AccessSpecifier::AS_public)
static void populateMemberTypeInfo(MemberTypeInfo &I, const FieldDecl *D)
static bool shouldSerializeInfo(bool PublicOnly, bool IsInAnonymousNamespace, const NamedDecl *D)
static RecordDecl * getRecordDeclForType(const QualType &T)
static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D, const FullComment *FC, int LineNumber, StringRef Filename, bool IsFileInRootDir, bool &IsInAnonymousNamespace)
void PopulateTemplateParameters(std::optional< TemplateInfo > &TemplateInfo, const clang::Decl *D)
std::string getSourceCode(const Decl *D, const SourceRange &R)
std::pair< std::unique_ptr< Info >, std::unique_ptr< Info > > emitInfo(const NamespaceDecl *D, const FullComment *FC, int LineNumber, llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly)
static bool isPublic(const clang::AccessSpecifier AS, const clang::Linkage Link)
llvm::SmallString< 128 > getInfoRelativePath(const llvm::SmallVectorImpl< doc::Reference > &Namespaces)
static void parseFullComment(const FullComment *C, CommentInfo &CI)
std::unique_ptr< Info > MakeAndInsertIntoParent(ChildType Child)
static std::string serialize(T &I)
static void parseParameters(FunctionInfo &I, const FunctionDecl *D)
static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C, int LineNumber, StringRef Filename, bool IsFileInRootDir, bool &IsInAnonymousNamespace)
static SymbolID getUSRForDecl(const Decl *D)
TemplateParamInfo TemplateArgumentToInfo(const clang::Decl *D, const TemplateArgument &Arg)
static AccessSpecifier getFinalAccessSpecifier(AccessSpecifier FirstAS, AccessSpecifier SecondAS)
static void InsertChild(ScopeChildren &Scope, const NamespaceInfo &Info)
TypeInfo getTypeInfoForType(const QualType &T, const PrintingPolicy &Policy)
static void populateParentNamespaces(llvm::SmallVector< Reference, 4 > &Namespaces, const T *D, bool &IsAnonymousNamespace)
static void parseEnumerators(EnumInfo &I, const EnumDecl *D)
static TagDecl * getTagDeclForType(const QualType &T)
static void parseBases(RecordInfo &I, const CXXRecordDecl *D)
SymbolID hashUSR(llvm::StringRef USR)
static void populateInfo(Info &I, const T *D, const FullComment *C, bool &IsInAnonymousNamespace)
static GeneratorRegistry::Add< MDGenerator > MD(MDGenerator::Format, "Generator for MD output.")
std::array< uint8_t, 20 > SymbolID
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
llvm::SmallVector< EnumValueInfo, 4 > Members
std::vector< CommentInfo > Description
SmallString< 16 > DefaultValue
llvm::SmallVector< FieldTypeInfo, 4 > Params
std::optional< TemplateInfo > Template
std::vector< CommentInfo > Description
llvm::SmallVector< Reference, 4 > Namespace
std::vector< CommentInfo > Description
llvm::SmallVector< MemberTypeInfo, 4 > Members
llvm::SmallVector< Reference, 4 > VirtualParents
llvm::SmallVector< Reference, 4 > Parents
std::vector< BaseRecordInfo > Bases
std::vector< Reference > Records
std::vector< TypedefInfo > Typedefs
std::vector< FunctionInfo > Functions
std::vector< Reference > Namespaces
std::vector< EnumInfo > Enums
llvm::SmallVector< Location, 2 > Loc
std::optional< Location > DefLoc
std::vector< TemplateParamInfo > Params