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()) {
386 F->getNameAsString(),
393 for (
const EnumConstantDecl *
E : D->enumerators()) {
394 std::string ValueExpr;
395 if (
const Expr *InitExpr =
E->getInitExpr())
398 SmallString<16> ValueStr;
399 E->getInitVal().toString(ValueStr);
400 I.
Members.emplace_back(
E->getNameAsString(), ValueStr, ValueExpr);
405 for (
const ParmVarDecl *P : D->parameters()) {
416 if (!D->isThisDeclarationADefinition())
418 for (
const CXXBaseSpecifier &B : D->bases()) {
421 if (
const auto *Ty = B.getType()->getAs<TemplateSpecializationType>()) {
422 const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl();
432 for (
const CXXBaseSpecifier &B : D->vbases()) {
445 const T *D,
bool &IsInAnonymousNamespace) {
446 const DeclContext *DC = D->getDeclContext();
448 if (
const auto *N = dyn_cast<NamespaceDecl>(DC)) {
449 std::string Namespace;
450 if (N->isAnonymousNamespace()) {
451 Namespace =
"@nonymous_namespace";
452 IsInAnonymousNamespace =
true;
454 Namespace = N->getNameAsString();
457 N->getQualifiedNameAsString());
458 }
else if (
const auto *N = dyn_cast<RecordDecl>(DC))
459 Namespaces.emplace_back(
getUSRForDecl(N), N->getNameAsString(),
461 N->getQualifiedNameAsString());
462 else if (
const auto *N = dyn_cast<FunctionDecl>(DC))
463 Namespaces.emplace_back(
getUSRForDecl(N), N->getNameAsString(),
465 N->getQualifiedNameAsString());
466 else if (
const auto *N = dyn_cast<EnumDecl>(DC))
467 Namespaces.emplace_back(
getUSRForDecl(N), N->getNameAsString(),
469 }
while ((DC = DC->getParent()));
474 if ((Namespaces.empty() && isa<RecordDecl>(D)) ||
476 Namespaces.emplace_back(
SymbolID(),
"GlobalNamespace",
481 const clang::Decl *D) {
482 if (
const TemplateParameterList *ParamList =
483 D->getDescribedTemplateParams()) {
487 for (
const NamedDecl *ND : *ParamList) {
495 const TemplateArgument &Arg) {
499 llvm::raw_string_ostream Stream(Str);
500 Arg.print(PrintingPolicy(D->getLangOpts()), Stream,
false);
506 bool &IsInAnonymousNamespace) {
508 I.
Name = D->getNameAsString();
519 bool IsFileInRootDir,
520 bool &IsInAnonymousNamespace) {
522 if (D->isThisDeclarationADefinition())
525 I.
Loc.emplace_back(LineNumber,
Filename, IsFileInRootDir);
529 const FullComment *FC,
int LineNumber,
530 StringRef
Filename,
bool IsFileInRootDir,
531 bool &IsInAnonymousNamespace) {
533 IsInAnonymousNamespace);
540 if (
const FunctionTemplateSpecializationInfo *FTSI =
541 D->getTemplateSpecializationInfo()) {
544 I.
Template->Specialization.emplace();
545 auto &Specialization = *I.
Template->Specialization;
547 Specialization.SpecializationOf =
getUSRForDecl(FTSI->getTemplate());
550 if (FTSI->TemplateArguments) {
551 for (
const TemplateArgument &Arg : FTSI->TemplateArguments->asArray()) {
559 assert(D &&
"Expect non-null FieldDecl in populateMemberTypeInfo");
561 ASTContext& Context = D->getASTContext();
564 RawComment *Comment = Context.getRawCommentForDeclNoCache(D);
568 Comment->setAttached();
569 if (comments::FullComment* fc = Comment->parse(Context,
nullptr, D)) {
578 AccessSpecifier ParentAccess = AccessSpecifier::AS_public) {
580 if (!D->isThisDeclarationADefinition())
582 for (
const CXXBaseSpecifier &B : D->bases()) {
583 if (
const RecordType *Ty = B.getType()->getAs<RecordType>()) {
584 if (
const CXXRecordDecl *Base =
585 cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition())) {
592 if (
const auto *Ty = B.getType()->getAs<TemplateSpecializationType>()) {
593 const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl();
595 BI.Name = B.getType().getAsString();
598 BI.Name = Base->getNameAsString();
601 for (
const auto &
Decl : Base->decls())
602 if (
const auto *
MD = dyn_cast<CXXMethodDecl>(
Decl)) {
604 if (
MD->getAccessUnsafe() == AccessSpecifier::AS_private ||
605 !
MD->isUserProvided())
612 bool IsInAnonymousNamespace;
615 IsInAnonymousNamespace);
618 BI.Children.Functions.emplace_back(std::move(FI));
620 I.
Bases.emplace_back(std::move(BI));
625 I.
Bases.back().Access);
631std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
632emitInfo(
const NamespaceDecl *D,
const FullComment *FC,
int LineNumber,
633 llvm::StringRef File,
bool IsFileInRootDir,
bool PublicOnly) {
634 auto I = std::make_unique<NamespaceInfo>();
635 bool IsInAnonymousNamespace =
false;
640 I->Name = D->isAnonymousNamespace()
641 ? llvm::SmallString<16>(
"@nonymous_namespace")
644 if (I->Namespace.empty() && I->USR ==
SymbolID())
645 return {std::unique_ptr<Info>{std::move(I)},
nullptr};
649 return {std::move(I), MakeAndInsertIntoParent<const NamespaceInfo &>(*I)};
652std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
653emitInfo(
const RecordDecl *D,
const FullComment *FC,
int LineNumber,
654 llvm::StringRef File,
bool IsFileInRootDir,
bool PublicOnly) {
655 auto I = std::make_unique<RecordInfo>();
656 bool IsInAnonymousNamespace =
false;
658 IsInAnonymousNamespace);
662 I->TagType = D->getTagKind();
664 if (
const auto *
C = dyn_cast<CXXRecordDecl>(D)) {
665 if (
const TypedefNameDecl *TD =
C->getTypedefNameForAnonDecl()) {
666 I->Name = TD->getNameAsString();
678 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
680 I->Template.emplace();
681 I->Template->Specialization.emplace();
682 auto &Specialization = *I->Template->Specialization;
685 auto SpecOf = CTSD->getSpecializedTemplateOrPartial();
686 if (SpecOf.is<ClassTemplateDecl *>()) {
687 Specialization.SpecializationOf =
689 }
else if (SpecOf.is<ClassTemplatePartialSpecializationDecl *>()) {
690 Specialization.SpecializationOf =
691 getUSRForDecl(SpecOf.get<ClassTemplatePartialSpecializationDecl *>());
699 if (
const ClassTemplatePartialSpecializationDecl *CTPSD =
700 dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) {
701 if (
const ASTTemplateArgumentListInfo *AsWritten =
702 CTPSD->getTemplateArgsAsWritten()) {
703 for (
unsigned i = 0; i < AsWritten->getNumTemplateArgs(); i++) {
704 Specialization.Params.emplace_back(
709 for (
const TemplateArgument &Arg : CTSD->getTemplateArgs().asArray()) {
717 auto Parent = MakeAndInsertIntoParent<const RecordInfo &>(*I);
718 return {std::move(I), std::move(
Parent)};
721std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
722emitInfo(
const FunctionDecl *D,
const FullComment *FC,
int LineNumber,
723 llvm::StringRef File,
bool IsFileInRootDir,
bool PublicOnly) {
725 bool IsInAnonymousNamespace =
false;
727 IsInAnonymousNamespace);
728 Func.
Access = clang::AccessSpecifier::AS_none;
733 return {
nullptr, MakeAndInsertIntoParent<FunctionInfo &&>(std::move(Func))};
736std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
737emitInfo(
const CXXMethodDecl *D,
const FullComment *FC,
int LineNumber,
738 llvm::StringRef File,
bool IsFileInRootDir,
bool PublicOnly) {
740 bool IsInAnonymousNamespace =
false;
742 IsInAnonymousNamespace);
748 const NamedDecl *
Parent =
nullptr;
750 dyn_cast<ClassTemplateSpecializationDecl>(D->getParent()))
751 Parent = SD->getSpecializedTemplate();
758 Parent->getQualifiedNameAsString()};
759 Func.
Access = D->getAccess();
762 return {
nullptr, MakeAndInsertIntoParent<FunctionInfo &&>(std::move(Func))};
765std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
766emitInfo(
const TypedefDecl *D,
const FullComment *FC,
int LineNumber,
767 StringRef File,
bool IsFileInRootDir,
bool PublicOnly) {
770 bool IsInAnonymousNamespace =
false;
775 Info.DefLoc.emplace(LineNumber, File, IsFileInRootDir);
777 if (
Info.Underlying.Type.
Name.empty()) {
783 Info.IsUsing =
false;
786 return {
nullptr, MakeAndInsertIntoParent<TypedefInfo &&>(std::move(
Info))};
791std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
792emitInfo(
const TypeAliasDecl *D,
const FullComment *FC,
int LineNumber,
793 StringRef File,
bool IsFileInRootDir,
bool PublicOnly) {
796 bool IsInAnonymousNamespace =
false;
801 Info.DefLoc.emplace(LineNumber, File, IsFileInRootDir);
806 return {
nullptr, MakeAndInsertIntoParent<TypedefInfo &&>(std::move(
Info))};
809std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
810emitInfo(
const EnumDecl *D,
const FullComment *FC,
int LineNumber,
811 llvm::StringRef File,
bool IsFileInRootDir,
bool PublicOnly) {
813 bool IsInAnonymousNamespace =
false;
815 IsInAnonymousNamespace);
819 Enum.Scoped = D->isScoped();
821 auto Name = D->getIntegerType().getAsString();
827 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)
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)
TypeInfo getTypeInfoForType(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
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