12
12
#include " clang/AST/Comment.h"
13
13
#include " clang/Index/USRGeneration.h"
14
14
#include " llvm/ADT/StringExtras.h"
15
- #include " llvm/Support/Error.h"
15
+ #include " llvm/ADT/StringSet.h"
16
+ #include " llvm/Support/Mutex.h"
16
17
17
18
namespace clang {
18
19
namespace doc {
19
20
21
+ static llvm::StringSet<> USRVisited;
22
+ static llvm::sys::Mutex USRVisitedGuard;
23
+
24
+ template <typename T> bool isTypedefAnonRecord (const T *D) {
25
+ if (const auto *C = dyn_cast<CXXRecordDecl>(D)) {
26
+ return C->getTypedefNameForAnonDecl ();
27
+ }
28
+ return false ;
29
+ }
30
+
20
31
void MapASTVisitor::HandleTranslationUnit (ASTContext &Context) {
21
32
TraverseDecl (Context.getTranslationUnitDecl ());
22
33
}
23
34
24
- template <typename T> bool MapASTVisitor::mapDecl (const T *D) {
35
+ template <typename T>
36
+ bool MapASTVisitor::mapDecl (const T *D, bool IsDefinition) {
25
37
// If we're looking a decl not in user files, skip this decl.
26
38
if (D->getASTContext ().getSourceManager ().isInSystemHeader (D->getLocation ()))
27
39
return true ;
@@ -34,6 +46,16 @@ template <typename T> bool MapASTVisitor::mapDecl(const T *D) {
34
46
// If there is an error generating a USR for the decl, skip this decl.
35
47
if (index ::generateUSRForDecl (D, USR))
36
48
return true ;
49
+ // Prevent Visiting USR twice
50
+ {
51
+ std::lock_guard<llvm::sys::Mutex> Guard (USRVisitedGuard);
52
+ StringRef Visited = USR.str ();
53
+ if (USRVisited.count (Visited) && !isTypedefAnonRecord<T>(D))
54
+ return true ;
55
+ // We considered a USR to be visited only when its defined
56
+ if (IsDefinition)
57
+ USRVisited.insert (Visited);
58
+ }
37
59
bool IsFileInRootDir;
38
60
llvm::SmallString<128 > File =
39
61
getFile (D, D->getASTContext (), CDCtx.SourceRoot , IsFileInRootDir);
@@ -53,30 +75,34 @@ template <typename T> bool MapASTVisitor::mapDecl(const T *D) {
53
75
}
54
76
55
77
bool MapASTVisitor::VisitNamespaceDecl (const NamespaceDecl *D) {
56
- return mapDecl (D);
78
+ return mapDecl (D, /* isDefinition= */ true );
57
79
}
58
80
59
- bool MapASTVisitor::VisitRecordDecl (const RecordDecl *D) { return mapDecl (D); }
81
+ bool MapASTVisitor::VisitRecordDecl (const RecordDecl *D) {
82
+ return mapDecl (D, D->isThisDeclarationADefinition ());
83
+ }
60
84
61
- bool MapASTVisitor::VisitEnumDecl (const EnumDecl *D) { return mapDecl (D); }
85
+ bool MapASTVisitor::VisitEnumDecl (const EnumDecl *D) {
86
+ return mapDecl (D, D->isThisDeclarationADefinition ());
87
+ }
62
88
63
89
bool MapASTVisitor::VisitCXXMethodDecl (const CXXMethodDecl *D) {
64
- return mapDecl (D);
90
+ return mapDecl (D, D-> isThisDeclarationADefinition () );
65
91
}
66
92
67
93
bool MapASTVisitor::VisitFunctionDecl (const FunctionDecl *D) {
68
94
// Don't visit CXXMethodDecls twice
69
95
if (isa<CXXMethodDecl>(D))
70
96
return true ;
71
- return mapDecl (D);
97
+ return mapDecl (D, D-> isThisDeclarationADefinition () );
72
98
}
73
99
74
100
bool MapASTVisitor::VisitTypedefDecl (const TypedefDecl *D) {
75
- return mapDecl (D);
101
+ return mapDecl (D, /* isDefinition= */ true );
76
102
}
77
103
78
104
bool MapASTVisitor::VisitTypeAliasDecl (const TypeAliasDecl *D) {
79
- return mapDecl (D);
105
+ return mapDecl (D, /* isDefinition= */ true );
80
106
}
81
107
82
108
comments::FullComment *
0 commit comments