1 //===-- Mapper.cpp - ClangDoc Mapper ----------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
10 #include "BitcodeWriter.h"
11 #include "Serialize.h"
12 #include "clang/AST/Comment.h"
13 #include "clang/Index/USRGeneration.h"
14 #include "llvm/ADT/StringExtras.h"
15 #include "llvm/Support/Error.h"
20 void MapASTVisitor::HandleTranslationUnit(ASTContext
&Context
) {
21 TraverseDecl(Context
.getTranslationUnitDecl());
24 template <typename T
> bool MapASTVisitor::mapDecl(const T
*D
) {
25 // If we're looking a decl not in user files, skip this decl.
26 if (D
->getASTContext().getSourceManager().isInSystemHeader(D
->getLocation()))
29 // Skip function-internal decls.
30 if (D
->getParentFunctionOrMethod())
33 llvm::SmallString
<128> USR
;
34 // If there is an error generating a USR for the decl, skip this decl.
35 if (index::generateUSRForDecl(D
, USR
))
38 llvm::SmallString
<128> File
=
39 getFile(D
, D
->getASTContext(), CDCtx
.SourceRoot
, IsFileInRootDir
);
40 auto I
= serialize::emitInfo(D
, getComment(D
, D
->getASTContext()),
41 getLine(D
, D
->getASTContext()), File
,
42 IsFileInRootDir
, CDCtx
.PublicOnly
);
44 // A null in place of I indicates that the serializer is skipping this decl
45 // for some reason (e.g. we're only reporting public decls).
47 CDCtx
.ECtx
->reportResult(llvm::toHex(llvm::toStringRef(I
.first
->USR
)),
48 serialize::serialize(I
.first
));
50 CDCtx
.ECtx
->reportResult(llvm::toHex(llvm::toStringRef(I
.second
->USR
)),
51 serialize::serialize(I
.second
));
55 bool MapASTVisitor::VisitNamespaceDecl(const NamespaceDecl
*D
) {
59 bool MapASTVisitor::VisitRecordDecl(const RecordDecl
*D
) { return mapDecl(D
); }
61 bool MapASTVisitor::VisitEnumDecl(const EnumDecl
*D
) { return mapDecl(D
); }
63 bool MapASTVisitor::VisitCXXMethodDecl(const CXXMethodDecl
*D
) {
67 bool MapASTVisitor::VisitFunctionDecl(const FunctionDecl
*D
) {
68 // Don't visit CXXMethodDecls twice
69 if (isa
<CXXMethodDecl
>(D
))
74 bool MapASTVisitor::VisitTypedefDecl(const TypedefDecl
*D
) {
78 bool MapASTVisitor::VisitTypeAliasDecl(const TypeAliasDecl
*D
) {
82 comments::FullComment
*
83 MapASTVisitor::getComment(const NamedDecl
*D
, const ASTContext
&Context
) const {
84 RawComment
*Comment
= Context
.getRawCommentForDeclNoCache(D
);
85 // FIXME: Move setAttached to the initial comment parsing.
87 Comment
->setAttached();
88 return Comment
->parse(Context
, nullptr, D
);
93 int MapASTVisitor::getLine(const NamedDecl
*D
,
94 const ASTContext
&Context
) const {
95 return Context
.getSourceManager().getPresumedLoc(D
->getBeginLoc()).getLine();
98 llvm::SmallString
<128> MapASTVisitor::getFile(const NamedDecl
*D
,
99 const ASTContext
&Context
,
100 llvm::StringRef RootDir
,
101 bool &IsFileInRootDir
) const {
102 llvm::SmallString
<128> File(Context
.getSourceManager()
103 .getPresumedLoc(D
->getBeginLoc())
105 IsFileInRootDir
= false;
106 if (RootDir
.empty() || !File
.starts_with(RootDir
))
108 IsFileInRootDir
= true;
109 llvm::SmallString
<128> Prefix(RootDir
);
110 // replace_path_prefix removes the exact prefix provided. The result of
111 // calling that function on ("A/B/C.c", "A/B", "") would be "/C.c", which
112 // starts with a / that is not needed. This is why we fix Prefix so it always
113 // ends with a / and the result has the desired format.
114 if (!llvm::sys::path::is_separator(Prefix
.back()))
115 Prefix
+= llvm::sys::path::get_separator();
116 llvm::sys::path::replace_path_prefix(File
, Prefix
, "");