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>
47 llvm::SmallString<128>
Path;
48 for (
auto R = Namespaces.rbegin(),
E = Namespaces.rend(); R !=
E; ++R)
49 llvm::sys::path::append(Path, R->Name);
54 llvm::SmallVector<Reference, 4> Namespaces;
82 std::string getCommandName(
unsigned CommandID)
const;
83 bool isWhitespaceOnly(StringRef S)
const;
89 CurrentCI.
Kind = C->getCommentKindName();
91 for (comments::Comment *Child :
92 llvm::make_range(C->child_begin(), C->child_end())) {
93 CurrentCI.
Children.emplace_back(std::make_unique<CommentInfo>());
100 if (!isWhitespaceOnly(C->getText()))
101 CurrentCI.
Text = C->getText();
105 const InlineCommandComment *C) {
106 CurrentCI.
Name = getCommandName(C->getCommandID());
107 for (
unsigned I = 0,
E = C->getNumArgs(); I !=
E; ++I)
108 CurrentCI.
Args.push_back(C->getArgText(I));
112 const HTMLStartTagComment *C) {
113 CurrentCI.
Name = C->getTagName();
115 for (
unsigned I = 0,
E = C->getNumAttrs(); I <
E; ++I) {
116 const HTMLStartTagComment::Attribute &Attr = C->getAttr(I);
117 CurrentCI.
AttrKeys.push_back(Attr.Name);
123 const HTMLEndTagComment *C) {
124 CurrentCI.
Name = C->getTagName();
129 const BlockCommandComment *C) {
130 CurrentCI.
Name = getCommandName(C->getCommandID());
131 for (
unsigned I = 0,
E = C->getNumArgs(); I <
E; ++I)
132 CurrentCI.
Args.push_back(C->getArgText(I));
136 const ParamCommandComment *C) {
138 ParamCommandComment::getDirectionAsString(C->getDirection());
139 CurrentCI.
Explicit = C->isDirectionExplicit();
140 if (C->hasParamName())
141 CurrentCI.
ParamName = C->getParamNameAsWritten();
145 const TParamCommandComment *C) {
146 if (C->hasParamName())
147 CurrentCI.
ParamName = C->getParamNameAsWritten();
151 const VerbatimBlockComment *C) {
152 CurrentCI.
Name = getCommandName(C->getCommandID());
157 const VerbatimBlockLineComment *C) {
158 if (!isWhitespaceOnly(C->getText()))
159 CurrentCI.
Text = C->getText();
163 const VerbatimLineComment *C) {
164 if (!isWhitespaceOnly(C->getText()))
165 CurrentCI.
Text = C->getText();
168 bool ClangDocCommentVisitor::isWhitespaceOnly(llvm::StringRef S)
const {
169 return std::all_of(S.begin(), S.end(), isspace);
172 std::string ClangDocCommentVisitor::getCommandName(
unsigned CommandID)
const {
173 const CommandInfo *
Info = CommandTraits::getBuiltinCommandInfo(CommandID);
177 return "<not a builtin command>";
182 template <
typename T>
static std::string
serialize(T &I) {
183 SmallString<2048> Buffer;
184 llvm::BitstreamWriter Stream(Buffer);
187 return Buffer.str().str();
193 return serialize(*static_cast<NamespaceInfo *>(I.get()));
195 return serialize(*static_cast<RecordInfo *>(I.get()));
197 return serialize(*static_cast<EnumInfo *>(I.get()));
199 return serialize(*static_cast<FunctionInfo *>(I.get()));
211 llvm::SmallString<128> USR;
212 if (index::generateUSRForDecl(D, USR))
218 if (
const RecordDecl *D = T->getAsRecordDecl())
219 return D->getDefinition();
223 static bool isPublic(
const clang::AccessSpecifier AS,
224 const clang::Linkage Link) {
225 if (AS == clang::AccessSpecifier::AS_private)
227 else if ((Link == clang::Linkage::ModuleLinkage) ||
228 (Link == clang::Linkage::ExternalLinkage))
234 const NamedDecl *D) {
235 bool IsAnonymousNamespace =
false;
236 if (
const auto *N = dyn_cast<NamespaceDecl>(D))
237 IsAnonymousNamespace = N->isAnonymousNamespace();
238 return !PublicOnly ||
239 (!IsInAnonymousNamespace && !IsAnonymousNamespace &&
240 isPublic(D->getAccessUnsafe(), D->getLinkageInternal()));
259 AccessSpecifier SecondAS) {
260 if (FirstAS == AccessSpecifier::AS_none ||
261 SecondAS == AccessSpecifier::AS_none)
262 return AccessSpecifier::AS_none;
263 if (FirstAS == AccessSpecifier::AS_private ||
264 SecondAS == AccessSpecifier::AS_private)
265 return AccessSpecifier::AS_private;
266 if (FirstAS == AccessSpecifier::AS_protected ||
267 SecondAS == AccessSpecifier::AS_protected)
268 return AccessSpecifier::AS_protected;
269 return AccessSpecifier::AS_public;
275 AccessSpecifier Access = AccessSpecifier::AS_public) {
276 for (
const FieldDecl *F : D->fields()) {
279 if (
const auto *T =
getDeclForType(F->getTypeSourceInfo()->getType())) {
282 if (
const auto *N = dyn_cast<EnumDecl>(T)) {
288 }
else if (
const auto *N = dyn_cast<RecordDecl>(T)) {
297 F->getTypeSourceInfo()->getType().getAsString(), F->getNameAsString(),
303 for (
const EnumConstantDecl *
E : D->enumerators())
304 I.
Members.emplace_back(
E->getNameAsString());
308 for (
const ParmVarDecl *P : D->parameters()) {
310 if (
const auto *N = dyn_cast<EnumDecl>(T)) {
313 P->getNameAsString());
315 }
else if (
const auto *N = dyn_cast<RecordDecl>(T)) {
318 P->getNameAsString());
322 I.
Params.emplace_back(P->getOriginalType().getAsString(),
323 P->getNameAsString());
331 if (!D->isThisDeclarationADefinition())
333 for (
const CXXBaseSpecifier &B : D->bases()) {
336 if (
const auto *Ty = B.getType()->getAs<TemplateSpecializationType>()) {
337 const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl();
344 I.
Parents.emplace_back(B.getType().getAsString());
346 for (
const CXXBaseSpecifier &B : D->vbases()) {
356 template <
typename T>
359 const T *D,
bool &IsInAnonymousNamespace) {
360 const auto *DC = dyn_cast<DeclContext>(D);
361 while ((DC = DC->getParent())) {
362 if (
const auto *N = dyn_cast<NamespaceDecl>(DC)) {
363 std::string Namespace;
364 if (N->isAnonymousNamespace()) {
365 Namespace =
"@nonymous_namespace";
366 IsInAnonymousNamespace =
true;
368 Namespace = N->getNameAsString();
371 }
else if (
const auto *N = dyn_cast<RecordDecl>(DC))
372 Namespaces.emplace_back(
getUSRForDecl(N), N->getNameAsString(),
374 else if (
const auto *N = dyn_cast<FunctionDecl>(DC))
375 Namespaces.emplace_back(
getUSRForDecl(N), N->getNameAsString(),
377 else if (
const auto *N = dyn_cast<EnumDecl>(DC))
378 Namespaces.emplace_back(
getUSRForDecl(N), N->getNameAsString(),
385 if ((Namespaces.empty() && dyn_cast<RecordDecl>(D)) ||
387 Namespaces.emplace_back(
SymbolID(),
"GlobalNamespace",
391 template <
typename T>
393 bool &IsInAnonymousNamespace) {
395 I.
Name = D->getNameAsString();
403 template <
typename T>
406 bool IsFileInRootDir,
407 bool &IsInAnonymousNamespace) {
409 if (D->isThisDeclarationADefinition())
410 I.
DefLoc.emplace(LineNumber, Filename, IsFileInRootDir);
412 I.
Loc.emplace_back(LineNumber, Filename, IsFileInRootDir);
416 const FullComment *FC,
int LineNumber,
417 StringRef
Filename,
bool IsFileInRootDir,
418 bool &IsInAnonymousNamespace) {
420 IsInAnonymousNamespace);
422 if (dyn_cast<EnumDecl>(T))
425 else if (dyn_cast<RecordDecl>(T))
437 AccessSpecifier ParentAccess = AccessSpecifier::AS_public) {
439 if (!D->isThisDeclarationADefinition())
441 for (
const CXXBaseSpecifier &B : D->bases()) {
442 if (
const RecordType *Ty = B.getType()->getAs<RecordType>()) {
443 if (
const CXXRecordDecl *
Base =
444 cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition())) {
451 if (
const auto *Ty = B.getType()->getAs<TemplateSpecializationType>()) {
452 const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl();
454 BI.
Name = B.getType().getAsString();
460 for (
const auto &
Decl :
Base->decls())
461 if (
const auto *
MD = dyn_cast<CXXMethodDecl>(
Decl)) {
463 if (
MD->getAccessUnsafe() == AccessSpecifier::AS_private ||
464 !
MD->isUserProvided())
471 bool IsInAnonymousNamespace;
474 IsInAnonymousNamespace);
479 I.
Bases.emplace_back(std::move(BI));
484 I.
Bases.back().Access);
490 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
491 emitInfo(
const NamespaceDecl *D,
const FullComment *FC,
int LineNumber,
492 llvm::StringRef File,
bool IsFileInRootDir,
bool PublicOnly) {
493 auto I = std::make_unique<NamespaceInfo>();
494 bool IsInAnonymousNamespace =
false;
499 I->Name = D->isAnonymousNamespace()
500 ? llvm::SmallString<16>(
"@nonymous_namespace")
503 if (I->Namespace.empty() && I->USR ==
SymbolID())
504 return {std::unique_ptr<Info>{std::move(I)},
nullptr};
506 auto ParentI = std::make_unique<NamespaceInfo>();
507 ParentI->USR = I->Namespace.empty() ?
SymbolID() : I->Namespace[0].USR;
510 if (I->Namespace.empty())
512 return {std::unique_ptr<Info>{std::move(I)},
513 std::unique_ptr<Info>{std::move(ParentI)}};
516 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
517 emitInfo(
const RecordDecl *D,
const FullComment *FC,
int LineNumber,
518 llvm::StringRef File,
bool IsFileInRootDir,
bool PublicOnly) {
519 auto I = std::make_unique<RecordInfo>();
520 bool IsInAnonymousNamespace =
false;
522 IsInAnonymousNamespace);
526 I->TagType = D->getTagKind();
528 if (
const auto *C = dyn_cast<CXXRecordDecl>(D)) {
529 if (
const TypedefNameDecl *TD = C->getTypedefNameForAnonDecl()) {
530 I->Name = TD->getNameAsString();
535 parseBases(*I, C, IsFileInRootDir, PublicOnly,
true);
539 switch (I->Namespace[0].RefType) {
541 auto ParentI = std::make_unique<NamespaceInfo>();
542 ParentI->USR = I->Namespace[0].USR;
545 return {std::unique_ptr<Info>{std::move(I)},
546 std::unique_ptr<Info>{std::move(ParentI)}};
549 auto ParentI = std::make_unique<RecordInfo>();
550 ParentI->USR = I->Namespace[0].USR;
553 return {std::unique_ptr<Info>{std::move(I)},
554 std::unique_ptr<Info>{std::move(ParentI)}};
557 llvm_unreachable(
"Invalid reference type for parent namespace");
561 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
562 emitInfo(
const FunctionDecl *D,
const FullComment *FC,
int LineNumber,
563 llvm::StringRef File,
bool IsFileInRootDir,
bool PublicOnly) {
565 bool IsInAnonymousNamespace =
false;
567 IsInAnonymousNamespace);
568 Func.
Access = clang::AccessSpecifier::AS_none;
573 auto ParentI = std::make_unique<NamespaceInfo>();
580 ParentI->ChildFunctions.emplace_back(std::move(Func));
582 return {
nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
585 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
586 emitInfo(
const CXXMethodDecl *D,
const FullComment *FC,
int LineNumber,
587 llvm::StringRef File,
bool IsFileInRootDir,
bool PublicOnly) {
589 bool IsInAnonymousNamespace =
false;
591 IsInAnonymousNamespace);
597 const NamedDecl *
Parent =
nullptr;
599 dyn_cast<ClassTemplateSpecializationDecl>(D->getParent()))
600 Parent = SD->getSpecializedTemplate();
602 Parent = D->getParent();
607 Func.
Access = D->getAccess();
610 auto ParentI = std::make_unique<RecordInfo>();
611 ParentI->USR = ParentUSR;
612 ParentI->ChildFunctions.emplace_back(std::move(Func));
614 return {
nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
617 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
618 emitInfo(
const EnumDecl *D,
const FullComment *FC,
int LineNumber,
619 llvm::StringRef File,
bool IsFileInRootDir,
bool PublicOnly) {
621 bool IsInAnonymousNamespace =
false;
623 IsInAnonymousNamespace);
627 Enum.
Scoped = D->isScoped();
632 auto ParentI = std::make_unique<NamespaceInfo>();
634 ParentI->ChildEnums.emplace_back(std::move(Enum));
638 return {
nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
644 auto ParentI = std::make_unique<NamespaceInfo>();
646 ParentI->ChildEnums.emplace_back(std::move(Enum));
649 return {
nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
652 auto ParentI = std::make_unique<RecordInfo>();
654 ParentI->ChildEnums.emplace_back(std::move(Enum));
657 return {
nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
660 llvm_unreachable(
"Invalid reference type for parent namespace");
llvm::SmallVector< Reference, 4 > Namespace
const FunctionDecl * Decl
static void parseFullComment(const FullComment *C, CommentInfo &CI)
std::vector< BaseRecordInfo > Bases
static bool shouldSerializeInfo(bool PublicOnly, bool IsInAnonymousNamespace, const NamedDecl *D)
void emitBlock(const NamespaceInfo &I)
llvm::Optional< Location > DefLoc
std::vector< FunctionInfo > ChildFunctions
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)
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)
static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C, int LineNumber, StringRef Filename, bool IsFileInRootDir, bool &IsInAnonymousNamespace)
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
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)
static void parseFields(RecordInfo &I, const RecordDecl *D, bool PublicOnly, AccessSpecifier Access=AccessSpecifier::AS_public)
llvm::SmallVector< Reference, 4 > Parents
static bool isPublic(const clang::AccessSpecifier AS, const clang::Linkage Link)
static AccessSpecifier getFinalAccessSpecifier(AccessSpecifier FirstAS, AccessSpecifier SecondAS)
static void parseParameters(FunctionInfo &I, const FunctionDecl *D)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static GeneratorRegistry::Add< MDGenerator > MD(MDGenerator::Format, "Generator for MD output.")
static SymbolID getUSRForDecl(const Decl *D)
static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D, const FullComment *FC, int LineNumber, StringRef Filename, bool IsFileInRootDir, bool &IsInAnonymousNamespace)
llvm::SmallVector< MemberTypeInfo, 4 > Members
std::unique_ptr< GlobalCompilationDatabase > Base
static void populateInfo(Info &I, const T *D, const FullComment *C, bool &IsInAnonymousNamespace)
std::array< uint8_t, 20 > SymbolID
SymbolID hashUSR(llvm::StringRef USR)