From 3952f0977c70bb7b71fc86736a17c76b17470361 Mon Sep 17 00:00:00 2001 From: Gennaro Prota Date: Wed, 16 Sep 2026 12:39:40 +0200 Subject: [PATCH 1/8] fix: user errors do not invite a bug report Every error-level message in MrDocs showed the internal source location and contained an invite to file a bug report. A missing config file, for instance, produced that and, with `--warn-as-error`, so did every undocumented symbol. This commit rectifies the situation by emitting such text only for internal errors. Fixes #1116. --- include/mrdocs/Support/Report.hpp | 59 ++++++++++++++++++++++------ src/mrdocs/AST/ASTVisitor.cpp | 8 ++-- src/mrdocs/AST/ExtractDocComment.cpp | 6 +-- src/mrdocs/Support/ReportImpl.hpp | 18 ++------- tests/golden/TestMain.cpp | 2 +- tools/mrdocs/src/Main.cpp | 2 +- 6 files changed, 58 insertions(+), 37 deletions(-) diff --git a/include/mrdocs/Support/Report.hpp b/include/mrdocs/Support/Report.hpp index 127e28096df..2327ea4d1a5 100644 --- a/include/mrdocs/Support/Report.hpp +++ b/include/mrdocs/Support/Report.hpp @@ -103,11 +103,10 @@ Level getMinimumLevel() noexcept; /** If true, source location information will be - printed with warnings, errors, and fatal messages. + printed. - @param b true to enable source location - information, false to disable it. The default - value is true. + @param b true to enable the bug report details, + false to disable them. The default value is true. */ MRDOCS_DECL void @@ -133,8 +132,13 @@ print( trailing newline will be added to the message automatically. - @param loc The source location of the report. - If this value is null, no location is printed. + @param loc The source location a bug report + should carry. If this value is null, the message + is printed on its own, without the bug report + details. + + @param e The error the message reports, when + there is one. Only read when `loc` is not null. */ MRDOCS_DECL void @@ -179,38 +183,42 @@ struct Located column widths) from the public reporting API. */ namespace detail { +// `withBugDetails` says whether the message reports a MrDocs defect. Only +// then is the location where MrDocs raised it worth printing, along with +// the rest of what a bug report needs. A message about the user's input +// does not contain such info. template requires (!std::same_as, Error>) void log_impl( Level level, + bool withBugDetails, Located fs, Arg0&& arg0, Args&&... args) { std::string str = std::vformat(fs.value, std::make_format_args(arg0, args...)); - return print(level, str, &fs.where); + return print(level, str, withBugDetails ? &fs.where : nullptr); } template void log_impl( Level level, + bool withBugDetails, Located fs, Error const& e, Args&&... args) { - // When the message is an error, we send split - // the information relevant to the user from - // the information relevant for bug tracking - // so that users can understand the message. + // The reason is what went wrong; where MrDocs raised it belongs to the + // bug report details, so the message carries the reason alone. std::string str = std::vformat(fs.value, std::make_format_args(e.reason(), args...)); return print( level, str, - &fs.where, + withBugDetails ? &fs.where : nullptr, &e); } @@ -218,10 +226,11 @@ inline void log_impl( Level level, + bool withBugDetails, Located fs) { std::string str(fs.value); - return print(level, str, &fs.where); + return print(level, str, withBugDetails ? &fs.where : nullptr); } } @@ -246,6 +255,7 @@ log( { return detail::log_impl( level, + false, fs, std::forward(args)...); } @@ -328,6 +338,29 @@ fatal( return log(Level::fatal, format, std::forward(args)...); } +/** Emit an error that reports a defect in MrDocs itself. + + The message is followed by the version and the source location a bug + report needs. Use it where MrDocs reached a state it does not handle. + A mistake in the user's input is not a bug in MrDocs, so it goes + through the other reporting functions. + + @param format fmt-style format string. + @param args Arguments substituted into the format string. +*/ +template +void +bug( + Located format, + Args&&... args) +{ + return detail::log_impl( + Level::error, + true, + format, + std::forward(args)...); +} + } // mrdocs #endif diff --git a/src/mrdocs/AST/ASTVisitor.cpp b/src/mrdocs/AST/ASTVisitor.cpp index 1e9fc460597..f1bb11ab5a0 100644 --- a/src/mrdocs/AST/ASTVisitor.cpp +++ b/src/mrdocs/AST/ASTVisitor.cpp @@ -2221,7 +2221,7 @@ addMember( addMember(I.Members.Macros, *U); return; } - report::error("Cannot push {} of type {} into members of namespace {}", + report::bug("Cannot push {} of type {} into members of namespace {}", Member.Name, mrdocs::toString(Member.Kind), I.Name); @@ -2311,7 +2311,7 @@ addMember(RecordTranche& T, Symbol const& Member) addMember(T.Usings, *U); return; } - report::error("Cannot push {} of type {} into tranche", + report::bug("Cannot push {} of type {} into tranche", Member.Name, mrdocs::toString(Member.Kind)); } @@ -2325,7 +2325,7 @@ addMember(EnumSymbol& I, Symbol const& Member) const addMember(I.Constants, *U); return; } - report::error("Cannot push {} of type {} into members of enum {}", + report::bug("Cannot push {} of type {} into members of enum {}", Member.Name, mrdocs::toString(Member.Kind), I.Name); @@ -2340,7 +2340,7 @@ addMember(OverloadsSymbol& I, Symbol const& Member) const addMember(I.Members, Member); return; } - report::error("Cannot push {} of type {} into members of enum {}", + report::bug("Cannot push {} of type {} into members of enum {}", Member.Name, mrdocs::toString(Member.Kind), I.Name); diff --git a/src/mrdocs/AST/ExtractDocComment.cpp b/src/mrdocs/AST/ExtractDocComment.cpp index bb6c15609da..148e19d085c 100644 --- a/src/mrdocs/AST/ExtractDocComment.cpp +++ b/src/mrdocs/AST/ExtractDocComment.cpp @@ -200,7 +200,7 @@ convertDirection(clang::comments::ParamCommandPassDirection d) case D::InOut: return doc::ParamDirection::inout; } - report::error( + report::bug( "error: unsupported ParamCommandPassDirection <{}>", static_cast(d)); MRDOCS_UNREACHABLE(); @@ -219,7 +219,7 @@ convertCopydoc(unsigned id) case T::KCI_copydetails: return doc::Parts::description; default: - report::error("error: unsupported CommandTrait id <{}>", id); + report::bug("error: unsupported CommandTrait id <{}>", id); MRDOCS_UNREACHABLE(); } } @@ -1761,7 +1761,7 @@ class DocCommentVisitor case T::KCI_copybrief: case T::KCI_copydetails: case T::KCI_copydoc: - report::error( + report::bug( "error: inline command {} should be handled elsewhere", cmd->Name); MRDOCS_UNREACHABLE(); diff --git a/src/mrdocs/Support/ReportImpl.hpp b/src/mrdocs/Support/ReportImpl.hpp index 77404709327..3531afc5270 100644 --- a/src/mrdocs/Support/ReportImpl.hpp +++ b/src/mrdocs/Support/ReportImpl.hpp @@ -103,7 +103,9 @@ getLevel( /** Formatted reporting to a live stream. - A trailing newline will be added automatically. + A trailing newline will be added automatically. If a location is present, + the message will be considered to be for a MrDocs defect, and will contain + an invite to file a bug report. */ MRDOCS_DECL void @@ -113,20 +115,6 @@ call_impl( source_location const* loc, Error const* e = nullptr); -/** Formatted reporting to a live stream. - - A trailing newline will be added automatically. -*/ -inline void -call( - Level level, - std::function f, - source_location const& loc = - source_location::current()) -{ - call_impl(level, std::move(f), &loc); -} - } // report } // mrdocs diff --git a/tests/golden/TestMain.cpp b/tests/golden/TestMain.cpp index 0ae40eb8c4a..9cedbcd048c 100644 --- a/tests/golden/TestMain.cpp +++ b/tests/golden/TestMain.cpp @@ -142,7 +142,7 @@ static void reportUnhandledException( { namespace sys = llvm::sys; - report::error("Unhandled exception: {}\n", ex.what()); + report::bug("Unhandled exception: {}\n", ex.what()); sys::PrintStackTrace(llvm::errs()); } #endif diff --git a/tools/mrdocs/src/Main.cpp b/tools/mrdocs/src/Main.cpp index 4595c121ab6..1f01f96974a 100644 --- a/tools/mrdocs/src/Main.cpp +++ b/tools/mrdocs/src/Main.cpp @@ -447,7 +447,7 @@ reportUnhandledException( { namespace sys = llvm::sys; - report::fatal("Unhandled exception: {}\n", ex.what()); + report::bug("Unhandled exception: {}\n", ex.what()); sys::PrintStackTrace(llvm::errs()); } #endif From a3330b4443761bd917a891bf8de25c354e851c9c Mon Sep 17 00:00:00 2001 From: Gennaro Prota Date: Wed, 16 Sep 2026 12:42:00 +0200 Subject: [PATCH 2/8] fix: a quoted error message no longer contains source location info The places that quote one error message inside another one used `Error::message()`, which also contains an indication of the source location in which the problem was detected. For instance, a doc-comment warning came out as "HTML tag not followed by (src/mrdocs/AST/ExtractDocComment.cpp:774) at (6)". Those places quote the reason now, but not the source location. Only detected bugs show source location information now. --- src/mrdocs/AST/ExtractDocComment.cpp | 14 +++++++------- src/mrdocs/Engines/JavaScript.cpp | 2 +- src/mrdocs/Extensions/ExtensionRegistry.cpp | 2 +- src/mrdocs/Extensions/JsBinding.cpp | 2 +- src/mrdocs/Generators/hbs/Builder.cpp | 8 ++++---- src/mrdocs/Generators/script/ScriptGenerator.cpp | 4 ++-- tools/mrdocs/src/Main.cpp | 4 ++-- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/mrdocs/AST/ExtractDocComment.cpp b/src/mrdocs/AST/ExtractDocComment.cpp index 148e19d085c..7d2d8fece79 100644 --- a/src/mrdocs/AST/ExtractDocComment.cpp +++ b/src/mrdocs/AST/ExtractDocComment.cpp @@ -793,7 +793,7 @@ class DocCommentVisitor Expected cellExp = parseTableCell(sub); if (!cellExp) { - warnNear(s, cellExp.error().message()); + warnNear(s, cellExp.error().reason()); return; } row.Cells.push_back(std::move(*cellExp)); @@ -894,7 +894,7 @@ class DocCommentVisitor Expected rowExp = parseTableRow(sub); if (!rowExp) { - warnNear(s, rowExp.error().message()); + warnNear(s, rowExp.error().reason()); return; } // Skip rows whose cells all failed to parse: a row with @@ -1049,7 +1049,7 @@ class DocCommentVisitor Expected tbExp = parseTable(cur); if (!tbExp) { - warnNear(C, tbExp.error().message()); + warnNear(C, tbExp.error().reason()); return; } // A table with no rows (e.g., because every row's content @@ -1185,7 +1185,7 @@ class DocCommentVisitor // written; the rest of the phrase follows as ordinary text. if (isSupportedHTMLTag(C->getTagName())) { - warnOnce(filename, loc.getLine(), compsExp.error().message()); + warnOnce(filename, loc.getLine(), compsExp.error().reason()); } emplaceInline( C->hasTrailingNewline(), @@ -1210,7 +1210,7 @@ class DocCommentVisitor // problem in the user's doc comment, not in Mr.Docs: warn // with the location and keep the text instead of failing // the whole run with an internal-error banner. - warnOnce(filename, loc.getLine(), r.error().message()); + warnOnce(filename, loc.getLine(), r.error().reason()); emplaceInline( C->hasTrailingNewline(), ensureUTF8(std::move(comps.text))); @@ -1276,7 +1276,7 @@ class DocCommentVisitor auto srcAttr = getAttr("src"); if (!srcAttr) { - warnOnce(filename, loc.getLine(), srcAttr.error().message()); + warnOnce(filename, loc.getLine(), srcAttr.error().reason()); return; } std::string alt = getAttr("alt").value_or(std::string()); @@ -1360,7 +1360,7 @@ class DocCommentVisitor warnOnce( files::makePosixStyle(loc.getFilename()), loc.getLine(), - r.error().message()); + r.error().reason()); } else if (comps.tag == "em") { diff --git a/src/mrdocs/Engines/JavaScript.cpp b/src/mrdocs/Engines/JavaScript.cpp index 57ef8e371d2..ca44eddeb3a 100644 --- a/src/mrdocs/Engines/JavaScript.cpp +++ b/src/mrdocs/Engines/JavaScript.cpp @@ -305,7 +305,7 @@ invokeHelper(Value const& fn, dom::Array const& args) auto ret = fn.apply(callArgs); if (!ret) { - return Unexpected(dom::Error(std::string(ret.error().message()))); + return Unexpected(dom::Error(std::string(ret.error().reason()))); } return ret->getDom(); } diff --git a/src/mrdocs/Extensions/ExtensionRegistry.cpp b/src/mrdocs/Extensions/ExtensionRegistry.cpp index e6b7b498ec9..7bb820b3dc7 100644 --- a/src/mrdocs/Extensions/ExtensionRegistry.cpp +++ b/src/mrdocs/Extensions/ExtensionRegistry.cpp @@ -95,7 +95,7 @@ ExtensionRegistry::applyTransforms(Corpus& corpus, Config const& config) const { return Unexpected(formatError( "extension transform '{}': {}", - id, invoked.error().message())); + id, invoked.error().reason())); } } } diff --git a/src/mrdocs/Extensions/JsBinding.cpp b/src/mrdocs/Extensions/JsBinding.cpp index 4c7cb5522cd..3c7a5d33d2b 100644 --- a/src/mrdocs/Extensions/JsBinding.cpp +++ b/src/mrdocs/Extensions/JsBinding.cpp @@ -189,7 +189,7 @@ loadJsExtensions(std::string const& scriptPath, Config const& config) if (!ran.has_value()) { return Unexpected(formatError( - "extension '{}': {}", scriptPath, ran.error().message())); + "extension '{}': {}", scriptPath, ran.error().reason())); } if (loaded.transforms.empty() && loaded.generators.empty()) diff --git a/src/mrdocs/Generators/hbs/Builder.cpp b/src/mrdocs/Generators/hbs/Builder.cpp index a6d89884b2d..0e196a54a99 100644 --- a/src/mrdocs/Generators/hbs/Builder.cpp +++ b/src/mrdocs/Generators/hbs/Builder.cpp @@ -360,7 +360,7 @@ registerUserJsHelpers( { return Unexpected(formatError( "Error loading utility {}: {}", - utilPath, exp.error().message())); + utilPath, exp.error().reason())); } } @@ -417,7 +417,7 @@ registerUserLuaHelpers( { return Unexpected(formatError( "Error loading utility {}: {}", - utilPath, exp.error().message())); + utilPath, exp.error().reason())); } } @@ -680,7 +680,7 @@ operator()(std::ostream& os, T const& I) // Reuse the already-built context to avoid recomputing DOM data. if (auto exp = callTemplate(os, templateFile, ctx); !exp) { - return Unexpected(dom::Error(std::string(exp.error().message()))); + return Unexpected(dom::Error(std::string(exp.error().reason()))); } return {}; })); @@ -715,7 +715,7 @@ renderWrapped( ctx.set("contents", dom::makeInvocable([&](dom::Value const &) -> dom::Expected { if (auto exp = contentsCb(); !exp) { - return Unexpected(dom::Error(std::string(exp.error().message()))); + return Unexpected(dom::Error(std::string(exp.error().reason()))); } return {}; })); diff --git a/src/mrdocs/Generators/script/ScriptGenerator.cpp b/src/mrdocs/Generators/script/ScriptGenerator.cpp index f7c93349cd1..ba63cb1692f 100644 --- a/src/mrdocs/Generators/script/ScriptGenerator.cpp +++ b/src/mrdocs/Generators/script/ScriptGenerator.cpp @@ -129,7 +129,7 @@ buildOutputApi(OutputSink& sink) doAppend); !wrote) { - result = Unexpected(dom::Error(std::string(wrote.error().message()))); + result = Unexpected(dom::Error(std::string(wrote.error().reason()))); } else { @@ -212,7 +212,7 @@ build(Corpus const& corpus, Config const& config) const if (!invoked) { result = Unexpected(formatError( - "generator '{}': {}", id_, invoked.error().message())); + "generator '{}': {}", id_, invoked.error().reason())); } return result; } diff --git a/tools/mrdocs/src/Main.cpp b/tools/mrdocs/src/Main.cpp index 1f01f96974a..35a3b7a54e4 100644 --- a/tools/mrdocs/src/Main.cpp +++ b/tools/mrdocs/src/Main.cpp @@ -413,7 +413,7 @@ mrdocs_main(int argc, char const** argv) auto res = getReferenceDirectories(execPath); if (!res) { - report::fatal("Failed to determine reference directories: {}", res.error().message()); + report::fatal("Failed to determine reference directories: {}", res.error()); return EXIT_FAILURE; } auto dirs = *std::move(res); @@ -421,7 +421,7 @@ mrdocs_main(int argc, char const** argv) auto expConfigPath = getConfigPath(dirs, cl); if (!expConfigPath) { - report::fatal("Failed to determine config path: {}", expConfigPath.error().message()); + report::fatal("Failed to determine config path: {}", expConfigPath.error()); return EXIT_FAILURE; } auto configPath = *std::move(expConfigPath); From 1cc30695d03c52c92671e12a50acf69f8319f479 Mon Sep 17 00:00:00 2001 From: Gennaro Prota Date: Wed, 16 Sep 2026 12:55:44 +0200 Subject: [PATCH 3/8] fix: source-root defaults to the config file's directory `source-root`'s default value is the bare placeholder "", but the resolver only stripped the placeholder when it was followed by a '/'; so the "<...>" text survived verbatim into the path, meaning that every configuration which omitted `source-root` died with a "path does not exist" error. The fix is to treat an empty remainder as ".". A new unit test loads a minimal mrdocs.yml and checks that `source-root` comes back as that file's directory. --- src/mrdocs/Config.cpp | 4 +-- tests/unit/Config.cpp | 57 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 tests/unit/Config.cpp diff --git a/src/mrdocs/Config.cpp b/src/mrdocs/Config.cpp index d615109b48d..a1391f4dc0d 100644 --- a/src/mrdocs/Config.cpp +++ b/src/mrdocs/Config.cpp @@ -1119,9 +1119,7 @@ struct ConfigSchemaVisitor { MRDOCS_TRY( std::string_view const baseDir, getBaseDir(referenceDirKey, dirs, settings)); - if (pos != std::string::npos) { - value = value.substr(pos + 1); - } + value = pos != std::string::npos ? value.substr(pos + 1) : "."; return std::string(baseDir); } }; diff --git a/tests/unit/Config.cpp b/tests/unit/Config.cpp new file mode 100644 index 00000000000..d60f8477d8f --- /dev/null +++ b/tests/unit/Config.cpp @@ -0,0 +1,57 @@ +// +// Licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Copyright (c) 2026 Gennaro Prota (gennaro.prota@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#include +#include +#include +#include +#include +#include + +namespace mrdocs { + +struct ConfigTest +{ + void + testSourceRootDefaultsToConfigDir() + { + ScopedTempDirectory td("mrdocs-config"); + BOOST_TEST(td); + // `addons` must name a directory that exists, and nothing reads + // it here, so an empty one will do. + std::string const addonsDir = files::appendPath(td.path(), "addons"); + BOOST_TEST(files::createDirectory(addonsDir).has_value()); + std::string const configPath = + files::appendPath(td.path(), "mrdocs.yml"); + { + std::ofstream os(configPath, std::ios::binary | std::ios::trunc); + os << "addons: addons\n"; + } + + Config config; + ReferenceDirectories const dirs; + Expected const loaded = + Config::load_file(config, configPath, dirs); + BOOST_TEST(loaded.has_value()); + BOOST_TEST(config.sourceRoot == files::makePosixStyle(td.path())); + } + + void + run() + { + testSourceRootDefaultsToConfigDir(); + } +}; + +TEST_SUITE( + ConfigTest, + "clang.mrdocs.Config"); + +} // mrdocs From f1b6a5e2651ed03672353bbcfb51fe5cdcb8cafd Mon Sep 17 00:00:00 2001 From: Gennaro Prota Date: Wed, 16 Sep 2026 12:56:25 +0200 Subject: [PATCH 4/8] fix: error message for overload sets mentions overload sets, not enums The message was likely the result of copy/paste. --- src/mrdocs/AST/ASTVisitor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mrdocs/AST/ASTVisitor.cpp b/src/mrdocs/AST/ASTVisitor.cpp index f1bb11ab5a0..f0b969e24c2 100644 --- a/src/mrdocs/AST/ASTVisitor.cpp +++ b/src/mrdocs/AST/ASTVisitor.cpp @@ -2340,7 +2340,7 @@ addMember(OverloadsSymbol& I, Symbol const& Member) const addMember(I.Members, Member); return; } - report::bug("Cannot push {} of type {} into members of enum {}", + report::bug("Cannot push {} of type {} into members of overload set {}", Member.Name, mrdocs::toString(Member.Kind), I.Name); From c81ef4c4d010bf8bb8f1b30f49def0eb4687f6eb Mon Sep 17 00:00:00 2001 From: Gennaro Prota Date: Wed, 16 Sep 2026 14:22:48 +0200 Subject: [PATCH 5/8] fix: release builds report any exception that reaches the main function This was always the intent, but a few places tested `_NDEBUG` instead of the intended `NDEBUG`, in fact removing the code that reported the exception. --- tests/golden/TestMain.cpp | 4 ++-- tools/mrdocs/src/Main.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/golden/TestMain.cpp b/tests/golden/TestMain.cpp index 9cedbcd048c..64ed8a3295c 100644 --- a/tests/golden/TestMain.cpp +++ b/tests/golden/TestMain.cpp @@ -136,7 +136,7 @@ accepted and applied like the mrdocs tool. return EXIT_SUCCESS; } -#ifdef _NDEBUG +#ifdef NDEBUG static void reportUnhandledException( std::exception const& ex) { @@ -152,7 +152,7 @@ static void reportUnhandledException( int main(int argc, char const** argv) { -#ifndef _NDEBUG +#ifndef NDEBUG return mrdocs::test_main(argc, argv); #else try diff --git a/tools/mrdocs/src/Main.cpp b/tools/mrdocs/src/Main.cpp index 35a3b7a54e4..67af1688444 100644 --- a/tools/mrdocs/src/Main.cpp +++ b/tools/mrdocs/src/Main.cpp @@ -439,7 +439,7 @@ mrdocs_main(int argc, char const** argv) return EXIT_SUCCESS; } -#ifdef _NDEBUG +#ifdef NDEBUG static void reportUnhandledException( @@ -457,7 +457,7 @@ reportUnhandledException( int main(int argc, char const** argv) { -#ifndef _NDEBUG +#ifndef NDEBUG return mrdocs::mrdocs_main(argc, argv); #else try From f1feb52695b9688cf4bd035b636755adcccbc97c Mon Sep 17 00:00:00 2001 From: Gennaro Prota Date: Wed, 16 Sep 2026 15:01:50 +0200 Subject: [PATCH 6/8] refactor: remove the unused getLevel function The function was error-prone, in that it used a mapping that was one off the values of the enumerators. Also, nothing in the project used it, and it lived in a private header, so let it go. --- src/mrdocs/Support/Report.cpp | 14 -------------- src/mrdocs/Support/ReportImpl.hpp | 7 ------- 2 files changed, 21 deletions(-) diff --git a/src/mrdocs/Support/Report.cpp b/src/mrdocs/Support/Report.cpp index 22b340e8fee..8d12a82afb2 100644 --- a/src/mrdocs/Support/Report.cpp +++ b/src/mrdocs/Support/Report.cpp @@ -107,20 +107,6 @@ print( //------------------------------------------------ -Level -getLevel(unsigned level) noexcept -{ - switch(level) - { - case 0: return Level::debug; - case 1: return Level::info; - case 2: return Level::warn; - case 3: return Level::error; - default: - return Level::fatal; - } -} - constexpr llvm::raw_ostream::Colors getLevelColor(Level level) diff --git a/src/mrdocs/Support/ReportImpl.hpp b/src/mrdocs/Support/ReportImpl.hpp index 3531afc5270..8c802b1839d 100644 --- a/src/mrdocs/Support/ReportImpl.hpp +++ b/src/mrdocs/Support/ReportImpl.hpp @@ -94,13 +94,6 @@ class separator //------------------------------------------------ -/** Return a level from an integer. -*/ -MRDOCS_DECL -Level -getLevel( - unsigned level) noexcept; - /** Formatted reporting to a live stream. A trailing newline will be added automatically. If a location is present, From 3765317a5045392eacfcd3c897b16c4b5469d795 Mon Sep 17 00:00:00 2001 From: Gennaro Prota Date: Thu, 17 Sep 2026 17:47:05 +0200 Subject: [PATCH 7/8] docs: fix a typo in a doc-comment --- include/mrdocs/Support/Report.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mrdocs/Support/Report.hpp b/include/mrdocs/Support/Report.hpp index 2327ea4d1a5..f17285123c5 100644 --- a/include/mrdocs/Support/Report.hpp +++ b/include/mrdocs/Support/Report.hpp @@ -34,7 +34,7 @@ */ namespace mrdocs::report { -/** Severity levels attached to reported messags. +/** Severity levels attached to reported messages. */ enum class Level { From 8e92ad5de3bb3dcbd85f4e9941f14fd915dd6c22 Mon Sep 17 00:00:00 2001 From: Gennaro Prota Date: Fri, 18 Sep 2026 10:49:44 +0200 Subject: [PATCH 8/8] fix: the mapping warning is complete and consistent The format string lacked a placeholder for the error passed with it, so the reason was dropped and the message ended at "because ". The hand-written "Warning: " prefix is also removed, as no other warning carries one. "because" is removed because it may not read well depending on the `err` message. --- src/mrdocs/Corpus.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mrdocs/Corpus.cpp b/src/mrdocs/Corpus.cpp index b5c404eb50c..33f85a1df35 100644 --- a/src/mrdocs/Corpus.cpp +++ b/src/mrdocs/Corpus.cpp @@ -522,8 +522,7 @@ Corpus::build( { return Unexpected(err); } - report::warn( - "Warning: mapping failed because ", err); + report::warn("Mapping failed: {}", err); } MRDOCS_TRY(auto results, context.results());