juliehockett updated this revision to Diff 133108. juliehockett marked 27 inline comments as done. juliehockett edited the summary of this revision. juliehockett edited projects, added clang-tools-extra; removed clang. juliehockett added a comment.
1. Moved the tool to clang-tools-extra 1. Refactored tool to have two stages to the frontend parsing: the mapping stage (this patch), which uses ASTMatchers to extract declarations and serialize each into an individual key-value pair in the ExecutionContext, and the reducing stage (next patch, not yet implemented), which will take the records in the ExecutionContext and reduce them by key to produce and write the final output of the frontend. 1. Replaced the YAML serialization with bitcode serialization. Will update again with tests once I've implemented a simple decoder for the serial bitcode format. 2. Streamlined the emit*Info function call path. 3. Introduced a new layer into the Info inheritance to better represent each level. https://reviews.llvm.org/D41102 Files: CMakeLists.txt clang-doc/CMakeLists.txt clang-doc/ClangDoc.cpp clang-doc/ClangDoc.h clang-doc/ClangDocBinary.cpp clang-doc/ClangDocBinary.h clang-doc/ClangDocMapper.cpp clang-doc/ClangDocMapper.h clang-doc/tool/CMakeLists.txt clang-doc/tool/ClangDocMain.cpp docs/clang-doc.rst
Index: docs/clang-doc.rst =================================================================== --- /dev/null +++ docs/clang-doc.rst @@ -0,0 +1,13 @@ +=================== +Clang-Doc +=================== + +.. contents:: + +Intro + +Setup +===== + +Use +============ Index: clang-doc/tool/ClangDocMain.cpp =================================================================== --- /dev/null +++ clang-doc/tool/ClangDocMain.cpp @@ -0,0 +1,88 @@ +//===-- ClangDocMain.cpp - Clangdoc -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ClangDoc.h" +#include "clang/AST/AST.h" +#include "clang/AST/Decl.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchersInternal.h" +#include "clang/Driver/Options.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Tooling/CommonOptionsParser.h" +#include "clang/Tooling/Execution.h" +#include "clang/Tooling/StandaloneExecution.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/raw_ostream.h" +#include <string> + +using namespace clang::ast_matchers; +using namespace clang::tooling; +using namespace clang; +using namespace llvm; + +namespace { + +static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); +static cl::OptionCategory ClangDocCategory("clang-doc options"); + +static cl::opt<bool> DumpResult("dump", cl::desc("Dump results to stdout."), + cl::init(false), cl::cat(ClangDocCategory)); + +static cl::opt<bool> OmitFilenames("omit-filenames", cl::desc("Omit filenames in output."), + cl::init(false), cl::cat(ClangDocCategory)); + +static cl::opt<bool> DoxygenOnly("doxygen", cl::desc("Use only doxygen-style comments to generate docs."), + cl::init(false), cl::cat(ClangDocCategory)); + +} // namespace + +int main(int argc, const char **argv) { + sys::PrintStackTraceOnErrorSignal(argv[0]); + + auto Exec = clang::tooling::createExecutorFromCommandLineArgs( + argc, argv, ClangDocCategory); + + if (!Exec) { + errs() << toString(Exec.takeError()) << "\n"; + return 1; + } + + MatchFinder Finder; + ExecutionContext *ECtx = Exec->get()->getExecutionContext(); + + doc::ClangDocCallback NCallback("namespace", *ECtx, OmitFilenames); + Finder.addMatcher(namespaceDecl().bind("namespace"), &NCallback); + doc::ClangDocCallback RCallback("record", *ECtx, OmitFilenames); + Finder.addMatcher(recordDecl().bind("record"), &RCallback); + doc::ClangDocCallback ECallback("enum", *ECtx, OmitFilenames); + Finder.addMatcher(enumDecl().bind("enum"), &ECallback); + doc::ClangDocCallback MCallback("method", *ECtx, OmitFilenames); + Finder.addMatcher(cxxMethodDecl(isUserProvided()).bind("method"), &MCallback); + doc::ClangDocCallback FCallback("function", *ECtx, OmitFilenames); + Finder.addMatcher(functionDecl(unless(cxxMethodDecl())).bind("function"), &FCallback); + + ArgumentsAdjuster ArgAdjuster; + if (!DoxygenOnly) + ArgAdjuster = combineAdjusters(getInsertArgumentAdjuster("-fparse-all-comments", tooling::ArgumentInsertPosition::BEGIN), ArgAdjuster); + auto Err = Exec->get()->execute(newFrontendActionFactory(&Finder), ArgAdjuster); + if (Err) + errs() << toString(std::move(Err)) << "\n"; + + if (DumpResult) + Exec->get()->getToolResults()->forEachResult( + [](StringRef Key, StringRef Value) { + errs() << Key.str() << " -----\n" << Value.str() << "\n"; + }); + + return 0; +} Index: clang-doc/tool/CMakeLists.txt =================================================================== --- /dev/null +++ clang-doc/tool/CMakeLists.txt @@ -0,0 +1,18 @@ +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) + +add_clang_executable(clang-doc + ClangDocMain.cpp + ) + +target_link_libraries(clang-doc + PRIVATE + clangAST + clangASTMatchers + clangBasic + clangFormat + clangFrontend + clangDoc + clangRewrite + clangTooling + clangToolingCore + ) Index: clang-doc/ClangDocMapper.h =================================================================== --- /dev/null +++ clang-doc/ClangDocMapper.h @@ -0,0 +1,161 @@ +//===-- ClangDocMapper.cpp - ClangDocMapper -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_MAPPER_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_MAPPER_H + +#include "clang/AST/AST.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/CommentVisitor.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Frontend/ASTConsumers.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Tooling/Execution.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/raw_ostream.h" +#include <memory> +#include <string> +#include <vector> + +using namespace clang::comments; +using namespace clang::tooling; + +namespace clang { +namespace doc { + +/// A representation of a parsed comment. +struct CommentInfo { + StringRef Kind; + StringRef Text; + StringRef Name; + StringRef Direction; + StringRef ParamName; + StringRef CloseName; + bool SelfClosing = false; + bool Explicit = false; + llvm::SmallVector<StringRef, 4> AttrKeys; + llvm::SmallVector<StringRef, 4> AttrValues; + llvm::SmallVector<StringRef, 4> Args; + llvm::SmallVector<StringRef, 4> Position; + std::vector<CommentInfo> Children; +}; + +// TODO: Pull the CommentInfo for a parameter or member out of the record or +// function's CommentInfo. +// Info for named types (parameters, members). +struct NamedType { + std::string Type; + std::string Name; + AccessSpecifier Access = clang::AccessSpecifier::AS_none; + CommentInfo Description; +}; + +/// A base struct for Infos. +struct Info { + std::string FullyQualifiedName; + std::string SimpleName; + std::string Namespace; + CommentInfo Description; +}; + +struct NamespaceInfo : public Info {}; + +struct SymbolInfo : public Info { + int LineNumber; + StringRef Filename; +}; + +struct NonDefInfo : public SymbolInfo {}; + +// TODO: Expand to allow for documenting templating. +// Info for functions. +struct FunctionInfo : public SymbolInfo { + StringRef MangledName; + std::string Parent; + NamedType ReturnType; + llvm::SmallVector<NamedType, 4> Params; + AccessSpecifier Access; +}; + +// TODO: Expand to allow for documenting templating, inheritance access, +// friend classes +// Info for types. +struct RecordInfo : public SymbolInfo { + TagTypeKind TagType; + llvm::SmallVector<NamedType, 4> Members; + llvm::SmallVector<StringRef, 4> Parents; + llvm::SmallVector<StringRef, 4> VirtualParents; +}; + +// TODO: Expand to allow for documenting templating. +// Info for types. +struct EnumInfo : public SymbolInfo { + bool Scoped; + llvm::SmallVector<NamedType, 4> Members; +}; + +// TODO: Add functionality to include separate markdown pages. + +class ClangDocCommentVisitor : public ConstCommentVisitor<ClangDocCommentVisitor> { +public: + ClangDocCommentVisitor(CommentInfo &CI) : CurrentCI(CI) {} + + CommentInfo 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: + StringRef getCommandName(unsigned CommandID) const; + bool isWhitespaceOnly(StringRef S) const; + + CommentInfo CurrentCI; +}; + +class ClangDocMapper { +public: + ClangDocMapper(bool OmitFilenames) : OmitFilenames(OmitFilenames) {} + + template<class C> + StringRef emitInfo(const C *D, const FullComment *FC, StringRef Key, int LineNumber, StringRef File); + +private: + template<typename T> + StringRef serialize(T &I) const; + void populateSymbolInfo(SymbolInfo &I, StringRef Name, StringRef SimpleName, + StringRef Namespace, const FullComment *C, int LineNumber, StringRef File); + void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D, StringRef Name, const FullComment *C, + int LineNumber, StringRef File); + template <class C> + StringRef serializeNonDefInfo(const C *D,StringRef Name, const FullComment *FC, int LineNumber, StringRef File); + void parseFields(RecordInfo &I, const RecordDecl *D) const; + void parseEnumerators(EnumInfo &I, const EnumDecl *D) const; + void parseBases(RecordInfo &I, const CXXRecordDecl *D) const; + void parseParameters(FunctionInfo &I, const FunctionDecl *D) const; + CommentInfo parseFullComment(const FullComment *C); + StringRef getParentNamespace(const DeclContext *D) const; + + bool OmitFilenames; +}; + +} // namespace doc +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_MAPPER_H Index: clang-doc/ClangDocMapper.cpp =================================================================== --- /dev/null +++ clang-doc/ClangDocMapper.cpp @@ -0,0 +1,270 @@ +//===-- ClangDocMapper.cpp - ClangDoc Mapper ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ClangDocMapper.h" +#include "ClangDocBinary.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using clang::comments::FullComment; + +namespace clang { +namespace doc { + +// ClangDocMapper + +template <> StringRef ClangDocMapper::emitInfo(const NamespaceDecl *D, + const FullComment *FC, StringRef Name, int LineNumber, StringRef File) { + NamespaceInfo I; + I.FullyQualifiedName = Name; + I.SimpleName = D->getNameAsString(); + I.Namespace = getParentNamespace(D); + if (FC) I.Description = parseFullComment(FC); + return serialize(I); +} + +template <> StringRef ClangDocMapper::emitInfo(const RecordDecl *D, + const FullComment *FC, StringRef Name, int LineNumber, StringRef File) { + if (!D->isThisDeclarationADefinition()) + return serializeNonDefInfo(D, Name, FC, LineNumber, File); + RecordInfo I; + populateSymbolInfo(I, Name, D->getNameAsString(), getParentNamespace(D), FC, LineNumber, File); + I.TagType = D->getTagKind(); + if (const auto *CXXR = dyn_cast<CXXRecordDecl>(D)) + parseBases(I, CXXR); + parseFields(I, D); + return serialize(I); +} + +template <> StringRef ClangDocMapper::emitInfo(const FunctionDecl *D, + const FullComment *FC, StringRef Name, int LineNumber, StringRef File) { + if (!D->isThisDeclarationADefinition()) + return serializeNonDefInfo(D, Name, FC, LineNumber, File); + FunctionInfo I; + populateFunctionInfo(I, D, Name, FC, LineNumber, File); + I.Access = clang::AccessSpecifier::AS_none; + return serialize(I); +} + +template <> StringRef ClangDocMapper::emitInfo(const CXXMethodDecl *D, + const FullComment *FC, StringRef Name, int LineNumber, StringRef File) { + if (!D->isThisDeclarationADefinition()) + return serializeNonDefInfo(D, Name, FC, LineNumber, File); + FunctionInfo I; + populateFunctionInfo(I, D, Name, FC, LineNumber, File); + I.Parent = D->getParent()->getQualifiedNameAsString(); + I.Access = D->getAccess(); + return serialize(I); +} + +template <> StringRef ClangDocMapper::emitInfo(const EnumDecl *D, + const FullComment *FC, StringRef Name, int LineNumber, StringRef File) { + if (!D->isThisDeclarationADefinition()) + return serializeNonDefInfo(D, Name, FC, LineNumber, File); + EnumInfo I; + populateSymbolInfo(I, Name, D->getNameAsString(), getParentNamespace(D), FC, LineNumber, File); + I.Scoped = D->isScoped(); + parseEnumerators(I, D); + return serialize(I); +} + +template <typename T> +StringRef ClangDocMapper::serialize(T &I) const { + SmallString<128> Buffer; + llvm::BitstreamWriter Stream(Buffer); + ClangDocBinaryWriter Writer(Stream, OmitFilenames); + Writer.writeBitstream(I); + return Buffer; +} + +CommentInfo ClangDocMapper::parseFullComment(const FullComment *C) { + CommentInfo CI; + ClangDocCommentVisitor Visitor(CI); + return Visitor.parseComment(C); +} + +void ClangDocMapper::populateSymbolInfo(SymbolInfo &I, StringRef Name, + StringRef SimpleName, + StringRef Namespace, const FullComment *C, + int LineNumber, StringRef File) { + I.FullyQualifiedName = Name; + I.SimpleName = SimpleName; + I.Namespace = Namespace; + I.LineNumber = LineNumber; + I.Filename = File; + if (C) I.Description = parseFullComment(C); +} + +void ClangDocMapper::populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D, StringRef Name, const FullComment *C, + int LineNumber, StringRef File) { + populateSymbolInfo(I, D->getQualifiedNameAsString(), D->getNameAsString(), getParentNamespace(D), C, LineNumber, File); + I.MangledName = Name; + NamedType N; + N.Type = D->getReturnType().getAsString(); + I.ReturnType = N; + parseParameters(I, D); +} + +template <class C> +StringRef ClangDocMapper::serializeNonDefInfo(const C *D, StringRef Name, const FullComment *FC, + int LineNumber, StringRef File) { + NonDefInfo I; + I.FullyQualifiedName = Name; + I.SimpleName = D->getNameAsString(); + I.Namespace = getParentNamespace(D); + I.LineNumber = LineNumber; + I.Filename = File; + if (FC) I.Description = parseFullComment(FC); + return serialize(I); +} + + +void ClangDocMapper::parseFields(RecordInfo &I, const RecordDecl *D) const { + for (const FieldDecl *F : D->fields()) { + NamedType N; + N.Type = F->getTypeSourceInfo()->getType().getAsString(); + N.Name = F->getQualifiedNameAsString(); + // FIXME: Set Access to the appropriate value. + I.Members.emplace_back(N); + } +} + +void ClangDocMapper::parseEnumerators(EnumInfo &I, const EnumDecl *D) const { + for (const EnumConstantDecl *E : D->enumerators()) { + NamedType N; + N.Type = E->getQualifiedNameAsString(); + // FIXME: Set Access to the appropriate value. + I.Members.emplace_back(N); + } +} + +void ClangDocMapper::parseParameters(FunctionInfo &I, + const FunctionDecl *D) const { + for (const ParmVarDecl *P : D->parameters()){ + NamedType N; + N.Type = P->getOriginalType().getAsString(); + N.Name = P->getQualifiedNameAsString(); + // FIXME: Set Access to the appropriate value. + I.Params.emplace_back(N); + } +} + +void ClangDocMapper::parseBases(RecordInfo &I, const CXXRecordDecl *D) const { + for (const CXXBaseSpecifier &B : D->bases()) { + if (!B.isVirtual()) + I.Parents.push_back(B.getType().getAsString()); + } + for (const CXXBaseSpecifier &B : D->vbases()) + I.VirtualParents.push_back(B.getType().getAsString()); +} + +StringRef ClangDocMapper::getParentNamespace(const DeclContext *D) const { + if (const auto *N = dyn_cast<NamedDecl>(D->getParent())) + return N->getQualifiedNameAsString(); + return ""; +} + +// ClangDocCommentVisitor + +CommentInfo ClangDocCommentVisitor::parseComment(const comments::Comment *C) { + CurrentCI.Kind = C->getCommentKindName(); + ConstCommentVisitor<ClangDocCommentVisitor>::visit(C); + for (comments::Comment *Child : make_range(C->child_begin(), C->child_end())) { + CommentInfo ChildCI; + ClangDocCommentVisitor Visitor(ChildCI); + CurrentCI.Children.emplace_back(Visitor.parseComment(Child)); + } + return CurrentCI; +} + +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() && C->isParamIndexValid()) + CurrentCI.ParamName = C->getParamNameAsWritten(); +} + +void ClangDocCommentVisitor::visitTParamCommandComment( + const TParamCommandComment *C) { + if (C->hasParamName() && C->isPositionValid()) + CurrentCI.ParamName = C->getParamNameAsWritten(); + + if (C->isPositionValid()) { + for (unsigned i = 0, e = C->getDepth(); i < e; ++i) + CurrentCI.Position.push_back(std::to_string(C->getIndex(i))); + } +} + +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(); +} + +StringRef 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>"; +} + +bool ClangDocCommentVisitor::isWhitespaceOnly(StringRef S) const { + return S.find_first_not_of(" \t\n\v\f\r") == std::string::npos; +} + +} // namespace doc +} // namespace clang Index: clang-doc/ClangDocBinary.h =================================================================== --- /dev/null +++ clang-doc/ClangDocBinary.h @@ -0,0 +1,73 @@ +//===-- ClangDocBinGem.h - ClangDoc Binary Generator -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_BIN_GEN_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_BIN_GEN_H + +#include "ClangDocMapper.h" +#include "clang/AST/AST.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Bitcode/BitstreamWriter.h" +#include <vector> + +using namespace llvm; + +namespace clang { +namespace doc { + +class ClangDocBinaryWriter { +public: + ClangDocBinaryWriter(BitstreamWriter Stream, bool OmitFilenames) : Stream(Stream), OmitFilenames(OmitFilenames) {}; + + using RecordData = SmallVector<uint64_t, 64>; + using RecordDataImpl = SmallVectorImpl<uint64_t>; + + template <typename T> + void writeBitstream(const T &I); + +private: + void addString(StringRef Str, RecordDataImpl &Record); + void addComment(const CommentInfo &I, RecordDataImpl &Record); + void addNamedType(const NamedType &I, RecordDataImpl &Record); + void addNamedTypeVector(const SmallVector<NamedType, 4> &Vec, RecordDataImpl &Record); + void addStringVector(const SmallVector<StringRef, 4> &Vec, RecordDataImpl &Record); + void addInfo(const Info &I, RecordDataImpl &Record); + void addSymbolInfo(const SymbolInfo &I, RecordDataImpl &Record); + + BitstreamWriter &Stream; + bool OmitFilenames; +}; + +// TODO: Implement, and use for testing. +class ClangDocBinaryReader { +public: + ClangDocBinaryReader(BitstreamWriter Stream, bool OmitFilenames) : Stream(Stream), OmitFilenames(OmitFilenames) {}; + + using RecordData = SmallVector<uint64_t, 64>; + using RecordDataImpl = SmallVectorImpl<uint64_t>; + + std::string readBitstream(); + +private: + std::string readString(const RecordData &Record, unsigned &Idx); + std::string readComment(const RecordDataImpl &Record, unsigned &Idx); + std::string readNamedType(const RecordDataImpl &Record, unsigned &Idx); + std::string readNamedTypeVector(const RecordDataImpl &Record, unsigned &Idx); + std::string readStringVector(const RecordDataImpl &Record, unsigned &Idx); + std::string readInfo(const RecordDataImpl &Record, unsigned &Idx, Info &I); + std::string readSymbolInfo(const RecordDataImpl &Record, unsigned &Idx); + + BitstreamWriter &Stream; + bool OmitFilenames; +}; + +} +} + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_BIN_GEN_H Index: clang-doc/ClangDocBinary.cpp =================================================================== --- /dev/null +++ clang-doc/ClangDocBinary.cpp @@ -0,0 +1,113 @@ +//===-- ClangDocBinGem.cpp - ClangDoc Binary Generator ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ClangDocBinary.h" + +using namespace llvm; + +namespace clang { +namespace doc { + +enum InfoType {IT_nondef = 0, IT_namespace = 1, IT_function = 2, IT_record = 3, IT_enum = 4}; + +void ClangDocBinaryWriter::addString(StringRef Str, RecordDataImpl &Record) { + Record.push_back(Str.size()); + Record.insert(Record.end(), Str.begin(), Str.end()); + } + + // TODO: implement. + void ClangDocBinaryWriter::addComment(const CommentInfo &I, RecordDataImpl &Record) {} + +void ClangDocBinaryWriter::addNamedType(const NamedType &I, RecordDataImpl &Record) { + addString(I.Type, Record); + addString(I.Name, Record); + Record.push_back(I.Access); + addComment(I.Description, Record); +} + + void ClangDocBinaryWriter::addNamedTypeVector(const SmallVector<NamedType, 4> &Vec, RecordDataImpl &Record) { + Record.push_back(static_cast<unsigned>(Vec.size())); + for (const auto N : Vec) + addNamedType(N, Record); + } + + void ClangDocBinaryWriter::addStringVector(const SmallVector<StringRef, 4> &Vec, RecordDataImpl &Record) { + Record.push_back(static_cast<unsigned>(Vec.size())); + for (const auto S : Vec) + addString(S, Record); + } + + void ClangDocBinaryWriter::addInfo(const Info &I, RecordDataImpl &Record) { + addString(I.FullyQualifiedName, Record); + addString(I.SimpleName, Record); + addString(I.Namespace, Record); + addComment(I.Description, Record); +} + +void ClangDocBinaryWriter::addSymbolInfo(const SymbolInfo &I, RecordDataImpl &Record) { + addInfo(I, Record); + Record.push_back(I.LineNumber); + addString(I.Filename, Record); +} + +template <> void ClangDocBinaryWriter::writeBitstream(const NamespaceInfo &I) { + RecordData Record; + Record.clear(); + addInfo(I, Record); + Stream.EmitRecord(IT_namespace, Record); +} + +template <> void ClangDocBinaryWriter::writeBitstream(const FunctionInfo &I) { + RecordData Record; + Record.clear(); + addSymbolInfo(I, Record); + addString(I.MangledName, Record); + addString(I.Parent, Record); + addNamedType(I.ReturnType, Record); + addNamedTypeVector(I.Params, Record); + Record.push_back(I.Access); + Stream.EmitRecord(IT_function, Record); +} + +template <> void ClangDocBinaryWriter::writeBitstream(const RecordInfo &I) { + RecordData Record; + Record.clear(); + addSymbolInfo(I, Record); + Record.push_back(I.LineNumber); + addNamedTypeVector(I.Members, Record); + addStringVector(I.Parents, Record); + addStringVector(I.VirtualParents, Record); + Stream.EmitRecord(IT_record, Record); +} + +template <> void ClangDocBinaryWriter::writeBitstream(const EnumInfo &I) { + RecordData Record; + Record.clear(); + addSymbolInfo(I, Record); + Record.push_back(I.Scoped); + addNamedTypeVector(I.Members, Record); + Stream.EmitRecord(IT_enum, Record); +} + +template <> void ClangDocBinaryWriter::writeBitstream(const NonDefInfo &I) { + RecordData Record; + Record.clear(); + addSymbolInfo(I, Record); + Stream.EmitRecord(IT_nondef, Record); +} + +std::string ClangDocBinaryReader::readString(const RecordData &Record, unsigned &Idx) { + unsigned Len = Record[Idx++]; + std::string Result(Record.data() + Idx, Record.data() + Idx + Len); + Idx += Len; + return Result; +} + +} // namespace clang +} // namespace doc \ No newline at end of file Index: clang-doc/ClangDoc.h =================================================================== --- /dev/null +++ clang-doc/ClangDoc.h @@ -0,0 +1,57 @@ +//===-- ClangDoc.cpp - ClangDoc ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANGDOC_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANGDOC_H + +#include "ClangDocMapper.h" +#include "clang/AST/AST.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Comment.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchersInternal.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/ASTConsumers.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Tooling/Tooling.h" +#include <string> +#include <vector> + +using namespace clang::ast_matchers; + +namespace clang { +namespace doc { + +/// Callback class for matchers. +/// Parses each match and sends it along to the reporter for serialization. +class ClangDocCallback : public MatchFinder::MatchCallback { +public: + ClangDocCallback(StringRef BoundName, ExecutionContext &ECtx, bool OmitFiles) : ECtx(ECtx), Mapper(OmitFiles), BoundName(BoundName) {} + virtual void run(const MatchFinder::MatchResult &Result) final; + +private: + template <class T> + void processMatchedDecl(const T *D); + int getLine(const NamedDecl *D) const; + StringRef getFile(const NamedDecl *D) const; + comments::FullComment *getComment(const NamedDecl *D); + std::string getName(const NamedDecl *D) const; + + ASTContext *Context; + ExecutionContext &ECtx; + ClangDocMapper Mapper; + StringRef BoundName; +}; + +} // namespace doc +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANGDOC_H Index: clang-doc/ClangDoc.cpp =================================================================== --- /dev/null +++ clang-doc/ClangDoc.cpp @@ -0,0 +1,82 @@ +//===-- ClangDoc.cpp - ClangDoc ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ClangDoc.h" +#include "clang/AST/AST.h" +#include "clang/AST/Comment.h" +#include "clang/AST/Mangle.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchersInternal.h" + +using namespace clang; +using namespace clang::ast_matchers; +using namespace clang::tooling; +using namespace llvm; + +namespace clang { +namespace doc { + +template <typename T> +void ClangDocCallback::processMatchedDecl(const T *D) { + if (!Context->getSourceManager().isWrittenInMainFile(D->getLocation())) + return; + std::string Name = getName(D); + ECtx.reportResult(Name, Mapper.emitInfo(D, getComment(D), Name, getLine(D), getFile(D))); +} + +void ClangDocCallback::run(const MatchFinder::MatchResult &Result) { + Context = Result.Context; + if (const auto *M = Result.Nodes.getNodeAs<NamespaceDecl>(BoundName)) + processMatchedDecl(M); + else if (const auto *M = Result.Nodes.getNodeAs<RecordDecl>(BoundName)) + processMatchedDecl(M); + else if (const auto *M = Result.Nodes.getNodeAs<EnumDecl>(BoundName)) + processMatchedDecl(M); + else if (const auto *M = Result.Nodes.getNodeAs<CXXMethodDecl>(BoundName)) + processMatchedDecl(M); + else if (const auto *M = Result.Nodes.getNodeAs<FunctionDecl>(BoundName)) + processMatchedDecl(M); +} + +comments::FullComment *ClangDocCallback::getComment(const NamedDecl *D) { + RawComment *Comment = Context->getRawCommentForDeclNoCache(D); + // FIXME: Move setAttached to the initial comment parsing. + if (Comment) { + Comment->setAttached(); + return Comment->parse(*Context, nullptr, D); + } + return nullptr; +} + +int ClangDocCallback::getLine(const NamedDecl *D) const { + return Context->getSourceManager().getPresumedLoc(D->getLocStart()).getLine(); +} + +StringRef ClangDocCallback::getFile(const NamedDecl *D) const { + return Context->getSourceManager().getPresumedLoc(D->getLocStart()).getFilename(); +} + +std::string ClangDocCallback::getName(const NamedDecl *D) const { + if (const auto *F = dyn_cast<FunctionDecl>(D)) { + MangleContext *MC = Context->createMangleContext(); + std::string S; + llvm::raw_string_ostream MangledName(S); + if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(F)) + MC->mangleCXXCtor(Ctor, CXXCtorType::Ctor_Complete, MangledName); + else if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(F)) + MC->mangleCXXDtor(Dtor, CXXDtorType::Dtor_Complete, MangledName); + else + MC->mangleName(F, MangledName); + return S; + } + return D->getQualifiedNameAsString(); +} + +} // namespace doc +} // namespace clang Index: clang-doc/CMakeLists.txt =================================================================== --- /dev/null +++ clang-doc/CMakeLists.txt @@ -0,0 +1,22 @@ +set(LLVM_LINK_COMPONENTS + support + ) + +add_clang_library(clangDoc + ClangDoc.cpp + ClangDocMapper.cpp + ClangDocBinary.cpp + + LINK_LIBS + clangAnalysis + clangAST + clangASTMatchers + clangBasic + clangFormat + clangFrontend + clangLex + clangTooling + clangToolingCore + ) + +add_subdirectory(tool) Index: CMakeLists.txt =================================================================== --- CMakeLists.txt +++ CMakeLists.txt @@ -7,6 +7,7 @@ endif() add_subdirectory(change-namespace) +add_subdirectory(clang-doc) add_subdirectory(clang-query) add_subdirectory(clang-move) add_subdirectory(clangd)
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits