juliehockett created this revision.
juliehockett added a project: clang.
Herald added a subscriber: mgorny.

Setting up a basic frontend framework for a clang-doc tool. It creates a 
frontend action for traversing the AST to extract comments and declarations, 
with a flag to only extract documentation-style comments. Right now, it outputs 
its findings in YAML format to the command line.

For a more detailed overview of the tool, see the design document on the 
mailing list: RFC: clang-doc proposal 
<http://lists.llvm.org/pipermail/cfe-dev/2017-December/056203.html>


https://reviews.llvm.org/D41102

Files:
  tools/CMakeLists.txt
  tools/clang-doc/CMakeLists.txt
  tools/clang-doc/ClangDoc.cpp
  tools/clang-doc/ClangDoc.h
  tools/clang-doc/ClangDocReporter.cpp
  tools/clang-doc/ClangDocReporter.h
  tools/clang-doc/tool/CMakeLists.txt
  tools/clang-doc/tool/ClangDocMain.cpp

Index: tools/clang-doc/tool/ClangDocMain.cpp
===================================================================
--- /dev/null
+++ tools/clang-doc/tool/ClangDocMain.cpp
@@ -0,0 +1,70 @@
+//===-- 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/Driver/Options.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Signals.h"
+#include <string>
+
+using namespace clang;
+using namespace llvm;
+
+namespace {
+
+cl::OptionCategory ClangDocCategory("clang-doc options");
+
+cl::opt<std::string>
+    EmitFormat("emit",
+               cl::desc("Output format (valid options are -emit=json and "
+                        "-emit=llvm)."),
+               cl::init("llvm"), cl::cat(ClangDocCategory));
+
+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) {
+  llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
+  tooling::CommonOptionsParser OptionsParser(argc, argv, ClangDocCategory);
+
+  if (EmitFormat != "llvm" && EmitFormat != "json") {
+    llvm::errs() << "Please specify llvm or json output.\n";
+    return 1;
+  }
+
+  // TODO: Update the source path list to only consider changed files for
+  // incremental doc updates
+  doc::ClangDocReporter Reporter(OptionsParser.getSourcePathList());
+  doc::ClangDocContext Context{EmitFormat};
+  llvm::outs() << "Output results in " << Context.EmitFormat << " format.\n";
+
+  tooling::ClangTool Tool(OptionsParser.getCompilations(),
+                          OptionsParser.getSourcePathList());
+
+  if (!DoxygenOnly)
+    Tool.appendArgumentsAdjuster(tooling::getInsertArgumentAdjuster(
+        "-fparse-all-comments", tooling::ArgumentInsertPosition::BEGIN));
+
+  doc::ClangDocActionFactory Factory(Context, Reporter);
+
+  llvm::outs() << "Parsing codebase...\n";
+  int Status = Tool.run(&Factory);
+  if (Status)
+    return Status;
+
+  llvm::outs() << "Writing docs...\n";
+  Reporter.Serialize(EmitFormat, llvm::outs());
+}
Index: tools/clang-doc/tool/CMakeLists.txt
===================================================================
--- /dev/null
+++ tools/clang-doc/tool/CMakeLists.txt
@@ -0,0 +1,17 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
+
+add_clang_executable(clang-doc
+  ClangDocMain.cpp
+  )
+
+target_link_libraries(clang-doc
+  clangAST
+  clangASTMatchers
+  clangBasic
+  clangFormat
+  clangFrontend
+  clangDoc
+  clangRewrite
+  clangTooling
+  clangToolingCore
+  )
\ No newline at end of file
Index: tools/clang-doc/ClangDocReporter.h
===================================================================
--- /dev/null
+++ tools/clang-doc/ClangDocReporter.h
@@ -0,0 +1,111 @@
+//===-- Doc.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_CLANG_DOC_REPORTER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_REPORTER_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/Tooling.h"
+#include "llvm/Support/raw_ostream.h"
+#include <set>
+#include <string>
+#include <vector>
+
+using namespace clang::comments;
+
+namespace clang {
+namespace doc {
+
+struct StringPair {
+  std::string Key;
+  std::string Value;
+};
+
+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;
+  std::vector<std::string> Args;
+  std::vector<StringPair> Attrs;
+  std::vector<int> Position;
+  std::vector<CommentInfo> Children;
+};
+
+// TODO: collect declarations of the same object, comment is preferentially:
+// 1) docstring on definition, 2) combined docstring from non-def decls, or
+// 3) comment on definition, 4) no comment.
+struct DeclInfo {
+  const Decl *D;
+  std::string QualifiedName;
+  CommentInfo Comment;
+};
+
+struct FileRecord {
+  std::string Filename;
+  std::vector<DeclInfo> Decls;
+  std::vector<CommentInfo> UnattachedComments;
+};
+
+class ClangDocReporter : public ConstCommentVisitor<ClangDocReporter> {
+public:
+  ClangDocReporter(std::vector<std::string> SourcePathList);
+
+  void AddComment(StringRef Filename, CommentInfo &CI);
+  void AddDecl(StringRef Filename, DeclInfo &D);
+  void AddFile(StringRef Filename);
+  void AddFileInTU(StringRef Filename) { FilesInThisTU.insert(Filename); }
+  void AddFileSeen(StringRef Filename) { FilesSeen.insert(Filename); }
+  void ClearFilesInThisTU() { FilesInThisTU.clear(); };
+
+  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);
+
+  CommentInfo ParseFullComment(comments::FullComment *Comment);
+
+  std::set<std::string> GetFilesInThisTU() const { return FilesInThisTU; }
+  bool HasFile(StringRef Filename) const;
+  bool HasSeenFile(StringRef Filename) const;
+  void Serialize(StringRef Format, llvm::raw_ostream &OS) const;
+
+private:
+  void parseComment(CommentInfo *CI, comments::Comment *C);
+  void serializeYAML(llvm::raw_ostream &OS) const;
+  void serializeLLVM(llvm::raw_ostream &OS) const;
+  const char *getCommandName(unsigned CommandID);
+  bool isWhitespaceOnly(std::string S);
+
+  CommentInfo *CurrentCI;
+  llvm::StringMap<FileRecord> FileRecords;
+  std::set<std::string> FilesInThisTU;
+  std::set<std::string> FilesSeen;
+};
+
+} // namespace doc
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_REPORTER_H
Index: tools/clang-doc/ClangDocReporter.cpp
===================================================================
--- /dev/null
+++ tools/clang-doc/ClangDocReporter.cpp
@@ -0,0 +1,241 @@
+//===-- Doc.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 "ClangDocReporter.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/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace clang::tooling;
+using namespace llvm;
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(clang::doc::DeclInfo)
+LLVM_YAML_IS_SEQUENCE_VECTOR(clang::doc::StringPair)
+LLVM_YAML_IS_SEQUENCE_VECTOR(clang::doc::CommentInfo)
+
+namespace llvm {
+namespace yaml {
+
+template <> struct MappingTraits<clang::doc::StringPair> {
+  static void mapping(IO &IO, clang::doc::StringPair &Info) {
+    IO.mapRequired("key", Info.Key);
+    IO.mapRequired("value", Info.Value);
+  }
+};
+
+template <> struct MappingTraits<clang::doc::FileRecord> {
+  static void mapping(IO &IO, clang::doc::FileRecord &Info) {
+    IO.mapRequired("Filename", Info.Filename);
+    IO.mapRequired("Decls", Info.Decls);
+    IO.mapRequired("UnattachedComments", Info.UnattachedComments);
+  }
+};
+
+template <> struct MappingTraits<clang::doc::DeclInfo> {
+  static void mapping(IO &IO, clang::doc::DeclInfo &Info) {
+    IO.mapRequired("Name", Info.QualifiedName);
+    IO.mapRequired("Comment", Info.Comment);
+  }
+};
+
+template <> struct MappingTraits<clang::doc::CommentInfo> {
+  static void mapping(IO &IO, clang::doc::CommentInfo &Info) {
+    IO.mapRequired("Kind", Info.Kind);
+    if (!Info.Text.empty())
+      IO.mapRequired("Text", Info.Text);
+    if (!Info.Name.empty())
+      IO.mapRequired("Text", Info.Name);
+    if (!Info.Direction.empty())
+      IO.mapRequired("Direction", Info.Direction);
+    if (!Info.ParamName.empty())
+      IO.mapRequired("ParamName", Info.ParamName);
+    if (!Info.CloseName.empty())
+      IO.mapRequired("CloseName", Info.CloseName);
+    if (Info.SelfClosing)
+      IO.mapRequired("SelfClosing", Info.SelfClosing);
+    if (Info.Explicit)
+      IO.mapRequired("Explicit", Info.Explicit);
+    if (Info.Args.size() > 0)
+      IO.mapRequired("Args", Info.Args);
+    if (Info.Attrs.size() > 0)
+      IO.mapRequired("Attrs", Info.Attrs);
+    if (Info.Position.size() > 0)
+      IO.mapRequired("Position", Info.Position);
+    if (Info.Children.size() > 0)
+      IO.mapRequired("Children", Info.Children);
+  }
+};
+
+} // end namespace yaml
+} // end namespace llvm
+
+namespace clang {
+namespace doc {
+
+ClangDocReporter::ClangDocReporter(std::vector<std::string> SourcePathList) {
+  for (std::string Path : SourcePathList)
+    AddFile(Path);
+}
+
+void ClangDocReporter::AddComment(StringRef Filename, CommentInfo &CI) {
+  FileRecords[Filename].UnattachedComments.push_back(std::move(CI));
+}
+
+void ClangDocReporter::AddDecl(StringRef Filename, DeclInfo &DI) {
+  FileRecords[Filename].Decls.push_back(std::move(DI));
+}
+
+void ClangDocReporter::AddFile(StringRef Filename) {
+  FileRecord FI;
+  FI.Filename = Filename;
+  FileRecords.insert(std::pair<StringRef, FileRecord>(Filename, std::move(FI)));
+}
+
+CommentInfo ClangDocReporter::ParseFullComment(comments::FullComment *Comment) {
+  CommentInfo CI;
+  parseComment(&CI, Comment);
+  return CI;
+}
+
+void ClangDocReporter::visitTextComment(const TextComment *C) {
+  if (!isWhitespaceOnly(C->getText()))
+    CurrentCI->Text = C->getText();
+}
+
+void ClangDocReporter::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 ClangDocReporter::visitHTMLStartTagComment(const HTMLStartTagComment *C) {
+  CurrentCI->Name = C->getTagName();
+  if (C->getNumAttrs() != 0) {
+    for (unsigned i = 0, e = C->getNumAttrs(); i != e; ++i) {
+      const HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
+      StringPair Pair{Attr.Name, Attr.Value};
+      CurrentCI->Attrs.push_back(std::move(Pair));
+    }
+  }
+  C->isSelfClosing() ? CurrentCI->SelfClosing = true
+                     : CurrentCI->SelfClosing = false;
+}
+
+void ClangDocReporter::visitHTMLEndTagComment(const HTMLEndTagComment *C) {
+  CurrentCI->Name = C->getTagName();
+  CurrentCI->SelfClosing = true;
+}
+
+void ClangDocReporter::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 ClangDocReporter::visitParamCommandComment(const ParamCommandComment *C) {
+  CurrentCI->Direction =
+      ParamCommandComment::getDirectionAsString(C->getDirection());
+  C->isDirectionExplicit() ? CurrentCI->Explicit = true
+                           : CurrentCI->Explicit = false;
+  if (C->hasParamName() && C->isParamIndexValid())
+    CurrentCI->ParamName = C->getParamNameAsWritten();
+}
+
+void ClangDocReporter::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(C->getIndex(i));
+  }
+}
+
+void ClangDocReporter::visitVerbatimBlockComment(
+    const VerbatimBlockComment *C) {
+  CurrentCI->Name = getCommandName(C->getCommandID());
+  CurrentCI->CloseName = C->getCloseName();
+}
+
+void ClangDocReporter::visitVerbatimBlockLineComment(
+    const VerbatimBlockLineComment *C) {
+  if (!isWhitespaceOnly(C->getText()))
+    CurrentCI->Text = C->getText();
+}
+
+void ClangDocReporter::visitVerbatimLineComment(const VerbatimLineComment *C) {
+  if (!isWhitespaceOnly(C->getText()))
+    CurrentCI->Text = C->getText();
+}
+
+bool ClangDocReporter::HasFile(StringRef Filename) const {
+  return FileRecords.find(Filename) != FileRecords.end();
+}
+
+bool ClangDocReporter::HasSeenFile(StringRef Filename) const {
+  return FilesSeen.find(Filename) != FilesSeen.end();
+}
+
+void ClangDocReporter::Serialize(StringRef Format,
+                                 llvm::raw_ostream &OS) const {
+  Format == "llvm" ? serializeLLVM(OS) : serializeYAML(OS);
+}
+
+void ClangDocReporter::parseComment(CommentInfo *CI, comments::Comment *C) {
+  CurrentCI = CI;
+  CI->Kind = C->getCommentKindName();
+  ConstCommentVisitor<ClangDocReporter>::visit(C);
+  for (comments::Comment::child_iterator I = C->child_begin(),
+                                         E = C->child_end();
+       I != E; ++I) {
+    CommentInfo ChildCI;
+    parseComment(&ChildCI, *I);
+    CI->Children.push_back(std::move(ChildCI));
+  }
+}
+
+void ClangDocReporter::serializeYAML(llvm::raw_ostream &OS) const {
+  yaml::Output Output(OS);
+  for (const auto &F : FileRecords) {
+    FileRecord NonConstValue = F.second;
+    Output << NonConstValue;
+  }
+}
+
+void ClangDocReporter::serializeLLVM(llvm::raw_ostream &OS) const {
+  // TODO: Implement.
+  OS << "Not yet implemented.\n";
+}
+
+const char *ClangDocReporter::getCommandName(unsigned CommandID) {
+  ;
+  const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID);
+  if (Info)
+    return Info->Name;
+  // TODO: Add parsing for \file command.
+  return "<not a builtin command>";
+}
+
+bool ClangDocReporter::isWhitespaceOnly(std::string S) {
+  return S.find_first_not_of(" \t\n\v\f\r") == std::string::npos || S.empty();
+}
+
+} // namespace doc
+} // namespace clang
Index: tools/clang-doc/ClangDoc.h
===================================================================
--- /dev/null
+++ tools/clang-doc/ClangDoc.h
@@ -0,0 +1,89 @@
+//===-- 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 "ClangDocReporter.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Tooling/Tooling.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace doc {
+
+// A Context which contains extra options which are used in ClangMoveTool.
+struct ClangDocContext {
+  // Which format to emit representation in.
+  std::string EmitFormat;
+};
+
+class ClangDocVisitor : public RecursiveASTVisitor<ClangDocVisitor> {
+public:
+  explicit ClangDocVisitor(ASTContext *Context, ClangDocReporter &Reporter)
+      : Context(Context), Reporter(Reporter) {}
+
+  virtual bool VisitNamedDecl(const NamedDecl *D);
+
+  void ParseUnattachedComments();
+  bool IsNewComment(SourceLocation Loc, SourceManager &Manager) const;
+
+private:
+  ASTContext *Context;
+  ClangDocReporter &Reporter;
+};
+
+class ClangDocConsumer : public clang::ASTConsumer {
+public:
+  explicit ClangDocConsumer(ASTContext *Context, ClangDocReporter &Reporter)
+      : Visitor(Context, Reporter), Reporter(Reporter) {}
+
+  virtual void HandleTranslationUnit(clang::ASTContext &Context);
+
+private:
+  ClangDocVisitor Visitor;
+  ClangDocReporter &Reporter;
+};
+
+class ClangDocAction : public clang::ASTFrontendAction {
+public:
+  ClangDocAction(ClangDocReporter &Reporter) : Reporter(Reporter) {}
+
+  virtual std::unique_ptr<clang::ASTConsumer>
+  CreateASTConsumer(clang::CompilerInstance &Compiler, llvm::StringRef InFile);
+  virtual void EndSourceFileAction();
+
+private:
+  ClangDocReporter &Reporter;
+};
+
+class ClangDocActionFactory : public tooling::FrontendActionFactory {
+public:
+  ClangDocActionFactory(ClangDocContext &Context, ClangDocReporter &Reporter)
+      : Context(Context), Reporter(Reporter) {}
+
+  clang::FrontendAction *create() override {
+    return new ClangDocAction(Reporter);
+  }
+
+private:
+  ClangDocContext &Context;
+  ClangDocReporter &Reporter;
+};
+
+} // namespace doc
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANGDOC_H
Index: tools/clang-doc/ClangDoc.cpp
===================================================================
--- /dev/null
+++ tools/clang-doc/ClangDoc.cpp
@@ -0,0 +1,93 @@
+//===-- 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/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Comment.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Tooling/Tooling.h"
+
+using namespace clang;
+using namespace clang::tooling;
+using namespace llvm;
+
+namespace clang {
+namespace doc {
+
+// TODO: limit to functions/objects/namespaces/etc?
+bool ClangDocVisitor::VisitNamedDecl(const NamedDecl *D) {
+  SourceManager &Manager = Context->getSourceManager();
+  if (!IsNewComment(D->getLocation(), Manager))
+    return true;
+
+  DeclInfo DI;
+  DI.D = D;
+  DI.QualifiedName = D->getQualifiedNameAsString();
+  RawComment *Comment = Context->getRawCommentForDeclNoCache(D);
+
+  // TODO: Move set attached to the initial comment parsing, not here
+  if (Comment) {
+    Comment->setAttached();
+    DI.Comment =
+        Reporter.ParseFullComment(Comment->parse(*Context, nullptr, D));
+  }
+  Reporter.AddDecl(Manager.getFilename(D->getLocation()), DI);
+  return true;
+}
+
+void ClangDocVisitor::ParseUnattachedComments() {
+  SourceManager &Manager = Context->getSourceManager();
+  for (RawComment *Comment : Context->getRawCommentList().getComments()) {
+    if (!IsNewComment(Comment->getLocStart(), Manager) || Comment->isAttached())
+      continue;
+    CommentInfo CI =
+        Reporter.ParseFullComment(Comment->parse(*Context, nullptr, nullptr));
+    Reporter.AddComment(Manager.getFilename(Comment->getLocStart()), CI);
+  }
+}
+
+bool ClangDocVisitor::IsNewComment(SourceLocation Loc,
+                                   SourceManager &Manager) const {
+  if (!Loc.isValid())
+    return false;
+  const std::string &Filename = Manager.getFilename(Loc);
+  if (!Reporter.HasFile(Filename) || Reporter.HasSeenFile(Filename))
+    return false;
+  if (Manager.isInSystemHeader(Loc) || Manager.isInExternCSystemHeader(Loc))
+    return false;
+  Reporter.AddFileInTU(Filename);
+  return true;
+}
+
+void ClangDocConsumer::HandleTranslationUnit(ASTContext &Context) {
+  Visitor.TraverseDecl(Context.getTranslationUnitDecl());
+  Visitor.ParseUnattachedComments();
+}
+
+std::unique_ptr<ASTConsumer>
+ClangDocAction::CreateASTConsumer(CompilerInstance &Compiler,
+                                  llvm::StringRef InFile) {
+  return std::unique_ptr<ASTConsumer>(
+      new ClangDocConsumer(&Compiler.getASTContext(), Reporter));
+}
+
+void ClangDocAction::EndSourceFileAction() {
+  for (const auto &Filename : Reporter.GetFilesInThisTU()) {
+    Reporter.AddFileSeen(Filename);
+  }
+  Reporter.ClearFilesInThisTU();
+}
+
+} // namespace doc
+} // namespace clang
Index: tools/clang-doc/CMakeLists.txt
===================================================================
--- /dev/null
+++ tools/clang-doc/CMakeLists.txt
@@ -0,0 +1,21 @@
+set(LLVM_LINK_COMPONENTS
+  support
+  )
+
+add_clang_library(clangDoc
+  ClangDoc.cpp
+  ClangDocReporter.cpp
+
+  LINK_LIBS
+  clangAnalysis
+  clangAST
+  clangASTMatchers
+  clangBasic
+  clangFormat
+  clangFrontend
+  clangLex
+  clangTooling
+  clangToolingCore
+  )
+
+add_subdirectory(tool)
Index: tools/CMakeLists.txt
===================================================================
--- tools/CMakeLists.txt
+++ tools/CMakeLists.txt
@@ -3,6 +3,7 @@
 add_clang_subdirectory(diagtool)
 add_clang_subdirectory(driver)
 add_clang_subdirectory(clang-diff)
+add_clang_subdirectory(clang-doc)
 add_clang_subdirectory(clang-format)
 add_clang_subdirectory(clang-format-vs)
 add_clang_subdirectory(clang-fuzzer)
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to