Mapper.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. //===-- Mapper.cpp - ClangDoc Mapper ----------------------------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "Mapper.h"
  9. #include "BitcodeWriter.h"
  10. #include "Serialize.h"
  11. #include "clang/AST/Comment.h"
  12. #include "clang/Index/USRGeneration.h"
  13. #include "llvm/ADT/StringExtras.h"
  14. #include "llvm/Support/Error.h"
  15. namespace clang {
  16. namespace doc {
  17. void MapASTVisitor::HandleTranslationUnit(ASTContext &Context) {
  18. TraverseDecl(Context.getTranslationUnitDecl());
  19. }
  20. template <typename T> bool MapASTVisitor::mapDecl(const T *D) {
  21. // If we're looking a decl not in user files, skip this decl.
  22. if (D->getASTContext().getSourceManager().isInSystemHeader(D->getLocation()))
  23. return true;
  24. // Skip function-internal decls.
  25. if (D->getParentFunctionOrMethod())
  26. return true;
  27. llvm::SmallString<128> USR;
  28. // If there is an error generating a USR for the decl, skip this decl.
  29. if (index::generateUSRForDecl(D, USR))
  30. return true;
  31. bool IsFileInRootDir;
  32. llvm::SmallString<128> File =
  33. getFile(D, D->getASTContext(), CDCtx.SourceRoot, IsFileInRootDir);
  34. auto I = serialize::emitInfo(D, getComment(D, D->getASTContext()),
  35. getLine(D, D->getASTContext()), File,
  36. IsFileInRootDir, CDCtx.PublicOnly);
  37. // A null in place of I indicates that the serializer is skipping this decl
  38. // for some reason (e.g. we're only reporting public decls).
  39. if (I.first)
  40. CDCtx.ECtx->reportResult(llvm::toHex(llvm::toStringRef(I.first->USR)),
  41. serialize::serialize(I.first));
  42. if (I.second)
  43. CDCtx.ECtx->reportResult(llvm::toHex(llvm::toStringRef(I.second->USR)),
  44. serialize::serialize(I.second));
  45. return true;
  46. }
  47. bool MapASTVisitor::VisitNamespaceDecl(const NamespaceDecl *D) {
  48. return mapDecl(D);
  49. }
  50. bool MapASTVisitor::VisitRecordDecl(const RecordDecl *D) { return mapDecl(D); }
  51. bool MapASTVisitor::VisitEnumDecl(const EnumDecl *D) { return mapDecl(D); }
  52. bool MapASTVisitor::VisitCXXMethodDecl(const CXXMethodDecl *D) {
  53. return mapDecl(D);
  54. }
  55. bool MapASTVisitor::VisitFunctionDecl(const FunctionDecl *D) {
  56. // Don't visit CXXMethodDecls twice
  57. if (isa<CXXMethodDecl>(D))
  58. return true;
  59. return mapDecl(D);
  60. }
  61. comments::FullComment *
  62. MapASTVisitor::getComment(const NamedDecl *D, const ASTContext &Context) const {
  63. RawComment *Comment = Context.getRawCommentForDeclNoCache(D);
  64. // FIXME: Move setAttached to the initial comment parsing.
  65. if (Comment) {
  66. Comment->setAttached();
  67. return Comment->parse(Context, nullptr, D);
  68. }
  69. return nullptr;
  70. }
  71. int MapASTVisitor::getLine(const NamedDecl *D,
  72. const ASTContext &Context) const {
  73. return Context.getSourceManager().getPresumedLoc(D->getBeginLoc()).getLine();
  74. }
  75. llvm::SmallString<128> MapASTVisitor::getFile(const NamedDecl *D,
  76. const ASTContext &Context,
  77. llvm::StringRef RootDir,
  78. bool &IsFileInRootDir) const {
  79. llvm::SmallString<128> File(Context.getSourceManager()
  80. .getPresumedLoc(D->getBeginLoc())
  81. .getFilename());
  82. IsFileInRootDir = false;
  83. if (RootDir.empty() || !File.startswith(RootDir))
  84. return File;
  85. IsFileInRootDir = true;
  86. llvm::SmallString<128> Prefix(RootDir);
  87. // replace_path_prefix removes the exact prefix provided. The result of
  88. // calling that function on ("A/B/C.c", "A/B", "") would be "/C.c", which
  89. // starts with a / that is not needed. This is why we fix Prefix so it always
  90. // ends with a / and the result has the desired format.
  91. if (!llvm::sys::path::is_separator(Prefix.back()))
  92. Prefix += llvm::sys::path::get_separator();
  93. llvm::sys::path::replace_path_prefix(File, Prefix, "");
  94. return File;
  95. }
  96. } // namespace doc
  97. } // namespace clang