juliehockett updated this revision to Diff 134855.
juliehockett marked 14 inline comments as done.
juliehockett added a comment.
1. Fixing docs
2. Adding static map from bitcode block/record id to block/record name
3. Pulling magic numbers into one struct
4. Cleaning up and clarifying command line options
5. Adding tests for functions and methods
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/ClangDocRepresentation.h
clang-doc/tool/CMakeLists.txt
clang-doc/tool/ClangDocMain.cpp
docs/clang-doc.rst
test/CMakeLists.txt
test/clang-doc/mapper-class.cpp
test/clang-doc/mapper-enum.cpp
test/clang-doc/mapper-function.cpp
test/clang-doc/mapper-method.cpp
test/clang-doc/mapper-namespace.cpp
test/clang-doc/mapper-struct.cpp
test/clang-doc/mapper-undefined.cpp
test/clang-doc/mapper-union.cpp
Index: test/clang-doc/mapper-union.cpp
===================================================================
--- /dev/null
+++ test/clang-doc/mapper-union.cpp
@@ -0,0 +1,26 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/A.bc --dump | FileCheck %s
+
+union A { int X; int Y; };
+// CHECK: <BLOCKINFO_BLOCK/>
+// CHECK: <RecordBlock NumWords=22 BlockCodeSize=5>
+ // CHECK: <FullyQualifiedName abbrevid=4 op0=1/> blob data = 'A'
+ // CHECK: <Name abbrevid=5 op0=1/> blob data = 'A'
+ // CHECK: <TagType abbrevid=9 op0=2/>
+ // CHECK: <NamedTypeBlock NumWords=6 BlockCodeSize=5>
+ // CHECK: <ID abbrevid=4 op0=2/>
+ // CHECK: <Type abbrevid=5 op0=3/> blob data = 'int'
+ // CHECK: <Name abbrevid=6 op0=4/> blob data = 'A::X'
+ // CHECK: <Access abbrevid=7 op0=3/>
+ // CHECK: </NamedTypeBlock>
+ // CHECK: <NamedTypeBlock NumWords=6 BlockCodeSize=5>
+ // CHECK: <ID abbrevid=4 op0=2/>
+ // CHECK: <Type abbrevid=5 op0=3/> blob data = 'int'
+ // CHECK: <Name abbrevid=6 op0=4/> blob data = 'A::Y'
+ // CHECK: <Access abbrevid=7 op0=3/>
+ // CHECK: </NamedTypeBlock>
+// CHECK: </RecordBlock>
Index: test/clang-doc/mapper-undefined.cpp
===================================================================
--- /dev/null
+++ test/clang-doc/mapper-undefined.cpp
@@ -0,0 +1,15 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/E.bc --dump | FileCheck %s
+
+class E;
+// CHECK: <BLOCKINFO_BLOCK/>
+// CHECK: <NonDefBlock NumWords=5 BlockCodeSize=5>
+ // CHECK: <FullyQualifiedName abbrevid=4 op0=1/> blob data = 'E'
+ // CHECK: <Name abbrevid=5 op0=1/> blob data = 'E'
+ // CHECK: <Type abbrevid=7 op0=2/>
+// CHECK: </NonDefBlock>
+
Index: test/clang-doc/mapper-struct.cpp
===================================================================
--- /dev/null
+++ test/clang-doc/mapper-struct.cpp
@@ -0,0 +1,19 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/C.bc --dump | FileCheck %s
+
+struct C { int i; };
+// CHECK: <BLOCKINFO_BLOCK/>
+// CHECK: <RecordBlock NumWords=13 BlockCodeSize=5>
+ // CHECK: <FullyQualifiedName abbrevid=4 op0=1/> blob data = 'C'
+ // CHECK: <Name abbrevid=5 op0=1/> blob data = 'C'
+ // CHECK: <NamedTypeBlock NumWords=6 BlockCodeSize=5>
+ // CHECK: <ID abbrevid=4 op0=2/>
+ // CHECK: <Type abbrevid=5 op0=3/> blob data = 'int'
+ // CHECK: <Name abbrevid=6 op0=4/> blob data = 'C::i'
+ // CHECK: <Access abbrevid=7 op0=3/>
+ // CHECK: </NamedTypeBlock>
+// CHECK: </RecordBlock>
Index: test/clang-doc/mapper-namespace.cpp
===================================================================
--- /dev/null
+++ test/clang-doc/mapper-namespace.cpp
@@ -0,0 +1,13 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/A.bc --dump | FileCheck %s
+
+namespace A {}
+// CHECK: <BLOCKINFO_BLOCK/>
+// CHECK: <NamespaceBlock NumWords=5 BlockCodeSize=5>
+ // CHECK: <FullyQualifiedName abbrevid=4 op0=1/> blob data = 'A'
+ // CHECK: <Name abbrevid=5 op0=1/> blob data = 'A'
+// CHECK: </NamespaceBlock>
Index: test/clang-doc/mapper-method.cpp
===================================================================
--- /dev/null
+++ test/clang-doc/mapper-method.cpp
@@ -0,0 +1,30 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/_ZN1E6MethodEi.bc --dump | FileCheck %s
+
+class E {
+public:
+ int Method(int param) { return param; }
+};
+// CHECK: <BLOCKINFO_BLOCK/>
+// CHECK: <FunctionBlock NumWords=32 BlockCodeSize=5>
+ // CHECK: <FullyQualifiedName abbrevid=4 op0=9/> blob data = 'E::Method'
+ // CHECK: <Name abbrevid=5 op0=6/> blob data = 'Method'
+ // CHECK: <Namespace abbrevid=6 op0=1/> blob data = 'E'
+ // CHECK: <MangledName abbrevid=9 op0=14/> blob data = '_ZN1E6MethodEi'
+ // CHECK: <Parent abbrevid=10 op0=1/> blob data = 'E'
+ // CHECK: <NamedTypeBlock NumWords=4 BlockCodeSize=5>
+ // CHECK: <ID abbrevid=4 op0=3/>
+ // CHECK: <Type abbrevid=5 op0=3/> blob data = 'int'
+ // CHECK: <Access abbrevid=7 op0=3/>
+ // CHECK: </NamedTypeBlock>
+ // CHECK: <NamedTypeBlock NumWords=7 BlockCodeSize=5>
+ // CHECK: <ID abbrevid=4 op0=1/>
+ // CHECK: <Type abbrevid=5 op0=3/> blob data = 'int'
+ // CHECK: <Name abbrevid=6 op0=5/> blob data = 'param'
+ // CHECK: <Access abbrevid=7 op0=3/>
+ // CHECK: </NamedTypeBlock>
+// CHECK: </FunctionBlock>
Index: test/clang-doc/mapper-function.cpp
===================================================================
--- /dev/null
+++ test/clang-doc/mapper-function.cpp
@@ -0,0 +1,25 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/_Z1Fi.bc --dump | FileCheck %s
+
+int F(int param) { return param; }
+// CHECK: <BLOCKINFO_BLOCK/>
+// CHECK: <FunctionBlock NumWords=23 BlockCodeSize=5>
+ // CHECK: <FullyQualifiedName abbrevid=4 op0=1/> blob data = 'F'
+ // CHECK: <Name abbrevid=5 op0=1/> blob data = 'F'
+ // CHECK: <MangledName abbrevid=9 op0=5/> blob data = '_Z1Fi'
+ // CHECK: <NamedTypeBlock NumWords=4 BlockCodeSize=5>
+ // CHECK: <ID abbrevid=4 op0=3/>
+ // CHECK: <Type abbrevid=5 op0=3/> blob data = 'int'
+ // CHECK: <Access abbrevid=7 op0=3/>
+ // CHECK: </NamedTypeBlock>
+ // CHECK: <NamedTypeBlock NumWords=7 BlockCodeSize=5>
+ // CHECK: <ID abbrevid=4 op0=1/>
+ // CHECK: <Type abbrevid=5 op0=3/> blob data = 'int'
+ // CHECK: <Name abbrevid=6 op0=5/> blob data = 'param'
+ // CHECK: <Access abbrevid=7 op0=3/>
+ // CHECK: </NamedTypeBlock>
+// CHECK: </FunctionBlock>
Index: test/clang-doc/mapper-enum.cpp
===================================================================
--- /dev/null
+++ test/clang-doc/mapper-enum.cpp
@@ -0,0 +1,23 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/B.bc --dump | FileCheck %s
+
+enum B { X, Y };
+// CHECK: <BLOCKINFO_BLOCK/>
+// CHECK: <EnumBlock NumWords=17 BlockCodeSize=5>
+ // CHECK: <FullyQualifiedName abbrevid=4 op0=1/> blob data = 'B'
+ // CHECK: <Name abbrevid=5 op0=1/> blob data = 'B'
+ // CHECK: <NamedTypeBlock NumWords=4 BlockCodeSize=5>
+ // CHECK: <ID abbrevid=4 op0=2/>
+ // CHECK: <Type abbrevid=5 op0=1/> blob data = 'X'
+ // CHECK: <Access abbrevid=7 op0=3/>
+ // CHECK: </NamedTypeBlock>
+ // CHECK: <NamedTypeBlock NumWords=4 BlockCodeSize=5>
+ // CHECK: <ID abbrevid=4 op0=2/>
+ // CHECK: <Type abbrevid=5 op0=1/> blob data = 'Y'
+ // CHECK: <Access abbrevid=7 op0=3/>
+ // CHECK: </NamedTypeBlock>
+// CHECK: </EnumBlock>
Index: test/clang-doc/mapper-class.cpp
===================================================================
--- /dev/null
+++ test/clang-doc/mapper-class.cpp
@@ -0,0 +1,14 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/E.bc --dump | FileCheck %s
+
+class E {};
+// CHECK: <BLOCKINFO_BLOCK/>
+// CHECK: <RecordBlock NumWords=5 BlockCodeSize=5>
+ // CHECK: <FullyQualifiedName abbrevid=4 op0=1/> blob data = 'E'
+ // CHECK: <Name abbrevid=5 op0=1/> blob data = 'E'
+ // CHECK: <TagType abbrevid=9 op0=3/>
+// CHECK: </RecordBlock>
Index: test/CMakeLists.txt
===================================================================
--- test/CMakeLists.txt
+++ test/CMakeLists.txt
@@ -41,6 +41,7 @@
clang-apply-replacements
clang-change-namespace
clangd
+ clang-doc
clang-include-fixer
clang-move
clang-query
Index: docs/clang-doc.rst
===================================================================
--- /dev/null
+++ docs/clang-doc.rst
@@ -0,0 +1,61 @@
+===================
+Clang-Doc
+===================
+
+.. contents::
+
+:program:`clang-doc` is a tool for generating C and C++ documenation from
+source code and comments.
+
+The tool is in a very early development stage, so you might encounter bugs and
+crashes. Submitting reports with information about how to reproduce the issue
+to `the LLVM bugtracker <https://llvm.org/bugs>`_ will definitely help the
+project. If you have any ideas or suggestions, please to put a feature request
+there.
+
+Use
+=====
+
+:program:`clang-doc` is a `LibTooling
+<http://clang.llvm.org/docs/LibTooling.html>`_-based tool, and so requires a
+compile command database for your project (for an example of how to do this
+see `How To Setup Tooling For LLVM
+<http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html>`_).
+
+The tool can be used on a single file or multiple files as defined in
+the compile commands database:
+
+.. code-block:: console
+
+ $ clang-doc /path/to/file.cpp -p /path/to/compile/commands
+
+This generates an intermediate representation of the declarations and their
+associated information in the specified TUs, serialized to LLVM bitcode.
+
+As currently implemented, the tool is only able to parse TUs that can be
+stored in-memory. Future additions will extend the current framework to use
+map-reduce frameworks to allow for use with large codebases.
+
+:program:`clang-doc` offers the following options:
+
+.. code-block:: console
+
+ $ clang-doc --help
+ USAGE: clang-doc [options] <source0> [... <sourceN>]
+
+ OPTIONS:
+
+ Generic Options:
+
+ -help - Display available options (-help-hidden for more)
+ -help-list - Display list of available options (-help-list-hidden for more)
+ -version - Display the version of this program
+
+ clang-doc options:
+
+ -doxygen - Use only doxygen-style comments to generate docs.
+ -dump - Dump results to stdout.
+ -extra-arg=<string> - Additional argument to append to the compiler command line
+ -extra-arg-before=<string> - Additional argument to prepend to the compiler command line
+ -omit-filenames - Omit filenames in output.
+ -p=<string> - Build path
Index: clang-doc/tool/ClangDocMain.cpp
===================================================================
--- /dev/null
+++ clang-doc/tool/ClangDocMain.cpp
@@ -0,0 +1,121 @@
+//===-- 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 <string>
+#include "ClangDoc.h"
+#include "ClangDocBinary.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/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/raw_ostream.h"
+
+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<std::string> OutDirectory(
+ "output", cl::desc("Directory for outputting generated files."), cl::init("docs"),
+ cl::cat(ClangDocCategory));
+
+static cl::opt<bool> DumpResult("dump", cl::desc("Dump intermediate results to bitcode file."),
+ 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]);
+ std::error_code OK;
+
+ 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::ClangDocBinaryWriter Writer(OmitFilenames);
+
+ doc::ClangDocCallback NCallback("namespace", *ECtx, Writer);
+ Finder.addMatcher(namespaceDecl().bind("namespace"), &NCallback);
+ doc::ClangDocCallback RCallback("record", *ECtx, Writer);
+ Finder.addMatcher(recordDecl().bind("record"), &RCallback);
+ doc::ClangDocCallback ECallback("enum", *ECtx, Writer);
+ Finder.addMatcher(enumDecl().bind("enum"), &ECallback);
+ doc::ClangDocCallback MCallback("method", *ECtx, Writer);
+ Finder.addMatcher(cxxMethodDecl(isUserProvided()).bind("method"), &MCallback);
+ doc::ClangDocCallback FCallback("function", *ECtx, Writer);
+ Finder.addMatcher(functionDecl(unless(cxxMethodDecl())).bind("function"),
+ &FCallback);
+
+ ArgumentsAdjuster ArgAdjuster;
+ if (!DoxygenOnly)
+ ArgAdjuster = combineAdjusters(
+ getInsertArgumentAdjuster("-fparse-all-comments",
+ tooling::ArgumentInsertPosition::BEGIN),
+ ArgAdjuster);
+
+ // Mapping phase
+ outs() << "Mapping decls...\n";
+ 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) {
+ SmallString<128> IRRootPath;
+ sys::path::native(OutDirectory, IRRootPath);
+ std::error_code DirectoryStatus = sys::fs::create_directories(IRRootPath);
+ if (DirectoryStatus != OK) {
+ errs() << "Unable to create documentation directories.\n";
+ return;
+ }
+ sys::path::append(IRRootPath, Key + ".bc");
+ std::error_code OutErrorInfo;
+ raw_fd_ostream OS(IRRootPath, OutErrorInfo, sys::fs::F_None);
+ if (OutErrorInfo != OK) {
+ errs() << "Error opening documentation file.\n";
+ return;
+ }
+ OS << Value;
+ OS.close();
+ });
+ }
+
+ return 0;
+}
Index: clang-doc/tool/CMakeLists.txt
===================================================================
--- /dev/null
+++ clang-doc/tool/CMakeLists.txt
@@ -0,0 +1,16 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
+
+add_clang_executable(clang-doc
+ ClangDocMain.cpp
+ )
+
+target_link_libraries(clang-doc
+ PRIVATE
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangFrontend
+ clangDoc
+ clangTooling
+ clangToolingCore
+ )
Index: clang-doc/ClangDocRepresentation.h
===================================================================
--- /dev/null
+++ clang-doc/ClangDocRepresentation.h
@@ -0,0 +1,112 @@
+///===-- ClangDocRepresentation.h - ClangDocRepresenation -------*- 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_REPRESENTATION_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_REPRESENTATION_H
+
+#include <string>
+#include "clang/AST/Type.h"
+#include "clang/Basic/Specifiers.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallVector.h"
+
+using namespace llvm;
+
+namespace clang {
+namespace doc {
+
+// A representation of a parsed comment.
+struct CommentInfo {
+ std::string Kind;
+ std::string Text;
+ std::string Name;
+ std::string Direction;
+ std::string ParamName;
+ std::string CloseName;
+ bool SelfClosing = false;
+ bool Explicit = false;
+ llvm::SmallVector<std::string, 4> AttrKeys;
+ llvm::SmallVector<std::string, 4> AttrValues;
+ llvm::SmallVector<std::string, 4> Args;
+ llvm::SmallVector<std::string, 4> Position;
+ std::vector<std::shared_ptr<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 {
+ enum FieldName { PARAM=1, MEMBER, RETTYPE };
+ FieldName Field;
+ std::string Type;
+ std::string Name;
+ AccessSpecifier Access = clang::AccessSpecifier::AS_none;
+ llvm::SmallVector<CommentInfo, 2> Description;
+};
+
+struct Location {
+ int LineNumber;
+ std::string Filename;
+};
+
+/// A base struct for Infos.
+struct Info {
+ std::string FullyQualifiedName;
+ std::string SimpleName;
+ std::string Namespace;
+ llvm::SmallVector<CommentInfo, 2> Description;
+};
+
+struct NamespaceInfo : public Info {};
+
+struct SymbolInfo : public Info {
+ Location DefLoc;
+ llvm::SmallVector<Location, 2> Loc;
+};
+
+struct NonDefInfo : public SymbolInfo {
+ enum InfoType { NAMESPACE, FUNCTION, RECORD, ENUM };
+ InfoType Type;
+};
+
+// TODO: Expand to allow for documenting templating and default args.
+// Info for functions.
+struct FunctionInfo : public SymbolInfo {
+ std::string 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<std::string, 4> Parents;
+ llvm::SmallVector<std::string, 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.
+
+} // namespace doc
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_REPRESENTATION_H
Index: clang-doc/ClangDocMapper.h
===================================================================
--- /dev/null
+++ clang-doc/ClangDocMapper.h
@@ -0,0 +1,95 @@
+//===-- ClangDocMapper.h - 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 <memory>
+#include <string>
+#include <vector>
+#include "ClangDocBinary.h"
+#include "ClangDocRepresentation.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/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"
+
+using namespace clang::comments;
+using namespace clang::tooling;
+
+namespace clang {
+namespace doc {
+
+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:
+ StringRef getCommandName(unsigned CommandID) const;
+ bool isWhitespaceOnly(StringRef S) const;
+
+ CommentInfo &CurrentCI;
+};
+
+class ClangDocMapper {
+ public:
+ ClangDocMapper(ClangDocBinaryWriter &Writer) : Writer(Writer) {}
+
+ template <class C>
+ StringRef emitInfo(const C *D, const FullComment *FC, StringRef Key,
+ int LineNumber, StringRef File);
+
+ private:
+ template <typename T>
+ SmallString<2048> 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, NonDefInfo::InfoType Type,
+ 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;
+ void parseFullComment(const FullComment *C, CommentInfo &CI);
+ std::string getParentNamespace(const DeclContext *D) const;
+
+ ClangDocBinaryWriter &Writer;
+};
+
+} // 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,292 @@
+//===-- 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 "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.emplace_back(CommentInfo{});
+ parseFullComment(FC, I.Description.back());
+ }
+ 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, NonDefInfo::RECORD, 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, NonDefInfo::FUNCTION, 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, NonDefInfo::FUNCTION, 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, NonDefInfo::ENUM, 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>
+SmallString<2048> ClangDocMapper::serialize(T &I) const {
+ SmallString<2048> Buffer;
+ llvm::BitstreamWriter Stream(Buffer);
+ Writer.writeBitstream(I, Stream, /*writeBlockInfo=*/true);
+ return Buffer;
+}
+
+void ClangDocMapper::parseFullComment(const FullComment *C, CommentInfo &CI) {
+ ClangDocCommentVisitor Visitor(CI);
+ 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.Loc.emplace_back(Location{LineNumber, File});
+ I.DefLoc = Location{LineNumber, File};
+ if (C) {
+ I.Description.emplace_back(CommentInfo());
+ parseFullComment(C, I.Description.back());
+ }
+}
+
+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, NonDefInfo::InfoType Type,
+ const FullComment *FC,
+ int LineNumber, StringRef File) {
+ NonDefInfo I;
+ I.Type = Type;
+ I.FullyQualifiedName = Name;
+ I.SimpleName = D->getNameAsString();
+ I.Namespace = getParentNamespace(D);
+ I.Loc.emplace_back(Location{LineNumber, File});
+ if (FC) {
+ I.Description.emplace_back(CommentInfo());
+ parseFullComment(FC, I.Description.back());
+ }
+ 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());
+}
+
+std::string ClangDocMapper::getParentNamespace(const DeclContext *D) const {
+ if (const auto *N = dyn_cast<NamedDecl>(D->getParent())) {
+ return N->getQualifiedNameAsString();
+ }
+ return "";
+}
+
+// ClangDocCommentVisitor
+
+void 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())) {
+ CurrentCI.Children.emplace_back(std::make_shared<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() && 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 std::all_of(S.begin(), S.end(), isspace);
+}
+
+} // namespace doc
+} // namespace clang
Index: clang-doc/ClangDocBinary.h
===================================================================
--- /dev/null
+++ clang-doc/ClangDocBinary.h
@@ -0,0 +1,188 @@
+//===-- ClangDocBinary.h - ClangDoc Binary ---------------------*- 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_BINARY_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_BINARY_H
+
+#include <vector>
+#include "ClangDocRepresentation.h"
+#include "clang/AST/AST.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+#include "llvm/Bitcode/BitstreamWriter.h"
+
+using namespace llvm;
+
+namespace clang {
+namespace doc {
+
+enum BlockId {
+ NAMESPACE_BLOCK_ID = bitc::FIRST_APPLICATION_BLOCKID,
+ NONDEF_BLOCK_ID,
+ ENUM_BLOCK_ID,
+ NAMED_TYPE_BLOCK_ID,
+ RECORD_BLOCK_ID,
+ FUNCTION_BLOCK_ID,
+ COMMENT_BLOCK_ID,
+ BI_FIRST = NAMESPACE_BLOCK_ID,
+ BI_LAST = COMMENT_BLOCK_ID
+};
+
+#define INFORECORDS(X) X##_FULLY_QUALIFIED_NAME, X##_NAME, X##_NAMESPACE,
+
+enum RecordId {
+ COMMENT_KIND = 1,
+ COMMENT_TEXT,
+ COMMENT_NAME,
+ COMMENT_POSITION,
+ COMMENT_DIRECTION,
+ COMMENT_PARAMNAME,
+ COMMENT_CLOSENAME,
+ COMMENT_SELFCLOSING,
+ COMMENT_EXPLICIT,
+ COMMENT_ATTRKEY,
+ COMMENT_ATTRVAL,
+ COMMENT_ARG,
+ NAMED_TYPE_ID,
+ NAMED_TYPE_TYPE,
+ NAMED_TYPE_NAME,
+ NAMED_TYPE_ACCESS,
+ INFORECORDS(NAMESPACE)
+ INFORECORDS(NONDEF)
+ NONDEF_TYPE,
+ NONDEF_LOCATION,
+ INFORECORDS(ENUM)
+ ENUM_DEFLOCATION,
+ ENUM_LOCATION,
+ ENUM_SCOPED,
+ INFORECORDS(RECORD)
+ RECORD_DEFLOCATION,
+ RECORD_LOCATION,
+ RECORD_TAG_TYPE,
+ RECORD_PARENT,
+ RECORD_VPARENT,
+ INFORECORDS(FUNCTION)
+ FUNCTION_DEFLOCATION,
+ FUNCTION_LOCATION,
+ FUNCTION_MANGLED_NAME,
+ FUNCTION_PARENT,
+ FUNCTION_ACCESS,
+ DT_FIRST = COMMENT_KIND,
+ DT_LAST = FUNCTION_ACCESS
+};
+
+#undef INFORECORDS
+
+static std::map<BlockId, std::string> BlockIdNameMap = {
+ {NAMESPACE_BLOCK_ID, "NamespaceBlock"},
+ {NONDEF_BLOCK_ID, "NonDefBlock"},
+ {ENUM_BLOCK_ID, "EnumBlock"},
+ {NAMED_TYPE_BLOCK_ID, "NamedTypeBlock"},
+ {RECORD_BLOCK_ID, "RecordBlock"},
+ {FUNCTION_BLOCK_ID, "FunctionBlock"},
+ {COMMENT_BLOCK_ID, "CommentBlock"}
+};
+
+static std::map<RecordId, std::string> RecordIdNameMap = {
+ {COMMENT_KIND, "Kind"},
+ {COMMENT_TEXT, "Text"},
+ {COMMENT_NAME, "Name"},
+ {COMMENT_POSITION, "Position"},
+ {COMMENT_DIRECTION, "Direction"},
+ {COMMENT_PARAMNAME, "ParamName"},
+ {COMMENT_CLOSENAME, "CloseName"},
+ {COMMENT_SELFCLOSING, "SelfClosing"},
+ {COMMENT_EXPLICIT, "Explicit"},
+ {COMMENT_ATTRKEY, "AttrKey"},
+ {COMMENT_ATTRVAL, "AttrVal"},
+ {COMMENT_ARG, "Arg"},
+ {NAMED_TYPE_ID, "ID"},
+ {NAMED_TYPE_TYPE, "Type"},
+ {NAMED_TYPE_NAME, "Name"},
+ {NAMED_TYPE_ACCESS, "Access"},
+ {NAMESPACE_FULLY_QUALIFIED_NAME, "FullyQualifiedName"},
+ {NAMESPACE_NAME, "Name"},
+ {NAMESPACE_NAMESPACE, "Namespace"},
+ {NONDEF_FULLY_QUALIFIED_NAME, "FullyQualifiedName"},
+ {NONDEF_NAME, "Name"},
+ {NONDEF_NAMESPACE, "Namespace"},
+ {NONDEF_LOCATION, "Location"},
+ {NONDEF_TYPE, "Type"},
+ {ENUM_FULLY_QUALIFIED_NAME, "FullyQualifiedName"},
+ {ENUM_NAME, "Name"},
+ {ENUM_NAMESPACE, "Namespace"},
+ {ENUM_DEFLOCATION, "DefLocation"},
+ {ENUM_LOCATION, "Location"},
+ {ENUM_SCOPED, "Scoped"},
+ {RECORD_FULLY_QUALIFIED_NAME, "FullyQualifiedName"},
+ {RECORD_NAME, "Name"},
+ {RECORD_NAMESPACE, "Namespace"},
+ {RECORD_DEFLOCATION, "DefLocation"},
+ {RECORD_LOCATION, "Location"},
+ {RECORD_TAG_TYPE, "TagType"},
+ {RECORD_PARENT, "Parent"},
+ {RECORD_VPARENT, "VParent"},
+ {FUNCTION_FULLY_QUALIFIED_NAME, "FullyQualifiedName"},
+ {FUNCTION_NAME, "Name"},
+ {FUNCTION_NAMESPACE, "Namespace"},
+ {FUNCTION_LOCATION, "Location"},
+ {FUNCTION_DEFLOCATION, "DefLocation"},
+ {FUNCTION_MANGLED_NAME, "MangledName"},
+ {FUNCTION_PARENT, "Parent"},
+ {FUNCTION_ACCESS, "Access"}
+};
+
+class AbbreviationMap {
+ llvm::DenseMap<unsigned, unsigned> Abbrevs;
+
+ public:
+ AbbreviationMap() {}
+ void add(RecordId RID, unsigned abbrevID);
+ unsigned get(RecordId RID);
+ void clear();
+};
+
+class ClangDocBinaryWriter {
+ public:
+ ClangDocBinaryWriter(bool OmitFilenames = false)
+ : OmitFilenames(OmitFilenames){};
+
+ using RecordData = SmallVector<uint64_t, 128>;
+
+ template <typename T>
+ void writeBitstream(const T &I, BitstreamWriter &Stream,
+ bool writeBlockInfo = false);
+
+ private:
+ void emitBlockInfoBlock(BitstreamWriter &Stream);
+ void emitHeader(BitstreamWriter &Stream);
+ void emitStringRecord(StringRef Str, RecordId ID,
+ BitstreamWriter &Stream);
+ void emitLocationRecord(int LineNumber, StringRef File, RecordId ID,
+ BitstreamWriter &Stream);
+ void emitIntRecord(int Value, RecordId ID, BitstreamWriter &Stream);
+ void emitNamedTypeBlock(const NamedType &N, NamedType::FieldName ID,
+ BitstreamWriter &Stream);
+ void emitCommentBlock(const CommentInfo *I, BitstreamWriter &Stream);
+
+ void emitRecordID(RecordId ID, BitstreamWriter &Stream);
+ void emitBlockID(BlockId ID, BitstreamWriter &Stream);
+ void emitStringAbbrev(RecordId ID, BlockId Block, BitstreamWriter &Stream);
+ void emitLocationAbbrev(RecordId ID, BlockId Block, BitstreamWriter &Stream);
+ void emitIntAbbrev(RecordId ID, BlockId Block, BitstreamWriter &Stream);
+
+ RecordData Record;
+ bool OmitFilenames;
+ AbbreviationMap Abbrevs;
+};
+
+} // namespace doc
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_BINARY_H
Index: clang-doc/ClangDocBinary.cpp
===================================================================
--- /dev/null
+++ clang-doc/ClangDocBinary.cpp
@@ -0,0 +1,355 @@
+//===-- ClangDocBinary.cpp - ClangDoc Binary -------------------*- 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 {
+
+struct BitCodeConstants {
+static constexpr int SubblockIDSize = 5;
+static constexpr int LineNumFixedSize = 16;
+static constexpr int SignatureBitSize = 8;
+};
+
+void AbbreviationMap::add(RecordId RID, unsigned AbbrevID) {
+ assert(Abbrevs.find(RID) == Abbrevs.end() &&
+ "Abbreviation already added.");
+ Abbrevs[RID] = AbbrevID;
+}
+
+unsigned AbbreviationMap::get(RecordId RID) {
+ assert(Abbrevs.find(RID) != Abbrevs.end() && "Abbreviation not added.");
+ return Abbrevs[RID];
+}
+
+void AbbreviationMap::clear() { Abbrevs.clear(); }
+
+void ClangDocBinaryWriter::emitHeader(BitstreamWriter &Stream) {
+ // Emit the file header.
+ Stream.Emit((unsigned)'D', BitCodeConstants::SignatureBitSize);
+ Stream.Emit((unsigned)'O', BitCodeConstants::SignatureBitSize);
+ Stream.Emit((unsigned)'C', BitCodeConstants::SignatureBitSize);
+ Stream.Emit((unsigned)'S', BitCodeConstants::SignatureBitSize);
+}
+
+/// \brief Emits a block ID in the BLOCKINFO block.
+void ClangDocBinaryWriter::emitBlockID(BlockId ID, BitstreamWriter &Stream) {
+ Record.clear();
+ Record.push_back(ID);
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
+
+ Record.clear();
+ for (const char C : BlockIdNameMap[ID]) Record.push_back(C);
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
+}
+
+/// \brief Emits a record ID in the BLOCKINFO block.
+void ClangDocBinaryWriter::emitRecordID(RecordId ID, BitstreamWriter &Stream) {
+ Record.clear();
+ Record.push_back(ID);
+ for (const char C : RecordIdNameMap[ID]) Record.push_back(C);
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
+}
+
+// Common Abbreviations
+
+void ClangDocBinaryWriter::emitStringAbbrev(RecordId ID, BlockId Block,
+ BitstreamWriter &Stream) {
+ auto Abbrev = std::make_shared<BitCodeAbbrev>();
+ Abbrev->Add(BitCodeAbbrevOp(ID));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, BitCodeConstants::LineNumFixedSize)); // String size
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // String
+ Abbrevs.add(ID, Stream.EmitBlockInfoAbbrev(Block, Abbrev));
+}
+
+void ClangDocBinaryWriter::emitLocationAbbrev(RecordId ID, BlockId Block,
+ BitstreamWriter &Stream) {
+ auto Abbrev = std::make_shared<BitCodeAbbrev>();
+ Abbrev->Add(BitCodeAbbrevOp(ID));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, BitCodeConstants::LineNumFixedSize)); // Line number
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, BitCodeConstants::LineNumFixedSize)); // Filename size
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Filename
+ Abbrevs.add(ID, Stream.EmitBlockInfoAbbrev(Block, Abbrev));
+}
+
+void ClangDocBinaryWriter::emitIntAbbrev(RecordId ID, BlockId Block,
+ BitstreamWriter &Stream) {
+ auto Abbrev = std::make_shared<BitCodeAbbrev>();
+ Abbrev->Add(BitCodeAbbrevOp(ID));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, BitCodeConstants::LineNumFixedSize)); // Integer
+ Abbrevs.add(ID, Stream.EmitBlockInfoAbbrev(Block, Abbrev));
+}
+
+// Common Records
+
+void ClangDocBinaryWriter::emitStringRecord(StringRef Str, RecordId ID,
+ BitstreamWriter &Stream) {
+ if (Str.empty()) return;
+ Record.clear();
+ Record.push_back(ID);
+ Record.push_back(Str.size());
+ Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, Str);
+}
+
+void ClangDocBinaryWriter::emitLocationRecord(int LineNumber, StringRef File,
+ RecordId ID,
+ BitstreamWriter &Stream) {
+ if (OmitFilenames) return;
+ Record.clear();
+ Record.push_back(ID);
+ Record.push_back(LineNumber);
+ Record.push_back(File.size());
+ Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, File);
+}
+
+void ClangDocBinaryWriter::emitIntRecord(int Value, RecordId ID,
+ BitstreamWriter &Stream) {
+ if (!Value) return;
+ Record.clear();
+ Record.push_back(ID);
+ Record.push_back(Value);
+ Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
+}
+
+// Common Blocks
+
+void ClangDocBinaryWriter::emitNamedTypeBlock(const NamedType &N, NamedType::FieldName ID,
+ BitstreamWriter &Stream) {
+ Stream.EnterSubblock(NAMED_TYPE_BLOCK_ID, BitCodeConstants::SubblockIDSize);
+ emitIntRecord(ID, NAMED_TYPE_ID, Stream);
+ emitStringRecord(N.Type, NAMED_TYPE_TYPE, Stream);
+ emitStringRecord(N.Name, NAMED_TYPE_NAME, Stream);
+ emitIntRecord(N.Access, NAMED_TYPE_ACCESS, Stream);
+ Stream.ExitBlock();
+}
+
+void ClangDocBinaryWriter::emitCommentBlock(const CommentInfo *I,
+ BitstreamWriter &Stream) {
+ Stream.EnterSubblock(COMMENT_BLOCK_ID, BitCodeConstants::SubblockIDSize);
+ emitStringRecord(I->Text, COMMENT_TEXT, Stream);
+ emitStringRecord(I->Name, COMMENT_NAME, Stream);
+ emitStringRecord(I->Direction, COMMENT_DIRECTION, Stream);
+ emitStringRecord(I->ParamName, COMMENT_PARAMNAME, Stream);
+ emitStringRecord(I->CloseName, COMMENT_CLOSENAME, Stream);
+ emitIntRecord(I->SelfClosing, COMMENT_SELFCLOSING, Stream);
+ emitIntRecord(I->Explicit, COMMENT_EXPLICIT, Stream);
+ for (const auto &A : I->AttrKeys)
+ emitStringRecord(A, COMMENT_ATTRKEY, Stream);
+ for (const auto &A : I->AttrValues)
+ emitStringRecord(A, COMMENT_ATTRVAL, Stream);
+ for (const auto &A : I->Args)
+ emitStringRecord(A, COMMENT_ARG, Stream);
+ for (const auto &P : I->Position)
+ emitStringRecord(P, COMMENT_POSITION, Stream);
+ for (const auto &C : I->Children)
+ emitCommentBlock(C.get(), Stream);
+ Stream.ExitBlock();
+}
+
+void ClangDocBinaryWriter::emitBlockInfoBlock(BitstreamWriter &Stream) {
+ Abbrevs.clear();
+ emitHeader(Stream);
+ Stream.EnterBlockInfoBlock();
+
+ // Comment Block
+ emitBlockID(COMMENT_BLOCK_ID, Stream);
+ emitRecordID(COMMENT_KIND, Stream);
+ emitRecordID(COMMENT_TEXT, Stream);
+ emitRecordID(COMMENT_NAME, Stream);
+ emitRecordID(COMMENT_DIRECTION, Stream);
+ emitRecordID(COMMENT_PARAMNAME, Stream);
+ emitRecordID(COMMENT_CLOSENAME, Stream);
+ emitRecordID(COMMENT_SELFCLOSING, Stream);
+ emitRecordID(COMMENT_EXPLICIT, Stream);
+ emitRecordID(COMMENT_ATTRKEY, Stream);
+ emitRecordID(COMMENT_ATTRVAL, Stream);
+ emitRecordID(COMMENT_ARG, Stream);
+ emitRecordID(COMMENT_POSITION, Stream);
+ emitStringAbbrev(COMMENT_KIND, COMMENT_BLOCK_ID, Stream);
+ emitStringAbbrev(COMMENT_TEXT, COMMENT_BLOCK_ID, Stream);
+ emitStringAbbrev(COMMENT_NAME, COMMENT_BLOCK_ID, Stream);
+ emitStringAbbrev(COMMENT_DIRECTION, COMMENT_BLOCK_ID, Stream);
+ emitStringAbbrev(COMMENT_PARAMNAME, COMMENT_BLOCK_ID, Stream);
+ emitStringAbbrev(COMMENT_CLOSENAME, COMMENT_BLOCK_ID, Stream);
+ emitIntAbbrev(COMMENT_SELFCLOSING, COMMENT_BLOCK_ID, Stream);
+ emitIntAbbrev(COMMENT_EXPLICIT, COMMENT_BLOCK_ID, Stream);
+ emitStringAbbrev(COMMENT_ATTRKEY, COMMENT_BLOCK_ID, Stream);
+ emitStringAbbrev(COMMENT_ATTRVAL, COMMENT_BLOCK_ID, Stream);
+ emitStringAbbrev(COMMENT_ARG, COMMENT_BLOCK_ID, Stream);
+ emitStringAbbrev(COMMENT_POSITION, COMMENT_BLOCK_ID, Stream);
+
+ // NamedType Block
+ emitBlockID(NAMED_TYPE_BLOCK_ID, Stream);
+ emitRecordID(NAMED_TYPE_ID, Stream);
+ emitRecordID(NAMED_TYPE_TYPE, Stream);
+ emitRecordID(NAMED_TYPE_NAME, Stream);
+ emitRecordID(NAMED_TYPE_ACCESS, Stream);
+ emitIntAbbrev(NAMED_TYPE_ID, NAMED_TYPE_BLOCK_ID, Stream);
+ emitStringAbbrev(NAMED_TYPE_TYPE, NAMED_TYPE_BLOCK_ID, Stream);
+ emitStringAbbrev(NAMED_TYPE_NAME, NAMED_TYPE_BLOCK_ID, Stream);
+ emitIntAbbrev(NAMED_TYPE_ACCESS, NAMED_TYPE_BLOCK_ID, Stream);
+
+#define INFORECORD(X) \
+ emitRecordID(X##_FULLY_QUALIFIED_NAME, Stream); \
+ emitRecordID(X##_NAME, Stream); \
+ emitRecordID(X##_NAMESPACE, Stream);
+
+#define INFOABBREV(X) \
+ emitStringAbbrev(X##_FULLY_QUALIFIED_NAME, X##_BLOCK_ID, Stream); \
+ emitStringAbbrev(X##_NAME, X##_BLOCK_ID, Stream); \
+ emitStringAbbrev(X##_NAMESPACE, X##_BLOCK_ID, Stream);
+
+ // Namespace Block
+ emitBlockID(NAMESPACE_BLOCK_ID, Stream);
+ INFORECORD(NAMESPACE)
+ INFOABBREV(NAMESPACE)
+
+ // NonDef Block
+ emitBlockID(NONDEF_BLOCK_ID, Stream);
+ INFORECORD(NONDEF)
+ emitRecordID(NONDEF_TYPE, Stream);
+ emitRecordID(NONDEF_LOCATION, Stream);
+ INFOABBREV(NONDEF)
+ emitIntAbbrev(NONDEF_TYPE, NONDEF_BLOCK_ID, Stream);
+ emitLocationAbbrev(NONDEF_LOCATION, NONDEF_BLOCK_ID, Stream);
+
+ // Enum Block
+ emitBlockID(ENUM_BLOCK_ID, Stream);
+ INFORECORD(ENUM)
+ emitRecordID(ENUM_DEFLOCATION, Stream);
+ emitRecordID(ENUM_LOCATION, Stream);
+ emitRecordID(ENUM_SCOPED, Stream);
+ INFOABBREV(ENUM)
+ emitLocationAbbrev(ENUM_DEFLOCATION, ENUM_BLOCK_ID, Stream);
+ emitLocationAbbrev(ENUM_LOCATION, ENUM_BLOCK_ID, Stream);
+ emitIntAbbrev(ENUM_SCOPED, ENUM_BLOCK_ID, Stream);
+
+ // Record Block
+ emitBlockID(RECORD_BLOCK_ID, Stream);
+ INFORECORD(RECORD)
+ emitRecordID(RECORD_DEFLOCATION, Stream);
+ emitRecordID(RECORD_LOCATION, Stream);
+ emitRecordID(RECORD_TAG_TYPE, Stream);
+ emitRecordID(RECORD_PARENT, Stream);
+ emitRecordID(RECORD_VPARENT, Stream);
+ INFOABBREV(RECORD)
+ emitLocationAbbrev(RECORD_DEFLOCATION, RECORD_BLOCK_ID, Stream);
+ emitLocationAbbrev(RECORD_LOCATION, RECORD_BLOCK_ID, Stream);
+ emitIntAbbrev(RECORD_TAG_TYPE, RECORD_BLOCK_ID, Stream);
+ emitStringAbbrev(RECORD_PARENT, RECORD_BLOCK_ID, Stream);
+ emitStringAbbrev(RECORD_VPARENT, RECORD_BLOCK_ID, Stream);
+
+ // Function Block
+ emitBlockID(FUNCTION_BLOCK_ID, Stream);
+ INFORECORD(FUNCTION)
+ emitRecordID(FUNCTION_DEFLOCATION, Stream);
+ emitRecordID(FUNCTION_LOCATION, Stream);
+ emitRecordID(FUNCTION_MANGLED_NAME, Stream);
+ emitRecordID(FUNCTION_PARENT, Stream);
+ emitRecordID(FUNCTION_ACCESS, Stream);
+ INFOABBREV(FUNCTION)
+ emitLocationAbbrev(FUNCTION_DEFLOCATION, FUNCTION_BLOCK_ID, Stream);
+ emitLocationAbbrev(FUNCTION_LOCATION, FUNCTION_BLOCK_ID, Stream);
+ emitStringAbbrev(FUNCTION_MANGLED_NAME, FUNCTION_BLOCK_ID, Stream);
+ emitStringAbbrev(FUNCTION_PARENT, FUNCTION_BLOCK_ID, Stream);
+ emitIntAbbrev(FUNCTION_ACCESS, FUNCTION_BLOCK_ID, Stream);
+
+#undef INFORECORDS
+#undef INFOABBREV
+
+ Stream.ExitBlock();
+}
+
+// Info emission
+
+#define EMITINFO(X) \
+ emitStringRecord(I.FullyQualifiedName, X##_FULLY_QUALIFIED_NAME, Stream); \
+ emitStringRecord(I.SimpleName, X##_NAME, Stream); \
+ emitStringRecord(I.Namespace, X##_NAMESPACE, Stream); \
+ for (const auto &CI : I.Description) \
+ emitCommentBlock(&CI, Stream);
+
+template <>
+void ClangDocBinaryWriter::writeBitstream(const NamespaceInfo &I,
+ BitstreamWriter &Stream, bool writeBlockInfo) {
+ if (writeBlockInfo) emitBlockInfoBlock(Stream);
+ Stream.EnterSubblock(NAMESPACE_BLOCK_ID, BitCodeConstants::SubblockIDSize);
+ EMITINFO(NAMESPACE)
+ Stream.ExitBlock();
+}
+
+template <>
+void ClangDocBinaryWriter::writeBitstream(const NonDefInfo &I,
+ BitstreamWriter &Stream, bool writeBlockInfo) {
+ if (writeBlockInfo) emitBlockInfoBlock(Stream);
+ Stream.EnterSubblock(NONDEF_BLOCK_ID, BitCodeConstants::SubblockIDSize);
+ EMITINFO(NONDEF)
+ emitIntRecord(I.Type, NONDEF_TYPE, Stream);
+ for (const auto &L : I.Loc)
+ emitLocationRecord(L.LineNumber, L.Filename, NONDEF_LOCATION, Stream);
+ Stream.ExitBlock();
+}
+
+template <>
+void ClangDocBinaryWriter::writeBitstream(const EnumInfo &I,
+ BitstreamWriter &Stream, bool writeBlockInfo) {
+ if (writeBlockInfo) emitBlockInfoBlock(Stream);
+ Stream.EnterSubblock(ENUM_BLOCK_ID, BitCodeConstants::SubblockIDSize);
+ EMITINFO(ENUM)
+ emitLocationRecord(I.DefLoc.LineNumber, I.DefLoc.Filename, ENUM_DEFLOCATION, Stream);
+ for (const auto &L : I.Loc)
+ emitLocationRecord(L.LineNumber, L.Filename, ENUM_LOCATION, Stream);
+ emitIntRecord(I.Scoped, ENUM_SCOPED, Stream);
+ for (const auto &N : I.Members)
+ emitNamedTypeBlock(N, NamedType::MEMBER, Stream);
+ Stream.ExitBlock();
+}
+
+template <>
+void ClangDocBinaryWriter::writeBitstream(const RecordInfo &I,
+ BitstreamWriter &Stream, bool writeBlockInfo) {
+ if (writeBlockInfo) emitBlockInfoBlock(Stream);
+ Stream.EnterSubblock(RECORD_BLOCK_ID, BitCodeConstants::SubblockIDSize);
+ EMITINFO(RECORD)
+ emitLocationRecord(I.DefLoc.LineNumber, I.DefLoc.Filename, RECORD_DEFLOCATION, Stream);
+ for (const auto &L : I.Loc)
+ emitLocationRecord(L.LineNumber, L.Filename, RECORD_LOCATION, Stream);
+ emitIntRecord(I.TagType, RECORD_TAG_TYPE, Stream);
+ for (const auto &N : I.Members)
+ emitNamedTypeBlock(N, NamedType::MEMBER, Stream);
+ for (const auto &P : I.Parents) emitStringRecord(P, RECORD_PARENT, Stream);
+ for (const auto &P : I.VirtualParents)
+ emitStringRecord(P, RECORD_VPARENT, Stream);
+ Stream.ExitBlock();
+}
+
+template <>
+void ClangDocBinaryWriter::writeBitstream(const FunctionInfo &I,
+ BitstreamWriter &Stream, bool writeBlockInfo) {
+ if (writeBlockInfo) emitBlockInfoBlock(Stream);
+ Stream.EnterSubblock(FUNCTION_BLOCK_ID, BitCodeConstants::SubblockIDSize);
+ EMITINFO(FUNCTION)
+ emitLocationRecord(I.DefLoc.LineNumber, I.DefLoc.Filename, FUNCTION_DEFLOCATION, Stream);
+ for (const auto &L : I.Loc)
+ emitLocationRecord(L.LineNumber, L.Filename, FUNCTION_LOCATION, Stream);
+ emitStringRecord(I.MangledName, FUNCTION_MANGLED_NAME, Stream);
+ emitStringRecord(I.Parent, FUNCTION_PARENT, Stream);
+ emitNamedTypeBlock(I.ReturnType, NamedType::RETTYPE, Stream);
+ for (const auto &N : I.Params)
+ emitNamedTypeBlock(N, NamedType::PARAM, Stream);
+ Stream.ExitBlock();
+}
+
+#undef EMITINFO
+
+} // namespace doc
+} // namespace clang
Index: clang-doc/ClangDoc.h
===================================================================
--- /dev/null
+++ clang-doc/ClangDoc.h
@@ -0,0 +1,60 @@
+//===-- ClangDoc.h - 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 <string>
+#include <vector>
+#include "ClangDocBinary.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/ASTConsumers.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Tooling/Tooling.h"
+
+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,
+ ClangDocBinaryWriter &Writer)
+ : ECtx(ECtx), Mapper(Writer), 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) const;
+ 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,86 @@
+//===-- 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"
+#include "llvm/Bitcode/BitstreamWriter.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) const {
+ 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 MangledName.str();
+ }
+ return D->getQualifiedNameAsString();
+}
+
+} // namespace doc
+} // namespace clang
Index: clang-doc/CMakeLists.txt
===================================================================
--- /dev/null
+++ clang-doc/CMakeLists.txt
@@ -0,0 +1,21 @@
+set(LLVM_LINK_COMPONENTS
+ support
+ )
+
+add_clang_library(clangDoc
+ ClangDoc.cpp
+ ClangDocMapper.cpp
+ ClangDocBinary.cpp
+
+ LINK_LIBS
+ clangAnalysis
+ clangAST
+ clangASTMatchers
+ clangBasic
+ 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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits