Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions docs/mrdocs.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,16 @@
"title": "Symbol patterns to exclude",
"type": "array"
},
"extract-all": {
"default": true,
"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.",
"enum": [
true,
false
],
"title": "Extract all symbols",
"type": "boolean"
},
"file-patterns": {
"default": [
"*.hpp",
Expand Down Expand Up @@ -439,6 +449,76 @@
],
"title": "Verbose output",
"type": "boolean"
},
"warn-as-error": {
"default": false,
"description": "When set to `true`, MrDocs treats warnings as errors and stops the generation of the documentation.",
"enum": [
true,
false
],
"title": "Treat warnings as errors",
"type": "boolean"
},
"warn-broken-ref": {
"default": true,
"description": "When set to `true`, MrDocs outputs a warning message if a reference in the documentation is broken.",
"enum": [
true,
false
],
"title": "Warn if a documentation reference is broken",
"type": "boolean"
},
"warn-if-doc-error": {
"default": true,
"description": "When set to `true`, MrDocs outputs a warning message if the documentation of a symbol has errors such as duplicate parameters and parameters that don't exist.",
"enum": [
true,
false
],
"title": "Warn if documentation has errors",
"type": "boolean"
},
"warn-if-undoc-enum-val": {
"default": true,
"description": "When set to `true`, MrDocs outputs a warning message if an enum value is not documented.",
"enum": [
true,
false
],
"title": "Warn if enum values are not documented",
"type": "boolean"
},
"warn-if-undocumented": {
"default": true,
"description": "When set to `true`, MrDocs outputs a warning message if a symbol that passes all filters is not documented.",
"enum": [
true,
false
],
"title": "Warn if symbols are not documented",
"type": "boolean"
},
"warn-no-paramdoc": {
"default": true,
"description": "When set to `true`, MrDocs outputs a warning message if a named function parameter is not documented.",
"enum": [
true,
false
],
"title": "Warn if parameters are not documented",
"type": "boolean"
},
"warnings": {
"default": true,
"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.",
"enum": [
true,
false
],
"title": "Enable warning messages",
"type": "boolean"
}
},
"required": [],
Expand Down
63 changes: 57 additions & 6 deletions src/lib/AST/ASTVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ void
ASTVisitor::
build()
{
// traverse the translation unit, only extracting
// Traverse the translation unit, only extracting
// declarations which satisfy all filter conditions.
// dependencies will be tracked, but not extracted
TranslationUnitDecl const* TU = context_.getTranslationUnitDecl();
Expand Down Expand Up @@ -3271,6 +3271,11 @@ Expected<
ASTVisitor::
upsert(DeclType const* D)
{
using R = std::conditional_t<
std::same_as<InfoTy, void>,
InfoTypeFor_t<DeclType>,
InfoTy>;

ExtractionMode const m = checkFilters(D);
if (m == ExtractionMode::Dependency)
{
Expand All @@ -3288,12 +3293,9 @@ upsert(DeclType const* D)
}

SymbolID const id = generateID(D);
MRDOCS_CHECK_MSG(id, "Failed to extract symbol ID");
MRDOCS_TRY(checkUndocumented<R>(id, D));

using R = std::conditional_t<
std::same_as<InfoTy, void>,
InfoTypeFor_t<DeclType>,
InfoTy>;
MRDOCS_CHECK_MSG(id, "Failed to extract symbol ID");
auto [I, isNew] = upsert<R>(id);

// Already populate the extraction mode
Expand All @@ -3306,4 +3308,53 @@ upsert(DeclType const* D)
return upsertResult<R>{std::ref(I), isNew};
}

template <
std::derived_from<Info> InfoTy,
std::derived_from<Decl> DeclTy>
Expected<void>
ASTVisitor::
checkUndocumented(
SymbolID const& id,
DeclTy const* D)
{
// If `extract-all` is enabled, we don't need to
// check for undocumented symbols
MRDOCS_CHECK_OR(!config_->extractAll, {});
// If the symbol is a namespace, the `extract-all`
// doesn't apply to it
MRDOCS_CHECK_OR((!std::same_as<InfoTy,NamespaceInfo>), {});
// If the symbol is not being extracted as a Regular
// symbol, we don't need to check for undocumented symbols
// These are expected to be potentially undocumented
MRDOCS_CHECK_OR(mode_ == Regular, {});
// Check if the symbol is documented, ensure this symbol is not in the set
// of undocumented symbols in this translation unit and return
// without an error if it is
if (D->getASTContext().getRawCommentForDeclNoCache(D))
{
if (config_->warnIfUndocumented)
{
auto const it = undocumented_.find(id);
undocumented_.erase(it);
}
return {};
}
// If the symbol is undocumented, check if we haven't seen a
// documented version before.
auto const it = info_.find(id);
if (it != info_.end() &&
it->get()->javadoc)
{
return {};
}
// If the symbol is undocumented, and we haven't seen a documented
// version before, store this symbol in the set of undocumented
// symbols we've seen so far in this translation unit.
if (config_->warnIfUndocumented)
{
undocumented_.insert({id, extractName(D)});
}
return Unexpected(Error("Undocumented"));
}

} // clang::mrdocs
44 changes: 44 additions & 0 deletions src/lib/AST/ASTVisitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,29 @@ class ASTVisitor
// An unordered set of all extracted Info declarations
InfoSet info_;

/* The symbols we would extract if they were documented

When `extract-all` is false, we only extract symbols
that are documented. If a symbol reappears in the
translation unit, we only extract the declaration
that's documented.

When `extract-all` is false and `warn-if-undocumented`
is true, we also warn if a symbol is not documented.
However, because a symbol can appear multiple times
in multiple translation units, we cannot be sure
a symbol is undocumented until we have processed
all translation units.

For this reason, this set stores the symbols that
are not documented but would otherwise have been
extracted as regular symbols in the current
translation unit. After symbols from all translation
units are merged, we will iterate these symbols
and warn if they are not documented.
*/
UndocumentedInfoSet undocumented_;

/* Struct to hold pre-processed file information.

This struct stores information about a file, including its full path,
Expand Down Expand Up @@ -288,6 +311,19 @@ class ASTVisitor
return info_;
}

/** Get the set of extracted Info declarations.

This function returns a reference to the set of Info
declarations that have been extracted by the ASTVisitor.

@return A reference to the InfoSet containing the extracted Info declarations.
*/
UndocumentedInfoSet&
undocumented()
{
return undocumented_;
}

private:
// =================================================
// AST Traversal
Expand Down Expand Up @@ -1156,6 +1192,14 @@ class ASTVisitor
InfoTypeFor_t<DeclType>,
InfoTy>>>
upsert(DeclType const* D);

template <
std::derived_from<Info> InfoTy,
std::derived_from<Decl> DeclTy>
Expected<void>
checkUndocumented(
SymbolID const& id,
DeclTy const* D);
};

} // clang::mrdocs
Expand Down
8 changes: 3 additions & 5 deletions src/lib/AST/ASTVisitorConsumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
#include "lib/AST/ASTVisitor.hpp"
#include "lib/Support/Path.hpp"

namespace clang {
namespace mrdocs {
namespace clang::mrdocs {

void
ASTVisitorConsumer::
Expand All @@ -31,8 +30,7 @@ HandleTranslationUnit(ASTContext& Context)
Context,
*sema_);
visitor.build();
ex_.report(std::move(visitor.results()), std::move(diags));
ex_.report(std::move(visitor.results()), std::move(diags), std::move(visitor.undocumented()));
}

} // mrdocs
} // clang
} // clang::mrdocs
Loading
Loading