Skip to content

Commit baa64ff

Browse files
committed
warn-if-undocumented option
#feat fix #758
1 parent 7681b72 commit baa64ff

File tree

12 files changed

+238
-29
lines changed

12 files changed

+238
-29
lines changed

docs/mrdocs.schema.json

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@
9393
},
9494
"extract-all": {
9595
"default": true,
96-
"description": "When set to `true`, MrDocs extracts all symbols from the source code, even if no documentation is provided. When set to `false`, it's still recommendable to provide file and symbol filters so that only the desired symbols are traversed by MrDocs.",
96+
"description": "When set to `true`, MrDocs extracts all symbols from the source code, even if no documentation is provided. MrDocs can only identify whether a symbol is ultimated documented after extracting information from all translation units. For this reason, when this option is set to `false`, it's still recommendable to provide file and symbol filters so that only the desired symbols are traversed and stored by MrDocs.",
9797
"enum": [
9898
true,
9999
false
@@ -450,6 +450,16 @@
450450
"title": "Verbose output",
451451
"type": "boolean"
452452
},
453+
"warn-if-undocumented": {
454+
"default": true,
455+
"description": "When set to `true`, MrDocs outputs a warning message if a symbol that passes all filters is not documented. This option is only effective when `extract-all` is set to `false`.",
456+
"enum": [
457+
true,
458+
false
459+
],
460+
"title": "Warn if symbols are not documented",
461+
"type": "boolean"
462+
},
453463
"warnings": {
454464
"default": true,
455465
"description": "When set to `true`, MrDocs outputs warning messages during the generation of the documentation. It is usually recommended to enable warnings while writing the documentation.",

src/lib/AST/ASTVisitor.cpp

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ void
7373
ASTVisitor::
7474
build()
7575
{
76-
// traverse the translation unit, only extracting
76+
// Traverse the translation unit, only extracting
7777
// declarations which satisfy all filter conditions.
7878
// dependencies will be tracked, but not extracted
7979
TranslationUnitDecl const* TU = context_.getTranslationUnitDecl();
@@ -3291,16 +3291,10 @@ upsert(DeclType const* D)
32913291
return Unexpected(Error("Explicit declaration in dependency mode"));
32923292
}
32933293
}
3294-
else if (
3295-
!InfoParent<R> &&
3296-
mode_ == Regular &&
3297-
!config_->extractAll &&
3298-
!D->getASTContext().getRawCommentForDeclNoCache(D))
3299-
{
3300-
return Unexpected(formatError("{}: Symbol is undocumented", extractName(D)));
3301-
}
33023294

33033295
SymbolID const id = generateID(D);
3296+
MRDOCS_TRY(checkUndocumented<R>(id, D));
3297+
33043298
MRDOCS_CHECK_MSG(id, "Failed to extract symbol ID");
33053299
auto [I, isNew] = upsert<R>(id);
33063300

@@ -3314,4 +3308,52 @@ upsert(DeclType const* D)
33143308
return upsertResult<R>{std::ref(I), isNew};
33153309
}
33163310

3311+
template <
3312+
std::derived_from<Info> InfoTy,
3313+
std::derived_from<Decl> DeclTy>
3314+
Expected<void>
3315+
ASTVisitor::
3316+
checkUndocumented(
3317+
SymbolID const& id,
3318+
DeclTy const* D)
3319+
{
3320+
// If `extract-all` is enabled, we don't need to
3321+
// check for undocumented symbols
3322+
MRDOCS_CHECK_OR(!config_->extractAll, {});
3323+
// If the symbol is a namespace, the `extract-all`
3324+
// doesn't apply to it
3325+
MRDOCS_CHECK_OR((!std::same_as<InfoTy,NamespaceInfo>), {});
3326+
// If the symbol is not being extracted as a Regular
3327+
// symbol, we don't need to check for undocumented symbols
3328+
// These are expected to be potentially undocumented
3329+
MRDOCS_CHECK_OR(mode_ == Regular, {});
3330+
// Check if the symbol is documented, ensure this symbol is not in the set
3331+
// of undocumented symbols in this translation unit and return
3332+
// without an error if it is
3333+
if (D->getASTContext().getRawCommentForDeclNoCache(D))
3334+
{
3335+
if (config_->warnIfUndocumented)
3336+
{
3337+
undocumented_.erase({id, extractName(D)});
3338+
}
3339+
return {};
3340+
}
3341+
// If the symbol is undocumented, check if we haven't seen a
3342+
// documented version before.
3343+
auto const it = info_.find(id);
3344+
if (it != info_.end() &&
3345+
it->get()->javadoc)
3346+
{
3347+
return {};
3348+
}
3349+
// If the symbol is undocumented, and we haven't seen a documented
3350+
// version before, store this symbol in the set of undocumented
3351+
// symbols we've seen so far in this translation unit.
3352+
if (config_->warnIfUndocumented)
3353+
{
3354+
undocumented_.insert({id, extractName(D)});
3355+
}
3356+
return Unexpected(Error("Undocumented"));
3357+
}
3358+
33173359
} // clang::mrdocs

src/lib/AST/ASTVisitor.hpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,29 @@ class ASTVisitor
7878
// An unordered set of all extracted Info declarations
7979
InfoSet info_;
8080

81+
/* The symbols we would extract if they were documented
82+
83+
When `extract-all` is false, we only extract symbols
84+
that are documented. If a symbol reappears in the
85+
translation unit, we only extract the declaration
86+
that's documented.
87+
88+
When `extract-all` is false and `warn-if-undocumented`
89+
is true, we also warn if a symbol is not documented.
90+
However, because a symbol can appear multiple times
91+
in multiple translation units, we cannot be sure
92+
a symbol is undocumented until we have processed
93+
all translation units.
94+
95+
For this reason, this set stores the symbols that
96+
are not documented but would otherwise have been
97+
extracted as regular symbols in the current
98+
translation unit. After symbols from all translation
99+
units are merged, we will iterate these symbols
100+
and warn if they are not documented.
101+
*/
102+
UndocumentedInfoSet undocumented_;
103+
81104
/* Struct to hold pre-processed file information.
82105
83106
This struct stores information about a file, including its full path,
@@ -288,6 +311,19 @@ class ASTVisitor
288311
return info_;
289312
}
290313

314+
/** Get the set of extracted Info declarations.
315+
316+
This function returns a reference to the set of Info
317+
declarations that have been extracted by the ASTVisitor.
318+
319+
@return A reference to the InfoSet containing the extracted Info declarations.
320+
*/
321+
UndocumentedInfoSet&
322+
undocumented()
323+
{
324+
return undocumented_;
325+
}
326+
291327
private:
292328
// =================================================
293329
// AST Traversal
@@ -1156,6 +1192,14 @@ class ASTVisitor
11561192
InfoTypeFor_t<DeclType>,
11571193
InfoTy>>>
11581194
upsert(DeclType const* D);
1195+
1196+
template <
1197+
std::derived_from<Info> InfoTy,
1198+
std::derived_from<Decl> DeclTy>
1199+
Expected<void>
1200+
checkUndocumented(
1201+
SymbolID const& id,
1202+
DeclTy const* D);
11591203
};
11601204

11611205
} // clang::mrdocs

src/lib/AST/ASTVisitorConsumer.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@
1515
#include "lib/AST/ASTVisitor.hpp"
1616
#include "lib/Support/Path.hpp"
1717

18-
namespace clang {
19-
namespace mrdocs {
18+
namespace clang::mrdocs {
2019

2120
void
2221
ASTVisitorConsumer::
@@ -31,8 +30,7 @@ HandleTranslationUnit(ASTContext& Context)
3130
Context,
3231
*sema_);
3332
visitor.build();
34-
ex_.report(std::move(visitor.results()), std::move(diags));
33+
ex_.report(std::move(visitor.results()), std::move(diags), std::move(visitor.undocumented()));
3534
}
3635

37-
} // mrdocs
38-
} // clang
36+
} // clang::mrdocs

src/lib/Lib/ConfigOptions.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@
181181
{
182182
"name": "extract-all",
183183
"brief": "Extract all symbols",
184-
"details": "When set to `true`, MrDocs extracts all symbols from the source code, even if no documentation is provided. When set to `false`, it's still recommendable to provide file and symbol filters so that only the desired symbols are traversed by MrDocs.",
184+
"details": "When set to `true`, MrDocs extracts all symbols from the source code, even if no documentation is provided. MrDocs can only identify whether a symbol is ultimated documented after extracting information from all translation units. For this reason, when this option is set to `false`, it's still recommendable to provide file and symbol filters so that only the desired symbols are traversed and stored by MrDocs.",
185185
"type": "bool",
186186
"default": true
187187
},
@@ -478,6 +478,13 @@
478478
"details": "When set to `true`, MrDocs outputs warning messages during the generation of the documentation. It is usually recommended to enable warnings while writing the documentation.",
479479
"type": "bool",
480480
"default": true
481+
},
482+
{
483+
"name": "warn-if-undocumented",
484+
"brief": "Warn if symbols are not documented",
485+
"details": "When set to `true`, MrDocs outputs a warning message if a symbol that passes all filters is not documented. This option is only effective when `extract-all` is set to `false`.",
486+
"type": "bool",
487+
"default": true
481488
}
482489
]
483490
},

src/lib/Lib/CorpusImpl.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,9 @@ build(
524524
}
525525

526526
MRDOCS_TRY(auto results, context.results());
527+
auto undocumented = context.undocumented();
527528
corpus->info_ = std::move(results);
529+
corpus->undocumented_ = std::move(undocumented);
528530

529531
report::info(
530532
"Extracted {} declarations in {}",
@@ -598,6 +600,12 @@ CorpusImpl::finalize()
598600
report::debug("Finalizing javadoc");
599601
JavadocFinalizer finalizer(*this);
600602
finalizer.build();
603+
604+
if (!config->extractAll && config->warnIfUndocumented)
605+
{
606+
finalizer.warnUndocumented();
607+
}
608+
undocumented_.clear();
601609
}
602610

603611

src/lib/Lib/CorpusImpl.hpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,16 @@
1616
#include "lib/Lib/ConfigImpl.hpp"
1717
#include "lib/Lib/Info.hpp"
1818
#include "lib/Support/Debug.hpp"
19-
#include <map>
20-
#include <mutex>
21-
#include <string>
2219
#include <clang/Tooling/CompilationDatabase.h>
2320
#include <mrdocs/ADT/UnorderedStringMap.hpp>
2421
#include <mrdocs/Corpus.hpp>
2522
#include <mrdocs/Metadata.hpp>
2623
#include <mrdocs/Platform.hpp>
2724
#include <mrdocs/Support/Error.hpp>
25+
#include <map>
26+
#include <mutex>
27+
#include <string>
28+
#include <set>
2829

2930
namespace clang::mrdocs {
3031

@@ -45,6 +46,9 @@ class CorpusImpl final : public Corpus
4546
// Info keyed on Symbol ID.
4647
InfoSet info_;
4748

49+
// Undocumented symbols
50+
UndocumentedInfoSet undocumented_;
51+
4852
// Lookup cache
4953
// The key represents the context symbol ID.
5054
// The value is another map from the name to the Info.

src/lib/Lib/ExecutionContext.cpp

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ void
5555
InfoExecutionContext::
5656
report(
5757
InfoSet&& results,
58-
Diagnostics&& diags)
58+
Diagnostics&& diags,
59+
UndocumentedInfoSet&& undocumented)
5960
{
6061
InfoSet info = std::move(results);
6162
// KRYSTIAN TODO: read stage will be required to
@@ -67,6 +68,7 @@ report(
6768
#endif
6869

6970
std::unique_lock<std::shared_mutex> write_lock(mutex_);
71+
7072
// Add all new Info to the existing set.
7173
info_.merge(info);
7274

@@ -80,6 +82,26 @@ report(
8082

8183
// Merge diagnostics and report any new messages.
8284
diags_.mergeAndReport(std::move(diags));
85+
86+
87+
88+
// Merge undocumented symbols and remove any symbols
89+
// from undocumented that we can find in info_ with
90+
// documentation from other translation units.
91+
undocumented_.merge(undocumented);
92+
for (auto it = undocumented_.begin(); it != undocumented_.end();)
93+
{
94+
auto infoIt = info_.find(it->first);
95+
if (infoIt != info_.end() &&
96+
infoIt->get()->javadoc)
97+
{
98+
it = undocumented_.erase(it);
99+
}
100+
else
101+
{
102+
++it;
103+
}
104+
}
83105
}
84106

85107
void
@@ -89,12 +111,19 @@ reportEnd(report::Level level)
89111
diags_.reportTotals(level);
90112
}
91113

92-
mrdocs::Expected<InfoSet>
114+
Expected<InfoSet>
93115
InfoExecutionContext::
94116
results()
95117
{
96118
return std::move(info_);
97119
}
98120

121+
UndocumentedInfoSet
122+
InfoExecutionContext::
123+
undocumented()
124+
{
125+
return std::move(undocumented_);
126+
}
127+
99128
} // mrdocs
100129
} // clang

0 commit comments

Comments
 (0)