Mapper.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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. bool MapASTVisitor::VisitTypedefDecl(const TypedefDecl *D) {
  62. return mapDecl(D);
  63. }
  64. bool MapASTVisitor::VisitTypeAliasDecl(const TypeAliasDecl *D) {
  65. return mapDecl(D);
  66. }
  67. comments::FullComment *
  68. MapASTVisitor::getComment(const NamedDecl *D, const ASTContext &Context) const {
  69. RawComment *Comment = Context.getRawCommentForDeclNoCache(D);
  70. // FIXME: Move setAttached to the initial comment parsing.
  71. if (Comment) {
  72. Comment->setAttached();
  73. return Comment->parse(Context, nullptr, D);
  74. }
  75. return nullptr;
  76. }
  77. int MapASTVisitor::getLine(const NamedDecl *D,
  78. const ASTContext &Context) const {
  79. return Context.getSourceManager().getPresumedLoc(D->getBeginLoc()).getLine();
  80. }
  81. llvm::SmallString<128> MapASTVisitor::getFile(const NamedDecl *D,
  82. const ASTContext &Context,
  83. llvm::StringRef RootDir,
  84. bool &IsFileInRootDir) const {
  85. llvm::SmallString<128> File(Context.getSourceManager()
  86. .getPresumedLoc(D->getBeginLoc())
  87. .getFilename());
  88. IsFileInRootDir = false;
  89. if (RootDir.empty() || !File.startswith(RootDir))
  90. return File;
  91. IsFileInRootDir = true;
  92. llvm::SmallString<128> Prefix(RootDir);
  93. // replace_path_prefix removes the exact prefix provided. The result of
  94. // calling that function on ("A/B/C.c", "A/B", "") would be "/C.c", which
  95. // starts with a / that is not needed. This is why we fix Prefix so it always
  96. // ends with a / and the result has the desired format.
  97. if (!llvm::sys::path::is_separator(Prefix.back()))
  98. Prefix += llvm::sys::path::get_separator();
  99. llvm::sys::path::replace_path_prefix(File, Prefix, "");
  100. return File;
  101. }
  102. } // namespace doc
  103. } // namespace clang