summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-doc/Serialize.cpp
diff options
context:
space:
mode:
authorJulie Hockett <juliehockett@google.com>2018-03-21 21:21:45 +0000
committerJulie Hockett <juliehockett@google.com>2018-03-21 21:21:45 +0000
commit1442a5dd3ad91e0a57bf8677a58ca87a6bf54041 (patch)
tree19c3a663a4588dada0a638dcf372e69a03e44fe5 /clang-tools-extra/clang-doc/Serialize.cpp
parentcd0efec2b4fc574b50291a4dcd230cad520b7a12 (diff)
downloadbcm5719-llvm-1442a5dd3ad91e0a57bf8677a58ca87a6bf54041.tar.gz
bcm5719-llvm-1442a5dd3ad91e0a57bf8677a58ca87a6bf54041.zip
[clang-doc] Reland "[clang-doc] Setup clang-doc frontend framework"
Fixing the the failing Windows tests. llvm-svn: 328150
Diffstat (limited to 'clang-tools-extra/clang-doc/Serialize.cpp')
-rw-r--r--clang-tools-extra/clang-doc/Serialize.cpp336
1 files changed, 336 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp
new file mode 100644
index 00000000000..ccde579b181
--- /dev/null
+++ b/clang-tools-extra/clang-doc/Serialize.cpp
@@ -0,0 +1,336 @@
+//===-- Serializer.cpp - ClangDoc Serializer --------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Serialize.h"
+#include "BitcodeWriter.h"
+#include "clang/AST/Comment.h"
+#include "clang/Index/USRGeneration.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/SHA1.h"
+
+using clang::comments::FullComment;
+
+namespace clang {
+namespace doc {
+namespace serialize {
+
+SymbolID hashUSR(llvm::StringRef USR) {
+ return llvm::SHA1::hash(arrayRefFromStringRef(USR));
+}
+
+class ClangDocCommentVisitor
+ : public ConstCommentVisitor<ClangDocCommentVisitor> {
+public:
+ ClangDocCommentVisitor(CommentInfo &CI) : CurrentCI(CI) {}
+
+ void parseComment(const comments::Comment *C);
+
+ void visitTextComment(const TextComment *C);
+ void visitInlineCommandComment(const InlineCommandComment *C);
+ void visitHTMLStartTagComment(const HTMLStartTagComment *C);
+ void visitHTMLEndTagComment(const HTMLEndTagComment *C);
+ void visitBlockCommandComment(const BlockCommandComment *C);
+ void visitParamCommandComment(const ParamCommandComment *C);
+ void visitTParamCommandComment(const TParamCommandComment *C);
+ void visitVerbatimBlockComment(const VerbatimBlockComment *C);
+ void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
+ void visitVerbatimLineComment(const VerbatimLineComment *C);
+
+private:
+ std::string getCommandName(unsigned CommandID) const;
+ bool isWhitespaceOnly(StringRef S) const;
+
+ CommentInfo &CurrentCI;
+};
+
+void ClangDocCommentVisitor::parseComment(const comments::Comment *C) {
+ CurrentCI.Kind = C->getCommentKindName();
+ ConstCommentVisitor<ClangDocCommentVisitor>::visit(C);
+ for (comments::Comment *Child :
+ llvm::make_range(C->child_begin(), C->child_end())) {
+ CurrentCI.Children.emplace_back(llvm::make_unique<CommentInfo>());
+ ClangDocCommentVisitor Visitor(*CurrentCI.Children.back());
+ Visitor.parseComment(Child);
+ }
+}
+
+void ClangDocCommentVisitor::visitTextComment(const TextComment *C) {
+ if (!isWhitespaceOnly(C->getText()))
+ CurrentCI.Text = C->getText();
+}
+
+void ClangDocCommentVisitor::visitInlineCommandComment(
+ const InlineCommandComment *C) {
+ CurrentCI.Name = getCommandName(C->getCommandID());
+ for (unsigned I = 0, E = C->getNumArgs(); I != E; ++I)
+ CurrentCI.Args.push_back(C->getArgText(I));
+}
+
+void ClangDocCommentVisitor::visitHTMLStartTagComment(
+ const HTMLStartTagComment *C) {
+ CurrentCI.Name = C->getTagName();
+ CurrentCI.SelfClosing = C->isSelfClosing();
+ for (unsigned I = 0, E = C->getNumAttrs(); I < E; ++I) {
+ const HTMLStartTagComment::Attribute &Attr = C->getAttr(I);
+ CurrentCI.AttrKeys.push_back(Attr.Name);
+ CurrentCI.AttrValues.push_back(Attr.Value);
+ }
+}
+
+void ClangDocCommentVisitor::visitHTMLEndTagComment(
+ const HTMLEndTagComment *C) {
+ CurrentCI.Name = C->getTagName();
+ CurrentCI.SelfClosing = true;
+}
+
+void ClangDocCommentVisitor::visitBlockCommandComment(
+ const BlockCommandComment *C) {
+ CurrentCI.Name = getCommandName(C->getCommandID());
+ for (unsigned I = 0, E = C->getNumArgs(); I < E; ++I)
+ CurrentCI.Args.push_back(C->getArgText(I));
+}
+
+void ClangDocCommentVisitor::visitParamCommandComment(
+ const ParamCommandComment *C) {
+ CurrentCI.Direction =
+ ParamCommandComment::getDirectionAsString(C->getDirection());
+ CurrentCI.Explicit = C->isDirectionExplicit();
+ if (C->hasParamName())
+ CurrentCI.ParamName = C->getParamNameAsWritten();
+}
+
+void ClangDocCommentVisitor::visitTParamCommandComment(
+ const TParamCommandComment *C) {
+ if (C->hasParamName())
+ CurrentCI.ParamName = C->getParamNameAsWritten();
+}
+
+void ClangDocCommentVisitor::visitVerbatimBlockComment(
+ const VerbatimBlockComment *C) {
+ CurrentCI.Name = getCommandName(C->getCommandID());
+ CurrentCI.CloseName = C->getCloseName();
+}
+
+void ClangDocCommentVisitor::visitVerbatimBlockLineComment(
+ const VerbatimBlockLineComment *C) {
+ if (!isWhitespaceOnly(C->getText()))
+ CurrentCI.Text = C->getText();
+}
+
+void ClangDocCommentVisitor::visitVerbatimLineComment(
+ const VerbatimLineComment *C) {
+ if (!isWhitespaceOnly(C->getText()))
+ CurrentCI.Text = C->getText();
+}
+
+bool ClangDocCommentVisitor::isWhitespaceOnly(llvm::StringRef S) const {
+ return std::all_of(S.begin(), S.end(), isspace);
+}
+
+std::string ClangDocCommentVisitor::getCommandName(unsigned CommandID) const {
+ const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID);
+ if (Info)
+ return Info->Name;
+ // TODO: Add parsing for \file command.
+ return "<not a builtin command>";
+}
+
+// Serializing functions.
+
+template <typename T> static std::string serialize(T &I) {
+ SmallString<2048> Buffer;
+ llvm::BitstreamWriter Stream(Buffer);
+ ClangDocBitcodeWriter Writer(Stream);
+ Writer.emitBlock(I);
+ return Buffer.str().str();
+}
+
+static void parseFullComment(const FullComment *C, CommentInfo &CI) {
+ ClangDocCommentVisitor Visitor(CI);
+ Visitor.parseComment(C);
+}
+
+static SymbolID getUSRForDecl(const Decl *D) {
+ llvm::SmallString<128> USR;
+ if (index::generateUSRForDecl(D, USR))
+ return SymbolID();
+ return hashUSR(USR);
+}
+
+static RecordDecl *getDeclForType(const QualType &T) {
+ auto *Ty = T->getAs<RecordType>();
+ if (!Ty)
+ return nullptr;
+ return Ty->getDecl()->getDefinition();
+}
+
+static void parseFields(RecordInfo &I, const RecordDecl *D) {
+ for (const FieldDecl *F : D->fields()) {
+ // FIXME: Set Access to the appropriate value.
+ SymbolID Type;
+ std::string Name;
+ InfoType RefType;
+ if (const auto *T = getDeclForType(F->getTypeSourceInfo()->getType())) {
+ Type = getUSRForDecl(T);
+ if (dyn_cast<EnumDecl>(T))
+ RefType = InfoType::IT_enum;
+ else if (dyn_cast<RecordDecl>(T))
+ RefType = InfoType::IT_record;
+ I.Members.emplace_back(Type, RefType, F->getQualifiedNameAsString());
+ } else {
+ Name = F->getTypeSourceInfo()->getType().getAsString();
+ I.Members.emplace_back(Name, F->getQualifiedNameAsString());
+ }
+ }
+}
+
+static void parseEnumerators(EnumInfo &I, const EnumDecl *D) {
+ for (const EnumConstantDecl *E : D->enumerators())
+ I.Members.emplace_back(E->getNameAsString());
+}
+
+static void parseParameters(FunctionInfo &I, const FunctionDecl *D) {
+ for (const ParmVarDecl *P : D->parameters()) {
+ SymbolID Type;
+ std::string Name;
+ InfoType RefType;
+ if (const auto *T = getDeclForType(P->getOriginalType())) {
+ Type = getUSRForDecl(T);
+ if (dyn_cast<EnumDecl>(T))
+ RefType = InfoType::IT_enum;
+ else if (dyn_cast<RecordDecl>(T))
+ RefType = InfoType::IT_record;
+ I.Params.emplace_back(Type, RefType, P->getQualifiedNameAsString());
+ } else {
+ Name = P->getOriginalType().getAsString();
+ I.Params.emplace_back(Name, P->getQualifiedNameAsString());
+ }
+ }
+}
+
+static void parseBases(RecordInfo &I, const CXXRecordDecl *D) {
+ for (const CXXBaseSpecifier &B : D->bases()) {
+ if (B.isVirtual())
+ continue;
+ if (const auto *P = getDeclForType(B.getType()))
+ I.Parents.emplace_back(getUSRForDecl(P), InfoType::IT_record);
+ else
+ I.Parents.emplace_back(B.getType().getAsString());
+ }
+ for (const CXXBaseSpecifier &B : D->vbases()) {
+ if (const auto *P = getDeclForType(B.getType()))
+ I.VirtualParents.emplace_back(getUSRForDecl(P), InfoType::IT_record);
+ else
+ I.VirtualParents.emplace_back(B.getType().getAsString());
+ }
+}
+
+template <typename T>
+static void
+populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
+ const T *D) {
+ const auto *DC = dyn_cast<DeclContext>(D);
+ while ((DC = DC->getParent())) {
+ if (const auto *N = dyn_cast<NamespaceDecl>(DC))
+ Namespaces.emplace_back(getUSRForDecl(N), InfoType::IT_namespace);
+ else if (const auto *N = dyn_cast<RecordDecl>(DC))
+ Namespaces.emplace_back(getUSRForDecl(N), InfoType::IT_record);
+ else if (const auto *N = dyn_cast<FunctionDecl>(DC))
+ Namespaces.emplace_back(getUSRForDecl(N), InfoType::IT_function);
+ else if (const auto *N = dyn_cast<EnumDecl>(DC))
+ Namespaces.emplace_back(getUSRForDecl(N), InfoType::IT_enum);
+ }
+}
+
+template <typename T>
+static void populateInfo(Info &I, const T *D, const FullComment *C) {
+ I.USR = getUSRForDecl(D);
+ I.Name = D->getNameAsString();
+ populateParentNamespaces(I.Namespace, D);
+ if (C) {
+ I.Description.emplace_back();
+ parseFullComment(C, I.Description.back());
+ }
+}
+
+template <typename T>
+static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C,
+ int LineNumber, StringRef Filename) {
+ populateInfo(I, D, C);
+ if (D->isThisDeclarationADefinition())
+ I.DefLoc.emplace(LineNumber, Filename);
+ else
+ I.Loc.emplace_back(LineNumber, Filename);
+}
+
+static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
+ const FullComment *FC, int LineNumber,
+ StringRef Filename) {
+ populateSymbolInfo(I, D, FC, LineNumber, Filename);
+ if (const auto *T = getDeclForType(D->getReturnType())) {
+ I.ReturnType.Type.USR = getUSRForDecl(T);
+ if (dyn_cast<EnumDecl>(T))
+ I.ReturnType.Type.RefType = InfoType::IT_enum;
+ else if (dyn_cast<RecordDecl>(T))
+ I.ReturnType.Type.RefType = InfoType::IT_record;
+ } else {
+ I.ReturnType.Type.UnresolvedName = D->getReturnType().getAsString();
+ }
+ parseParameters(I, D);
+}
+
+std::string emitInfo(const NamespaceDecl *D, const FullComment *FC,
+ int LineNumber, llvm::StringRef File) {
+ NamespaceInfo I;
+ populateInfo(I, D, FC);
+ return serialize(I);
+}
+
+std::string emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber,
+ llvm::StringRef File) {
+ RecordInfo I;
+ populateSymbolInfo(I, D, FC, LineNumber, File);
+ I.TagType = D->getTagKind();
+ parseFields(I, D);
+ if (const auto *C = dyn_cast<CXXRecordDecl>(D))
+ parseBases(I, C);
+ return serialize(I);
+}
+
+std::string emitInfo(const FunctionDecl *D, const FullComment *FC,
+ int LineNumber, llvm::StringRef File) {
+ FunctionInfo I;
+ populateFunctionInfo(I, D, FC, LineNumber, File);
+ I.Access = clang::AccessSpecifier::AS_none;
+ return serialize(I);
+}
+
+std::string emitInfo(const CXXMethodDecl *D, const FullComment *FC,
+ int LineNumber, llvm::StringRef File) {
+ FunctionInfo I;
+ populateFunctionInfo(I, D, FC, LineNumber, File);
+ I.IsMethod = true;
+ I.Parent = Reference(getUSRForDecl(D->getParent()), InfoType::IT_record);
+ I.Access = D->getAccess();
+ return serialize(I);
+}
+
+std::string emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber,
+ llvm::StringRef File) {
+ EnumInfo I;
+ populateSymbolInfo(I, D, FC, LineNumber, File);
+ I.Scoped = D->isScoped();
+ parseEnumerators(I, D);
+ return serialize(I);
+}
+
+} // namespace serialize
+} // namespace doc
+} // namespace clang
OpenPOWER on IntegriCloud