Skip to content

Commit b10dbb0

Browse files
committed
fix(ast): canonicalize friend targets
canonicalize friend targets to avoid recursion fix #1117
1 parent 9ca1c15 commit b10dbb0

15 files changed

+236
-20
lines changed

src/lib/AST/ASTVisitor.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -753,10 +753,7 @@ populate(
753753
{
754754
for (clang::FriendDecl const* FD : D->friends())
755755
{
756-
// Check if the friend is a fundamental type
757-
// Declaring a fundamental type like `int` as a friend of a
758-
// class or struct does not have any practical effect. Thus,
759-
// it's not considered part of the public API.
756+
// Skip meaningless builtin friend types
760757
if (clang::TypeSourceInfo const* TSI = FD->getFriendType())
761758
{
762759
clang::Type const* T = TSI->getType().getTypePtrOrNull();
@@ -1216,9 +1213,13 @@ populate(
12161213
}
12171214
else if (clang::NamedDecl const* ND = D->getFriendDecl())
12181215
{
1219-
// ND can be a function or a class
1216+
// ND can be a function or a class; converge to the semantic owner
1217+
// (primary template or canonical decl) before traversing so friend
1218+
// graphs built from many instantiations collapse to a single node.
1219+
clang::Decl const* Target = canonicalFriendTarget(ND);
1220+
MRDOCS_CHECK_OR(Target);
12201221
ScopeExitRestore s(mode_, Dependency);
1221-
if (Symbol const* SI = traverse(dyn_cast<clang::Decl>(ND)))
1222+
if (Symbol const* SI = findOrTraverse(Target))
12221223
{
12231224
I.id = SI->id;
12241225
}

src/lib/AST/ClangHelpers.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,45 @@ SubstituteConstraintExpressionWithoutSatisfaction(
8787
return SubstConstr.get();
8888
}
8989

90+
clang::Decl const*
91+
canonicalFriendTarget(clang::NamedDecl const* ND)
92+
{
93+
if (!ND)
94+
return nullptr;
95+
96+
if (auto const* CTSD = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(ND))
97+
{
98+
if (auto* T = CTSD->getSpecializedTemplate())
99+
return T->getTemplatedDecl()->getCanonicalDecl();
100+
}
101+
102+
if (auto const* CRD = llvm::dyn_cast<clang::CXXRecordDecl>(ND))
103+
{
104+
if (auto* CTD = CRD->getDescribedClassTemplate())
105+
return CTD->getTemplatedDecl()->getCanonicalDecl();
106+
}
107+
108+
if (auto const* VTS = llvm::dyn_cast<clang::VarTemplateSpecializationDecl>(ND))
109+
{
110+
if (auto* VT = VTS->getSpecializedTemplate())
111+
return VT->getTemplatedDecl()->getCanonicalDecl();
112+
}
113+
114+
if (auto const* VTD = llvm::dyn_cast<clang::VarTemplateDecl>(ND))
115+
return VTD->getTemplatedDecl()->getCanonicalDecl();
116+
117+
if (auto const* FD = llvm::dyn_cast<clang::FunctionDecl>(ND))
118+
{
119+
if (auto const* PT = FD->getPrimaryTemplate())
120+
return PT->getTemplatedDecl()->getCanonicalDecl();
121+
}
122+
123+
if (auto const* FTD = llvm::dyn_cast<clang::FunctionTemplateDecl>(ND))
124+
return FTD->getTemplatedDecl()->getCanonicalDecl();
125+
126+
return ND->getCanonicalDecl();
127+
}
128+
90129
clang::AccessSpecifier
91130
getAccess(clang::Decl const* D)
92131
{

src/lib/AST/ClangHelpers.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,15 @@ SubstituteConstraintExpressionWithoutSatisfaction(
5050
const clang::Sema::TemplateCompareNewDeclInfo &DeclInfo,
5151
const clang::Expr *ConstrExpr);
5252

53+
/** Collapse a friend target (function/class/template) to its canonical owner.
54+
55+
This resolves friend declarations that name template specializations or
56+
redeclarations to the primary/canonical declaration so traversal and
57+
symbol IDs converge on a single entity.
58+
*/
59+
clang::Decl const*
60+
canonicalFriendTarget(clang::NamedDecl const* ND);
61+
5362
/** Determine the MrDocs Info type for a Clang DeclType
5463
5564
This trait associates a Clang Decl type with the corresponding
Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
11
<html lang="en">
22
<head>
33
<title>Reference</title>
4+
<meta charset="utf-8">
45
</head>
56
<body>
67
<div>
78
<h1>Reference</h1>
89
<div>
910
<div>
10-
<h2 id="index"></h2>
11+
<h2 id="index">
12+
Global Namespace<a class="mrdocs-anchor" href="#index" aria-label="Permalink">#</a>
13+
</h2>
1114
</div>
1215
</div>
1316

1417
</div>
15-
<div>
16-
<h4>Created with <a href="https://www.mrdocs.com">MrDocs</a></h4>
17-
</div>
18+
<footer class="mrdocs-footer">
19+
<span>Created with <a href="https://www.mrdocs.com">MrDocs</a></span>
20+
</footer>
1821
</body>
1922
</html>

test-files/golden-tests/symbols/function/noreturn.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
</struct>
2020
<function name="f1" id="CnO51rIKTzfiVKHkR3TdPa0eo+8=">
2121
<file short-path="noreturn.cpp" source-path="noreturn.cpp" line="1"/>
22-
<file short-path="noreturn.cpp" source-path="noreturn.cpp" line="9"/>
2322
<attr id="is-no-return"/>
2423
</function>
2524
</namespace>

test-files/golden-tests/symbols/record/friend-duplicate.xml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515
<file short-path="friend-duplicate.cpp" source-path="friend-duplicate.cpp" line="12" class="def"/>
1616
</class>
1717
<function name="f" id="s6nsa+zVhpzzrN+yUVPP5rvdXqs=">
18-
<file short-path="friend-duplicate.cpp" source-path="friend-duplicate.cpp" line="9"/>
19-
<file short-path="friend-duplicate.cpp" source-path="friend-duplicate.cpp" line="8"/>
2018
<file short-path="friend-duplicate.cpp" source-path="friend-duplicate.cpp" line="7"/>
2119
<file short-path="friend-duplicate.cpp" source-path="friend-duplicate.cpp" line="14"/>
2220
</function>

test-files/golden-tests/symbols/record/friend-excluded.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
</class>
2222
<function name="f" id="s6nsa+zVhpzzrN+yUVPP5rvdXqs=">
2323
<file short-path="friend-excluded.cpp" source-path="friend-excluded.cpp" line="7"/>
24-
<file short-path="friend-excluded.cpp" source-path="friend-excluded.cpp" line="13"/>
2524
</function>
2625
</namespace>
2726
</mrdocs>

test-files/golden-tests/symbols/record/friend-fn-member.xml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
<file short-path="friend-fn-member.cpp" source-path="friend-fn-member.cpp" line="1" class="def"/>
1919
<function class="constructor" name="X" id="6Jx2eK9l4C46QIRucTvox+6PH2k=">
2020
<file short-path="friend-fn-member.cpp" source-path="friend-fn-member.cpp" line="3"/>
21-
<file short-path="friend-fn-member.cpp" source-path="friend-fn-member.cpp" line="13"/>
2221
<doc>
2322
<brief>
2423
<text>Default constructor</text>
@@ -27,7 +26,6 @@
2726
</function>
2827
<function class="destructor" name="~X" id="HK6hbp0kJrHWxbYoHddN1v/GCWc=">
2928
<file short-path="friend-fn-member.cpp" source-path="friend-fn-member.cpp" line="4"/>
30-
<file short-path="friend-fn-member.cpp" source-path="friend-fn-member.cpp" line="14"/>
3129
<doc>
3230
<brief>
3331
<text>Destructor</text>
@@ -36,7 +34,6 @@
3634
</function>
3735
<function name="foo" id="wZtQh+QR5vgNZmk34MnRmnKO5MI=">
3836
<file short-path="friend-fn-member.cpp" source-path="friend-fn-member.cpp" line="8"/>
39-
<file short-path="friend-fn-member.cpp" source-path="friend-fn-member.cpp" line="15"/>
4037
<return>
4138
<type class="pointer">
4239
<pointee-type name="char"/>

test-files/golden-tests/symbols/record/friend-fn-multi-2nd.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
</struct>
1717
<function name="f" id="s6nsa+zVhpzzrN+yUVPP5rvdXqs=">
1818
<file short-path="friend-fn-multi-2nd.cpp" source-path="friend-fn-multi-2nd.cpp" line="3"/>
19-
<file short-path="friend-fn-multi-2nd.cpp" source-path="friend-fn-multi-2nd.cpp" line="9"/>
2019
<file short-path="friend-fn-multi-2nd.cpp" source-path="friend-fn-multi-2nd.cpp" line="12"/>
2120
<doc>
2221
<brief>

test-files/golden-tests/symbols/record/friend-fn-multi-free.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
</struct>
1717
<function name="f" id="s6nsa+zVhpzzrN+yUVPP5rvdXqs=">
1818
<file short-path="friend-fn-multi-free.cpp" source-path="friend-fn-multi-free.cpp" line="3"/>
19-
<file short-path="friend-fn-multi-free.cpp" source-path="friend-fn-multi-free.cpp" line="8"/>
2019
<file short-path="friend-fn-multi-free.cpp" source-path="friend-fn-multi-free.cpp" line="12"/>
2120
<doc>
2221
<brief>

0 commit comments

Comments
 (0)