Skip to content

Commit b7b2f37

Browse files
committed
extract dependency base class members
#feat
1 parent f778b44 commit b7b2f37

File tree

13 files changed

+649
-79
lines changed

13 files changed

+649
-79
lines changed

src/lib/AST/ASTVisitor.cpp

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ ASTVisitor::
160160
traverse(UsingDirectiveDecl* D)
161161
{
162162
// Find the parent namespace
163-
ScopeExitRestore s1(mode_, ExtractionMode::Dependency);
163+
ScopeExitRestore s1(mode_, TraversalMode::Dependency);
164164
Decl* P = getParent(D);
165165
MRDOCS_SYMBOL_TRACE(P, context_);
166166
Info* PI = findOrTraverse(P);
@@ -171,7 +171,7 @@ traverse(UsingDirectiveDecl* D)
171171
// Find the nominated namespace
172172
Decl* ND = D->getNominatedNamespace();
173173
MRDOCS_SYMBOL_TRACE(ND, context_);
174-
ScopeExitRestore s2(mode_, ExtractionMode::Dependency);
174+
ScopeExitRestore s2(mode_, TraversalMode::Dependency);
175175
Info* NDI = findOrTraverse(ND);
176176
MRDOCS_CHECK_OR(NDI, nullptr);
177177

@@ -205,29 +205,35 @@ traverseMembers(InfoTy& I, DeclTy* DC)
205205
std::derived_from<DeclTy, DeclContext>)
206206
{
207207
// We only need members of regular symbols and see-below namespaces
208-
// - SeeBelow symbols (that are not namespaces) are only the
209-
// symbol and the documentation.
210-
// - ImplementationDefined symbols have no pages
211-
// - Dependency symbols only need the names
212-
MRDOCS_CHECK_OR(
213-
I.Extraction == ExtractionMode::Regular ||
214-
I.Extraction == ExtractionMode::SeeBelow);
208+
// - If symbol is SeeBelow we want the members if it's a namespace
215209
MRDOCS_CHECK_OR(
216210
I.Extraction != ExtractionMode::SeeBelow ||
217211
I.Kind == InfoKind::Namespace);
218212

219-
// Set the context for the members
220-
ScopeExitRestore s(mode_, I.Extraction);
213+
// - If symbol is a Dependency, we only want the members if
214+
// the traversal mode is BaseClass
215+
MRDOCS_CHECK_OR(
216+
I.Extraction != ExtractionMode::Dependency ||
217+
mode_ == TraversalMode::BaseClass);
221218

222-
// There are many implicit declarations in the
223-
// translation unit declaration, so we preemtively
224-
// skip them here.
219+
// - If symbol is ImplementationDefined, we only want the members if
220+
// the traversal mode is BaseClass
221+
MRDOCS_CHECK_OR(
222+
I.Extraction != ExtractionMode::ImplementationDefined ||
223+
mode_ == TraversalMode::BaseClass);
224+
225+
// There are many implicit declarations, especially in the
226+
// translation unit declaration, so we preemtively skip them here.
225227
auto explicitMembers = std::ranges::views::filter(DC->decls(), [](Decl* D)
226228
{
227229
return !D->isImplicit() || isa<IndirectFieldDecl>(D);
228230
});
229231
for (auto* D : explicitMembers)
230232
{
233+
// No matter what happens in the process, we restore the
234+
// traversal mode to the original mode for the next member
235+
ScopeExitRestore s(mode_);
236+
// Traverse the member
231237
traverse(D);
232238
}
233239
}
@@ -259,12 +265,11 @@ traverseParents(InfoTy& I, DeclTy* DC)
259265
// Check if we haven't already extracted or started
260266
// to extract the parent scope
261267

262-
263268
// Traverse the parent scope as a dependency if it
264269
// hasn't been extracted yet
265270
Info* PI = nullptr;
266271
{
267-
ScopeExitRestore s(mode_, ExtractionMode::Dependency);
272+
ScopeExitRestore s(mode_, Dependency);
268273
if (PI = findOrTraverse(PD); !PI)
269274
{
270275
return;
@@ -548,7 +553,7 @@ populateInfoBases(InfoTy& I, bool const isNew, DeclTy* D)
548553
I.Extraction = ExtractionMode::Regular;
549554
// default mode also becomes regular for its
550555
// members
551-
mode_ = ExtractionMode::Regular;
556+
mode_ = TraversalMode::Regular;
552557
}
553558
}
554559

@@ -773,7 +778,7 @@ populate(
773778
}
774779

775780
QualType const BT = B.getType();
776-
auto BaseType = toTypeInfo(BT);
781+
auto BaseType = toTypeInfo(BT, BaseClass);
777782

778783
// CXXBaseSpecifier::getEllipsisLoc indicates whether the
779784
// base was a pack expansion; a PackExpansionType is not built
@@ -1210,10 +1215,9 @@ populate(
12101215
I.Qualifier = toNameInfo(D->getQualifier());
12111216
for (UsingShadowDecl const* UDS: D->shadows())
12121217
{
1213-
ScopeExitRestore s(mode_, ExtractionMode::Dependency);
1218+
ScopeExitRestore s(mode_, Dependency);
12141219
Decl* S = UDS->getTargetDecl();
1215-
Info* SI = findOrTraverse(S);
1216-
if (SI)
1220+
if (Info* SI = findOrTraverse(S))
12171221
{
12181222
I.UsingSymbols.emplace_back(SI->id);
12191223
}
@@ -1647,15 +1651,15 @@ generateJavadoc(
16471651

16481652
std::unique_ptr<TypeInfo>
16491653
ASTVisitor::
1650-
toTypeInfo(QualType const qt)
1654+
toTypeInfo(QualType const qt, TraversalMode const mode)
16511655
{
16521656
MRDOCS_SYMBOL_TRACE(qt, context_);
16531657

16541658
// The qualified symbol referenced by a regular symbol is a dependency.
16551659
// For library types, can be proved wrong and the Info type promoted
16561660
// to a regular type later on if the type matches the regular
16571661
// extraction criteria
1658-
ScopeExitRestore s(mode_, ExtractionMode::Dependency);
1662+
ScopeExitRestore s(mode_, mode);
16591663

16601664
// Build the TypeInfo representation for the type
16611665
TypeInfoBuilder Builder(*this);
@@ -1674,7 +1678,7 @@ toNameInfo(
16741678
}
16751679
MRDOCS_SYMBOL_TRACE(NNS, context_);
16761680

1677-
ScopeExitRestore scope(mode_,ExtractionMode::Dependency);
1681+
ScopeExitRestore scope(mode_, Dependency);
16781682
std::unique_ptr<NameInfo> I = nullptr;
16791683
if (const Type* T = NNS->getAsType())
16801684
{
@@ -1763,7 +1767,7 @@ toNameInfo(
17631767
{
17641768
return nullptr;
17651769
}
1766-
ScopeExitRestore scope(mode_, ExtractionMode::Dependency);
1770+
ScopeExitRestore scope(mode_, Dependency);
17671771
auto* ID = getInstantiatedFrom(D);
17681772
if (Info const* info = findOrTraverse(const_cast<Decl*>(ID)))
17691773
{
@@ -2397,15 +2401,15 @@ shouldExtract(
23972401
MRDOCS_CHECK_OR(!isa<TranslationUnitDecl>(D), true);
23982402

23992403
// Check if this kind of symbol should be extracted.
2400-
// This filters symbols supported by mrdocs and
2404+
// This filters symbols supported by MrDocs and
24012405
// symbol types whitelisted in the configuration,
24022406
// such as private members and anonymous namespaces.
24032407
MRDOCS_CHECK_OR(checkTypeFilters(D, access), false);
24042408

24052409
// In dependency mode, we don't need the file and symbol
24062410
// filters because this is a dependency of another
24072411
// declaration that passes the filters.
2408-
if (mode_ == ExtractionMode::Dependency)
2412+
if (mode_ != TraversalMode::Regular)
24092413
{
24102414
// If the whole declaration is implicit, we should
24112415
// not promote the extraction mode to regular
@@ -2426,7 +2430,7 @@ shouldExtract(
24262430
if (checkSymbolFilters(D) &&
24272431
checkFileFilters(D))
24282432
{
2429-
mode_ = ExtractionMode::Regular;
2433+
mode_ = TraversalMode::Regular;
24302434
}
24312435
// But we return true either way
24322436
return true;
@@ -2477,7 +2481,7 @@ checkTypeFilters(Decl const* D, AccessSpecifier access)
24772481
// KRYSTIAN FIXME: is this correct? a namespace should not
24782482
// be extracted as a dependency (until namespace aliases and
24792483
// using directives are supported)
2480-
MRDOCS_CHECK_OR(mode_ == ExtractionMode::Regular, false);
2484+
MRDOCS_CHECK_OR(mode_ == TraversalMode::Regular, false);
24812485
}
24822486

24832487
return true;
@@ -2832,7 +2836,9 @@ upsert(SymbolID const& id)
28322836
{
28332837
info = info_.emplace(std::make_unique<
28342838
InfoTy>(id)).first->get();
2835-
info->Extraction = mostSpecific(info->Extraction, mode_);
2839+
auto const minExtract = mode_ == TraversalMode::Regular ?
2840+
ExtractionMode::Regular : ExtractionMode::Dependency;
2841+
info->Extraction = mostSpecific(info->Extraction, minExtract);
28362842
}
28372843
MRDOCS_ASSERT(info->Kind == InfoTy::kind_id);
28382844
return {static_cast<InfoTy&>(*info), isNew};
@@ -2873,11 +2879,11 @@ upsert(DeclType* D)
28732879
// this time.
28742880
bool const previouslyExtractedAsDependency =
28752881
!isNew &&
2876-
mode_ != ExtractionMode::Dependency &&
2882+
mode_ != TraversalMode::Dependency &&
28772883
I.Extraction == ExtractionMode::Dependency;
28782884
if (previouslyExtractedAsDependency)
28792885
{
2880-
I.Extraction = mostSpecific(I.Extraction, mode_);
2886+
I.Extraction = mostSpecific(I.Extraction, ExtractionMode::Regular);
28812887
isNew = true;
28822888
}
28832889

src/lib/AST/ASTVisitor.hpp

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,17 +118,63 @@ class ASTVisitor
118118
*/
119119
std::unordered_map<const FileEntry*, FileInfo> files_;
120120

121-
/* The current extraction mode
121+
/* How we should traverse the current node
122+
*/
123+
enum TraversalMode {
124+
/* Only symbols that pass the filters will be extracted
125+
126+
Excluded symbols are not traversed. All other symbols
127+
are traversed and their appropriate ExtractionMode
128+
is determined.
129+
130+
Member of these symbols are also traversed.
131+
132+
*/
133+
Regular,
134+
135+
/* All symbols are extracted
136+
137+
Even excluded symbols are traversed. If a sy bol
138+
doesn't pass the filters, it is extracted as a
139+
dependency.
140+
141+
Members of these dependency symbols are not
142+
traversed.
143+
144+
This is used when an included symbol makes a
145+
reference to an excluded symbol.
146+
*/
147+
Dependency,
148+
149+
/* All symbols will be extracted and traversed
122150
123-
This defines the extraction mode assigned to
151+
This mode is used to extract all symbols, including
152+
those that are excluded by the filters. These
153+
excluded symbols are marked as dependencies.
154+
155+
However, members of these dependency symbols are
156+
also traversed.
157+
158+
This is used when an included record makes use
159+
of an excluded record as a base class.
160+
In this case, we also need information about the
161+
excluded base class members to populate the
162+
derived class.
163+
*/
164+
BaseClass
165+
};
166+
167+
/* The current traversal mode
168+
169+
This defines the traversal mode assigned to
124170
new Info types.
125171
126172
A symbol that passes the filters will be
127173
extracted as a regular symbol.
128174
129175
If a symbol also passes the see-below or
130176
implementation-defined filters, we
131-
change the current extraction mode
177+
change the current traversal mode
132178
accordingly so the symbol can be tagged.
133179
Members of this symbol types are not
134180
extracted.
@@ -139,7 +185,7 @@ class ASTVisitor
139185
when another symbol makes a reference
140186
to it.
141187
*/
142-
ExtractionMode mode_ = ExtractionMode::Regular;
188+
TraversalMode mode_ = Regular;
143189

144190
public:
145191
/** Constructor for ASTVisitor.
@@ -573,7 +619,13 @@ class ASTVisitor
573619
Decl const* D);
574620

575621
std::unique_ptr<TypeInfo>
576-
toTypeInfo(QualType qt);
622+
toTypeInfo(QualType qt, TraversalMode mode);
623+
624+
std::unique_ptr<TypeInfo>
625+
toTypeInfo(QualType qt)
626+
{
627+
return toTypeInfo(qt, TraversalMode::Dependency);
628+
}
577629

578630
std::unique_ptr<NameInfo>
579631
toNameInfo(

src/lib/AST/ClangHelpers.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,12 @@ isAllImplicit(Decl const* D)
334334
{
335335
return false;
336336
}
337+
else if (auto const* TSD = dynamic_cast<VarTemplateSpecializationDecl const*>(D);
338+
TSD &&
339+
TSD->isExplicitSpecialization())
340+
{
341+
return false;
342+
}
337343
auto const* P = getParent(D);
338344
return isAllImplicit(P);
339345
}

0 commit comments

Comments
 (0)