diff --git a/include/mrdocs/Support/Report.hpp b/include/mrdocs/Support/Report.hpp index 127e28096df..4b2afc9c0c0 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 { @@ -102,17 +102,6 @@ Level */ getMinimumLevel() noexcept; -/** If true, source location information will be - printed with warnings, errors, and fatal messages. - - @param b true to enable source location - information, false to disable it. The default - value is true. -*/ -MRDOCS_DECL -void -setSourceLocationWarnings(bool b) noexcept; - /** Report a message to the console. @param text The message to print. A @@ -132,17 +121,12 @@ print( @param text The message to print. A 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. */ MRDOCS_DECL void print( Level level, - std::string const& text, - source_location const* loc = nullptr, - Error const* e = nullptr); + std::string const& text); /** Parameter type that adds a source location to a value. */ @@ -190,7 +174,7 @@ log_impl( { std::string str = std::vformat(fs.value, std::make_format_args(arg0, args...)); - return print(level, str, &fs.where); + return print(level, str); } template @@ -201,17 +185,9 @@ log_impl( 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. std::string str = std::vformat(fs.value, std::make_format_args(e.reason(), args...)); - return print( - level, - str, - &fs.where, - &e); + return print(level, str); } inline @@ -221,7 +197,7 @@ log_impl( Located fs) { std::string str(fs.value); - return print(level, str, &fs.where); + return print(level, str); } } diff --git a/src/mrdocs/AST/ASTVisitor.cpp b/src/mrdocs/AST/ASTVisitor.cpp index 1e9fc460597..da8d47bcbc4 100644 --- a/src/mrdocs/AST/ASTVisitor.cpp +++ b/src/mrdocs/AST/ASTVisitor.cpp @@ -2221,10 +2221,7 @@ addMember( addMember(I.Members.Macros, *U); return; } - report::error("Cannot push {} of type {} into members of namespace {}", - Member.Name, - mrdocs::toString(Member.Kind), - I.Name); + MRDOCS_UNREACHABLE(); } void @@ -2311,9 +2308,7 @@ addMember(RecordTranche& T, Symbol const& Member) addMember(T.Usings, *U); return; } - report::error("Cannot push {} of type {} into tranche", - Member.Name, - mrdocs::toString(Member.Kind)); + MRDOCS_UNREACHABLE(); } void @@ -2325,10 +2320,7 @@ addMember(EnumSymbol& I, Symbol const& Member) const addMember(I.Constants, *U); return; } - report::error("Cannot push {} of type {} into members of enum {}", - Member.Name, - mrdocs::toString(Member.Kind), - I.Name); + MRDOCS_UNREACHABLE(); } void @@ -2340,10 +2332,7 @@ addMember(OverloadsSymbol& I, Symbol const& Member) const addMember(I.Members, Member); return; } - report::error("Cannot push {} of type {} into members of enum {}", - Member.Name, - mrdocs::toString(Member.Kind), - I.Name); + MRDOCS_UNREACHABLE(); } void diff --git a/src/mrdocs/AST/ExtractDocComment.cpp b/src/mrdocs/AST/ExtractDocComment.cpp index bb6c15609da..d9dc92c26dd 100644 --- a/src/mrdocs/AST/ExtractDocComment.cpp +++ b/src/mrdocs/AST/ExtractDocComment.cpp @@ -200,9 +200,6 @@ convertDirection(clang::comments::ParamCommandPassDirection d) case D::InOut: return doc::ParamDirection::inout; } - report::error( - "error: unsupported ParamCommandPassDirection <{}>", - static_cast(d)); MRDOCS_UNREACHABLE(); } @@ -219,7 +216,6 @@ convertCopydoc(unsigned id) case T::KCI_copydetails: return doc::Parts::description; default: - report::error("error: unsupported CommandTrait id <{}>", id); MRDOCS_UNREACHABLE(); } } @@ -793,7 +789,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 +890,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 +1045,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 +1181,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 +1206,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 +1272,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 +1356,7 @@ class DocCommentVisitor warnOnce( files::makePosixStyle(loc.getFilename()), loc.getLine(), - r.error().message()); + r.error().reason()); } else if (comps.tag == "em") { @@ -1761,9 +1757,6 @@ class DocCommentVisitor case T::KCI_copybrief: case T::KCI_copydetails: case T::KCI_copydoc: - report::error( - "error: inline command {} should be handled elsewhere", - cmd->Name); MRDOCS_UNREACHABLE(); default: diff --git a/src/mrdocs/Config.cpp b/src/mrdocs/Config.cpp index d615109b48d..412a7f659e0 100644 --- a/src/mrdocs/Config.cpp +++ b/src/mrdocs/Config.cpp @@ -591,7 +591,8 @@ load_file( { auto ft = files::getFileType(configPath); MRDOCS_CHECK(ft, formatError( - "Config file does not exist: \"{}\"", ft.error(), configPath)); + "Cannot determine the type of config file \"{}\": {}", + configPath, ft.error().reason())); if (ft.value() == files::FileType::regular) { c.config = configPath; @@ -619,7 +620,8 @@ load_file( std::string configYaml; auto ft = files::getFileType(configPath); MRDOCS_CHECK(ft, formatError( - "Config file does not exist: \"{}\"", ft.error(), configPath)); + "Cannot determine the type of config file \"{}\": {}", + configPath, ft.error().reason())); if (ft.value() == files::FileType::regular) { c.config = configPath; @@ -1119,9 +1121,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/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()); 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/Engines/JavaScript/ValueBridge.ipp b/src/mrdocs/Engines/JavaScript/ValueBridge.ipp index 1e7ac652397..dc9c72c6e09 100644 --- a/src/mrdocs/Engines/JavaScript/ValueBridge.ipp +++ b/src/mrdocs/Engines/JavaScript/ValueBridge.ipp @@ -448,7 +448,7 @@ toDomValue(jerry_value_t v, std::shared_ptr const& impl) { auto err = makeError(ret); jerry_value_free(ret); - return Unexpected(dom::Error(std::string(err.message()))); + return Unexpected(dom::Error(std::string(err.reason()))); } auto dv = toDomValue(ret, impl); jerry_value_free(ret); diff --git a/src/mrdocs/Engines/Lua/registerHelper.ipp b/src/mrdocs/Engines/Lua/registerHelper.ipp index 3523102aa2d..d555018ab3d 100644 --- a/src/mrdocs/Engines/Lua/registerHelper.ipp +++ b/src/mrdocs/Engines/Lua/registerHelper.ipp @@ -155,7 +155,7 @@ invokeHelperRef( int const rc = lua_pcall(A, static_cast(narg), 1, 0); if (rc != LUA_OK) - return Unexpected(dom::Error(std::string(luaM_popError(A).message()))); + return Unexpected(dom::Error(std::string(luaM_popError(A).reason()))); dom::Value result = luaToDom(A, lua_gettop(A)); lua_pop(A, 1); @@ -184,7 +184,7 @@ invokeRef( int const rc = lua_pcall(A, static_cast(narg), 1, 0); if (rc != LUA_OK) - return Unexpected(dom::Error(std::string(luaM_popError(A).message()))); + return Unexpected(dom::Error(std::string(luaM_popError(A).reason()))); dom::Value result = luaToDom(A, lua_gettop(A)); lua_pop(A, 1); 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/src/mrdocs/Support/Error/Error.cpp b/src/mrdocs/Support/Error/Error.cpp index 2a8a4e5cc71..0445960cbc5 100644 --- a/src/mrdocs/Support/Error/Error.cpp +++ b/src/mrdocs/Support/Error/Error.cpp @@ -108,7 +108,7 @@ Error( for(auto const& err : errors) { reason_.append(" "); - reason_.append(err.message()); + reason_.append(err.reason()); reason_.push_back('\n'); } message_ = formatMessage(reason_, where_); diff --git a/src/mrdocs/Support/Report.cpp b/src/mrdocs/Support/Report.cpp index 22b340e8fee..854604e55aa 100644 --- a/src/mrdocs/Support/Report.cpp +++ b/src/mrdocs/Support/Report.cpp @@ -12,12 +12,10 @@ #include #include "ReportImpl.hpp" #include -#include #include #include #include #include -#include #include #ifdef _MSC_VER @@ -55,7 +53,6 @@ namespace report { static llvm::sys::Mutex mutex_; static Level level_ = Level::debug; -static bool sourceLocationWarnings_ = true; constinit Results results{}; @@ -71,12 +68,6 @@ getMinimumLevel() noexcept return level_; } -void -setSourceLocationWarnings(bool b) noexcept -{ - sourceLocationWarnings_ = b; -} - void print( std::string const& s) @@ -94,33 +85,17 @@ print( void print( Level level, - std::string const& text, - source_location const* loc, - Error const* e) + std::string const& text) { call_impl(level, [&](llvm::raw_ostream& os) { os << text; - }, loc, e); + }); } //------------------------------------------------ -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) @@ -148,42 +123,13 @@ getLevelColor(Level level) void call_impl( Level level, - std::function f, - source_location const* loc, - Error const* e) + std::function f) { std::string s; if(level >= level_) { llvm::raw_string_ostream os(s); f(os); - using LT = std::underlying_type_t; - if(sourceLocationWarnings_ && - loc && - static_cast(level) >= static_cast(Level::error)) - { - os << "\n\n"; - os << "An issue occurred during execution.\n"; - os << "If you believe this is a bug, please report it at https://github.com/cppalliance/mrdocs/issues\n" - "with the following details:\n"; - os << std::format(" MrDocs Release: {}\n", - project_release_with_build.empty() - ? std::string_view("unknown") - : project_release_with_build); - os << std::format(" MrDocs Version: {} (Build: {})\n", - project_version, project_version_build); - if (e) - { - os << std::format( - " Error Location: `{}` at line {}\n", - files::makeProjectRelative(e->location().file_name()), - e->location().line()); - } - os << std::format(" Reported From: `{}` at line {}\n", - files::makeProjectRelative(loc->file_name()), - loc->line()); - // VFALCO attach a stack trace for Level::fatal - } os << '\n'; } diff --git a/src/mrdocs/Support/ReportImpl.hpp b/src/mrdocs/Support/ReportImpl.hpp index 77404709327..2c6f9722b85 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. @@ -109,23 +102,7 @@ MRDOCS_DECL void call_impl( Level level, - std::function f, - 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); -} + std::function f); } // report diff --git a/src/mrdocs/Support/Yaml.cpp b/src/mrdocs/Support/Yaml.cpp index dcdf6fa30d8..331563011c4 100644 --- a/src/mrdocs/Support/Yaml.cpp +++ b/src/mrdocs/Support/Yaml.cpp @@ -41,8 +41,7 @@ void YamlReporter::diag(llvm::SMDiagnostic const &D, void *) { } report::call_impl( - level, [&](llvm::raw_ostream &os) { D.print("mrdocs", os, true, true); }, - nullptr); + level, [&](llvm::raw_ostream &os) { D.print("mrdocs", os, true, true); }); } } // mrdocs diff --git a/tests/golden/TestMain.cpp b/tests/golden/TestMain.cpp index 0ae40eb8c4a..f50e1db6bc5 100644 --- a/tests/golden/TestMain.cpp +++ b/tests/golden/TestMain.cpp @@ -121,7 +121,6 @@ accepted and applied like the mrdocs tool. auto ll = ConfigSchema::LogLevel::Info; ConfigSchema::fromString(testCliArgs.logLevel, ll); report::setMinimumLevel(static_cast(ll)); - report::setSourceLocationWarnings(false); if (!testCliArgs.inputs.empty()) { @@ -136,14 +135,11 @@ accepted and applied like the mrdocs tool. return EXIT_SUCCESS; } -#ifdef _NDEBUG +#ifdef NDEBUG static void reportUnhandledException( std::exception const& ex) { - namespace sys = llvm::sys; - report::error("Unhandled exception: {}\n", ex.what()); - sys::PrintStackTrace(llvm::errs()); } #endif @@ -152,7 +148,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/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 diff --git a/tools/mrdocs/src/Main.cpp b/tools/mrdocs/src/Main.cpp index 4595c121ab6..bbd01293d1b 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); @@ -439,16 +439,13 @@ mrdocs_main(int argc, char const** argv) return EXIT_SUCCESS; } -#ifdef _NDEBUG +#ifdef NDEBUG static void reportUnhandledException( std::exception const& ex) { - namespace sys = llvm::sys; - report::fatal("Unhandled exception: {}\n", ex.what()); - sys::PrintStackTrace(llvm::errs()); } #endif @@ -457,7 +454,7 @@ reportUnhandledException( int main(int argc, char const** argv) { -#ifndef _NDEBUG +#ifndef NDEBUG return mrdocs::mrdocs_main(argc, argv); #else try