From 3aecfc07914c17b0350068dd97af4909e0deb02b Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski Date: Mon, 17 Jul 2023 11:07:32 -0400 Subject: [PATCH] feat: safe names --- include/mrdox/Metadata/DomMetadata.hpp | 22 +- include/mrdox/Metadata/Function.hpp | 12 +- .../asciidoc/layouts/single-symbol.adoc.hbs | 1 + .../partials/declarator-before.adoc.hbs | 2 +- .../generator/asciidoc/partials/enum.adoc.hbs | 2 +- .../asciidoc/partials/namespace.adoc.hbs | 2 +- .../asciidoc/partials/record.adoc.hbs | 2 +- .../asciidoc/partials/template-arg.adoc.hbs | 2 +- .../generator/asciidoc/partials/xref.adoc.hbs | 2 +- .../html/partials/declarator-before.html.hbs | 4 +- src/lib/-HTML/Builder.cpp | 2 +- src/lib/-HTML/HTMLGenerator.cpp | 4 +- src/lib/-XML/XMLWriter.cpp | 6 +- src/lib/-adoc/AdocCorpus.cpp | 45 ++ src/lib/-adoc/AdocCorpus.hpp | 19 +- src/lib/-adoc/AdocGenerator.cpp | 22 +- src/lib/-adoc/Builder.cpp | 32 +- src/lib/-adoc/Builder.hpp | 12 +- src/lib/-adoc/MultiPageVisitor.cpp | 8 +- src/lib/-bitcode/BitcodeGenerator.cpp | 3 +- src/lib/Dom/Object.cpp | 2 +- src/lib/Lib/Corpus.cpp | 10 +- src/lib/Metadata/DomMetadata.cpp | 107 ++-- src/lib/Metadata/Function.cpp | 115 ++-- src/lib/Support/SafeNames.cpp | 513 ++++++++++-------- src/lib/Support/SafeNames.hpp | 35 +- src/tool/ToolMain.cpp | 2 +- 27 files changed, 568 insertions(+), 420 deletions(-) diff --git a/include/mrdox/Metadata/DomMetadata.hpp b/include/mrdox/Metadata/DomMetadata.hpp index 25fcdb29c..f05d89752 100644 --- a/include/mrdox/Metadata/DomMetadata.hpp +++ b/include/mrdox/Metadata/DomMetadata.hpp @@ -35,10 +35,6 @@ class MRDOX_DECL std::unique_ptr impl_; public: - /** The Corpus associated with the Dom. - */ - Corpus const& corpus; - /** Destructor. */ virtual ~DomCorpus(); @@ -51,26 +47,30 @@ class MRDOX_DECL @param corpus The Corpus whose metadata to use. */ - explicit DomCorpus(Corpus const& corpus); - /** Return a Dom object representing the given symbol. + /** Returns the Corpus associated with the Dom. + */ + Corpus const& getCorpus() const; - @return A value containing the symbol contents. + /** Construct a Dom object representing the given symbol. - @param id The id of the symbol to return. + This function is called internally when a `dom::Object` + representing a symbol needs to be constructed because + it was not found in the cache. */ + virtual dom::Object - get(SymbolID const& id) const; + construct(Info const& I) const; /** Return a Dom object representing the given symbol. @return A value containing the symbol contents. - @param I The metadata for the symbol. + @param id The id of the symbol to return. */ dom::Object - get(Info const& I) const; + get(SymbolID const& id) const; /** Return a Dom object representing the given symbol. diff --git a/include/mrdox/Metadata/Function.hpp b/include/mrdox/Metadata/Function.hpp index e3378b7b9..022c58eb7 100644 --- a/include/mrdox/Metadata/Function.hpp +++ b/include/mrdox/Metadata/Function.hpp @@ -28,11 +28,15 @@ namespace clang { namespace mrdox { /** Return the name of an operator as a string. + + @param include_keyword Whether the name + should be prefixed with the `operator` keyword. */ MRDOX_DECL std::string_view getOperatorName( - OperatorKind kind) noexcept; + OperatorKind kind, + bool include_keyword = false) noexcept; /** Return the short name of an operator as a string. */ @@ -42,11 +46,15 @@ getShortOperatorName( OperatorKind kind) noexcept; /** Return the safe name of an operator as a string. + + @param include_keyword Whether the name + should be prefixed with `operator_`. */ MRDOX_DECL std::string_view getSafeOperatorName( - OperatorKind kind) noexcept; + OperatorKind kind, + bool include_keyword = false) noexcept; /** Function classifications */ enum class FunctionClass diff --git a/share/mrdox/addons/generator/asciidoc/layouts/single-symbol.adoc.hbs b/share/mrdox/addons/generator/asciidoc/layouts/single-symbol.adoc.hbs index e3fbed5ce..d9620be2e 100644 --- a/share/mrdox/addons/generator/asciidoc/layouts/single-symbol.adoc.hbs +++ b/share/mrdox/addons/generator/asciidoc/layouts/single-symbol.adoc.hbs @@ -1,3 +1,4 @@ +{{#if relfileprefix}}:relfileprefix: {{relfileprefix}}{{/if}} {{#with symbol}} {{> (lookup . 'kind') symbol=.}} {{/with}} diff --git a/share/mrdox/addons/generator/asciidoc/partials/declarator-before.adoc.hbs b/share/mrdox/addons/generator/asciidoc/partials/declarator-before.adoc.hbs index af2239fa9..5b42e5581 100644 --- a/share/mrdox/addons/generator/asciidoc/partials/declarator-before.adoc.hbs +++ b/share/mrdox/addons/generator/asciidoc/partials/declarator-before.adoc.hbs @@ -18,5 +18,5 @@ {{#if cv-qualifiers~}} {{#if pointee-type}} {{cv-qualifiers}}{{else}}{{cv-qualifiers}} {{/if~}} {{/if~}} -{{#if id}}{{>xref .}}[{{name}}]{{else if name}}{{name}}{{/if~}} +{{#if symbol}}{{>xref symbol}}[{{name}}]{{else if name}}{{name}}{{/if~}} {{#if (eq kind "specialization")}}{{>template-args args=args}}{{/if}} \ No newline at end of file diff --git a/share/mrdox/addons/generator/asciidoc/partials/enum.adoc.hbs b/share/mrdox/addons/generator/asciidoc/partials/enum.adoc.hbs index 85736fc50..4bbc4da3a 100644 --- a/share/mrdox/addons/generator/asciidoc/partials/enum.adoc.hbs +++ b/share/mrdox/addons/generator/asciidoc/partials/enum.adoc.hbs @@ -1,6 +1,6 @@ {{!-- enum --}} [#{{symbol.id}}] -== {{symbol.name}} +== {{#if symbol.name}}Enum {{symbol.name}}{{else}}Unnamed enum{{/if}} {{symbol.doc.brief}} diff --git a/share/mrdox/addons/generator/asciidoc/partials/namespace.adoc.hbs b/share/mrdox/addons/generator/asciidoc/partials/namespace.adoc.hbs index cb4b79b9a..6afa5776f 100644 --- a/share/mrdox/addons/generator/asciidoc/partials/namespace.adoc.hbs +++ b/share/mrdox/addons/generator/asciidoc/partials/namespace.adoc.hbs @@ -1,6 +1,6 @@ {{!-- namespace --}} [#{{symbol.id}}] -== Namespace {{symbol.name}} +== {{#if symbol.name}}Namespace {{symbol.name}}{{else}}Unnamed namespace{{/if}} [,cols=2] |=== diff --git a/share/mrdox/addons/generator/asciidoc/partials/record.adoc.hbs b/share/mrdox/addons/generator/asciidoc/partials/record.adoc.hbs index a46c2e7bb..769f11098 100644 --- a/share/mrdox/addons/generator/asciidoc/partials/record.adoc.hbs +++ b/share/mrdox/addons/generator/asciidoc/partials/record.adoc.hbs @@ -1,6 +1,6 @@ {{!-- record --}} [#{{symbol.id}}] -== {{symbol.name}} +== {{#if symbol.name}}Class {{symbol.name}}{{else}}Unnamed class{{/if}} {{symbol.doc.brief}} diff --git a/share/mrdox/addons/generator/asciidoc/partials/template-arg.adoc.hbs b/share/mrdox/addons/generator/asciidoc/partials/template-arg.adoc.hbs index 720daaed0..6ba360c31 100644 --- a/share/mrdox/addons/generator/asciidoc/partials/template-arg.adoc.hbs +++ b/share/mrdox/addons/generator/asciidoc/partials/template-arg.adoc.hbs @@ -3,6 +3,6 @@ {{else if (eq kind "non-type")~}} {{~value~}} {{else if (eq kind "template")~}} -{{#if template}}{{>xref id=template}}[{{name~}}]{{else~}}{{name~}}{{/if~}} +{{#if template}}{{>xref template}}[{{name~}}]{{else~}}{{name~}}{{/if~}} {{/if~}} {{~#if is-pack}}...{{/if~}} diff --git a/share/mrdox/addons/generator/asciidoc/partials/xref.adoc.hbs b/share/mrdox/addons/generator/asciidoc/partials/xref.adoc.hbs index f9d09aae1..8b6fa5ba9 100644 --- a/share/mrdox/addons/generator/asciidoc/partials/xref.adoc.hbs +++ b/share/mrdox/addons/generator/asciidoc/partials/xref.adoc.hbs @@ -1 +1 @@ -xref:{{id}}{{#if (is_multipage)}}#{{/if}} \ No newline at end of file +xref:{{ref}}{{#if (is_multipage)}}#{{/if}} \ No newline at end of file diff --git a/share/mrdox/addons/generator/html/partials/declarator-before.html.hbs b/share/mrdox/addons/generator/html/partials/declarator-before.html.hbs index 16588b2dd..a36d02318 100644 --- a/share/mrdox/addons/generator/html/partials/declarator-before.html.hbs +++ b/share/mrdox/addons/generator/html/partials/declarator-before.html.hbs @@ -4,11 +4,11 @@ {{~else if (eq kind "tag")~}} {{#if cv-qualifiers}}{{cv-qualifiers}} {{/if~}} {{#if parent-type~}}{{>declarator parent-type decl-name="" decl-name-targs=""}}::{{/if~}} - {{#if id}}{{>xref id=id content=name}}{{else}}{{name~}}{{/if}} + {{#if symbol}}{{>xref symbol content=name}}{{else}}{{name~}}{{/if}} {{~else if (eq kind "specialization")~}} {{#if cv-qualifiers}}{{cv-qualifiers}} {{/if~}} {{#if parent-type~}}{{>declarator parent-type decl-name="" decl-name-targs=""}}::{{/if~}} - {{#if id}}{{>xref id=id content=name}}{{else}}{{name~}}{{/if}} + {{#if symbol}}{{>xref symbol content=name}}{{else}}{{name~}}{{/if}} {{~>template-args args=args~}} {{~else if (eq kind "lvalue-reference")~}} {{~>declarator-before pointee-type~}} diff --git a/src/lib/-HTML/Builder.cpp b/src/lib/-HTML/Builder.cpp index f4921df0d..73d012247 100644 --- a/src/lib/-HTML/Builder.cpp +++ b/src/lib/-HTML/Builder.cpp @@ -30,7 +30,7 @@ Builder( DomCorpus const& domCorpus, Options const& options) : domCorpus_(domCorpus) - , corpus_(domCorpus_.corpus) + , corpus_(domCorpus_.getCorpus()) , options_(options) { namespace fs = llvm::sys::fs; diff --git a/src/lib/-HTML/HTMLGenerator.cpp b/src/lib/-HTML/HTMLGenerator.cpp index 76f52c6c4..49995a05a 100644 --- a/src/lib/-HTML/HTMLGenerator.cpp +++ b/src/lib/-HTML/HTMLGenerator.cpp @@ -29,11 +29,11 @@ Expected> createExecutors( DomCorpus const& domCorpus) { - auto options = loadOptions(domCorpus.corpus); + auto options = loadOptions(domCorpus.getCorpus()); if(! options) return options.error(); - auto const& config = domCorpus.corpus.config; + auto const& config = domCorpus.getCorpus().config; auto& threadPool = config.threadPool(); ExecutorGroup group(threadPool); for(auto i = threadPool.getThreadCount(); i--;) diff --git a/src/lib/-XML/XMLWriter.cpp b/src/lib/-XML/XMLWriter.cpp index fdae9bba2..b464f465b 100644 --- a/src/lib/-XML/XMLWriter.cpp +++ b/src/lib/-XML/XMLWriter.cpp @@ -173,11 +173,11 @@ writeIndex() SafeNames names(corpus_); for(auto I : corpus_.index()) { - auto safe_name = names.get(I->id); + auto safe_name = names.getUnqualified(I->id); tags_.write("symbol", {}, { { "safe", safe_name }, { "name", corpus_.getFullyQualifiedName(*I, temp) }, - { "tag", getTagName(*I) }, + { "tag", toString(I->Kind) }, { I->id } }); } } @@ -186,7 +186,7 @@ writeIndex() for(auto I : corpus_.index()) tags_.write("symbol", {}, { { "name", corpus_.getFullyQualifiedName(*I, temp) }, - { "tag", getTagName(*I) }, + { "tag", toString(I->Kind) }, { I->id } }); } tags_.close("symbols"); diff --git a/src/lib/-adoc/AdocCorpus.cpp b/src/lib/-adoc/AdocCorpus.cpp index 4879cc9b9..e7e56783f 100644 --- a/src/lib/-adoc/AdocCorpus.cpp +++ b/src/lib/-adoc/AdocCorpus.cpp @@ -10,6 +10,7 @@ // #include "AdocCorpus.hpp" +#include "lib/Support/Radix.hpp" #include #include #include @@ -329,6 +330,50 @@ class DomJavadoc : public dom::LazyObjectImpl } // (anon) +dom::Object +AdocCorpus:: +construct(Info const& I) const +{ + // wraps a DomInfo with a lazy object which + // adds additional properties to the wrapped + // object once constructed. + struct AdocInfo : + public dom::LazyObjectImpl + { + Info const& I_; + AdocCorpus const& adocCorpus_; + + public: + AdocInfo( + Info const& I, + AdocCorpus const& adocCorpus) noexcept + : I_(I) + , adocCorpus_(adocCorpus) + { + } + + dom::Object construct() const override + { + auto obj = adocCorpus_.DomCorpus::construct(I_); + obj.set("ref", adocCorpus_.getXref(I_.id)); + return obj; + } + }; + return dom::newObject(I, *this); +} + +std::string +AdocCorpus:: +getXref(SymbolID const& id) const +{ + if(! safe_names) + // no safenames, use the SymbolID for references + return toBase16(id); + // use '/' as the seperator for multi-page, and '-' for single-page + return safe_names->getQualified(id, + getCorpus().config->multiPage ? '/' : '-'); +} + dom::Value AdocCorpus:: getJavadoc( diff --git a/src/lib/-adoc/AdocCorpus.hpp b/src/lib/-adoc/AdocCorpus.hpp index 048246738..4ebaa190e 100644 --- a/src/lib/-adoc/AdocCorpus.hpp +++ b/src/lib/-adoc/AdocCorpus.hpp @@ -12,7 +12,10 @@ #define MRDOX_LIB_ADOC_ADOCCORPUS_HPP #include +#include "lib/Support/SafeNames.hpp" +#include "Options.hpp" #include +#include namespace clang { namespace mrdox { @@ -21,13 +24,25 @@ namespace adoc { class AdocCorpus : public DomCorpus { public: - explicit + Options options; + std::optional safe_names; + AdocCorpus( - Corpus const& corpus) + Corpus const& corpus, + Options&& opts) : DomCorpus(corpus) + , options(std::move(opts)) { + if(options.safe_names) + safe_names.emplace(corpus); } + dom::Object + construct(Info const& I) const override; + + std::string + getXref(SymbolID const& id) const; + dom::Value getJavadoc( Javadoc const& jd) const override; diff --git a/src/lib/-adoc/AdocGenerator.cpp b/src/lib/-adoc/AdocGenerator.cpp index a2837e694..a608cfbe7 100644 --- a/src/lib/-adoc/AdocGenerator.cpp +++ b/src/lib/-adoc/AdocGenerator.cpp @@ -27,20 +27,16 @@ namespace adoc { Expected> createExecutors( - DomCorpus const& domCorpus) + AdocCorpus const& adocCorpus) { - auto options = loadOptions(domCorpus.corpus); - if(! options) - return options.error(); - - auto const& config = domCorpus.corpus.config; + auto const& config = adocCorpus.getCorpus().config; auto& threadPool = config.threadPool(); ExecutorGroup group(threadPool); for(auto i = threadPool.getThreadCount(); i--;) { try { - group.emplace(domCorpus, *options); + group.emplace(adocCorpus); } catch(Exception const& ex) { @@ -65,7 +61,11 @@ build( if(! corpus.config->multiPage) return Generator::build(outputPath, corpus); - AdocCorpus domCorpus(corpus); + auto options = loadOptions(corpus); + if(! options) + return options.error(); + + AdocCorpus domCorpus(corpus, options.release()); auto ex = createExecutors(domCorpus); if(! ex) return ex.error(); @@ -84,7 +84,11 @@ buildOne( std::ostream& os, Corpus const& corpus) const { - AdocCorpus domCorpus(corpus); + auto options = loadOptions(corpus); + if(! options) + return options.error(); + + AdocCorpus domCorpus(corpus, options.release()); auto ex = createExecutors(domCorpus); if(! ex) return ex.error(); diff --git a/src/lib/-adoc/Builder.cpp b/src/lib/-adoc/Builder.cpp index e1529c6c6..76e404823 100644 --- a/src/lib/-adoc/Builder.cpp +++ b/src/lib/-adoc/Builder.cpp @@ -27,16 +27,13 @@ namespace adoc { Builder:: Builder( - DomCorpus const& domCorpus, - Options const& options) - : domCorpus_(domCorpus) - , corpus_(domCorpus_.corpus) - , options_(options) + AdocCorpus const& corpus) + : domCorpus(corpus) { namespace fs = llvm::sys::fs; namespace path = llvm::sys::path; - Config const& config = corpus_.config; + Config const& config = domCorpus.getCorpus().config; js::Scope scope(ctx_); @@ -152,7 +149,7 @@ callTemplate( std::string_view name, dom::Value const& context) { - Config const& config = corpus_.config; + Config const& config = domCorpus.getCorpus().config; js::Scope scope(ctx_); auto Handlebars = scope.getGlobal("Handlebars"); @@ -195,11 +192,22 @@ renderSinglePageFooter() dom::Value Builder:: createContext( - SymbolID const& id) + Info const& I) { - return dom::Object({ - { "symbol", domCorpus_.get(id) } - }); + dom::Object::storage_type props; + props.emplace_back("symbol", domCorpus.get(I.id)); + std::string rel_prefix; + if(domCorpus.options.safe_names && + domCorpus.getCorpus().config->multiPage && + ! I.Namespace.empty()) + { + auto depth = I.Namespace.size() - 1; + rel_prefix.reserve(depth * 3); + while(depth--) + rel_prefix.append("../"); + } + props.emplace_back("relfileprefix", std::move(rel_prefix)); + return dom::Object(std::move(props)); } template @@ -209,7 +217,7 @@ operator()(T const& I) { return callTemplate( "single-symbol.adoc.hbs", - createContext(I.id)); + createContext(I)); } #define DEFINE(T) template Expected \ diff --git a/src/lib/-adoc/Builder.hpp b/src/lib/-adoc/Builder.hpp index 345ccfe43..833ce5c16 100644 --- a/src/lib/-adoc/Builder.hpp +++ b/src/lib/-adoc/Builder.hpp @@ -12,6 +12,7 @@ #define MRDOX_LIB_ADOC_BUILDER_HPP #include "Options.hpp" +#include "AdocCorpus.hpp" #include "lib/Support/Radix.hpp" #include #include @@ -31,17 +32,16 @@ namespace adoc { */ class Builder { - DomCorpus const& domCorpus_; - Corpus const& corpus_; - Options options_; js::Context ctx_; public: + AdocCorpus const& domCorpus; + + explicit Builder( - DomCorpus const& domCorpus, - Options const& options); + AdocCorpus const& corpus); - dom::Value createContext(SymbolID const& id); + dom::Value createContext(Info const& I); Expected callTemplate( diff --git a/src/lib/-adoc/MultiPageVisitor.cpp b/src/lib/-adoc/MultiPageVisitor.cpp index 6648c6196..4110c0699 100644 --- a/src/lib/-adoc/MultiPageVisitor.cpp +++ b/src/lib/-adoc/MultiPageVisitor.cpp @@ -38,8 +38,14 @@ renderPage( { auto pageText = builder(I).value(); + std::string fileName = files::appendPath( - outputPath_, toBase16(I.id) + ".adoc"); + outputPath_, builder.domCorpus.getXref(I.id) + ".adoc"); + + std::string dir = files::getParentDir(fileName); + if(auto err = files::createDirectory(dir)) + err.Throw(); + std::ofstream os; try { diff --git a/src/lib/-bitcode/BitcodeGenerator.cpp b/src/lib/-bitcode/BitcodeGenerator.cpp index d0a4f0362..0939745e9 100644 --- a/src/lib/-bitcode/BitcodeGenerator.cpp +++ b/src/lib/-bitcode/BitcodeGenerator.cpp @@ -59,8 +59,7 @@ class MultiFileBuilder [&] { llvm::SmallString<512> filePath(outputPath_); - llvm::StringRef name = names_.get(I.id); - path::append(filePath, name); + path::append(filePath, names_.getUnqualified(I.id)); filePath.append(".bc"); std::error_code ec; llvm::raw_fd_ostream os(filePath, ec, fs::CD_CreateAlways); diff --git a/src/lib/Dom/Object.cpp b/src/lib/Dom/Object.cpp index 98ec3c587..61f8eaf9a 100644 --- a/src/lib/Dom/Object.cpp +++ b/src/lib/Dom/Object.cpp @@ -220,7 +220,7 @@ void LazyObjectImpl:: set(String key, Value value) { - obj().set(std::move(key), value); + return obj().set(std::move(key), std::move(value)); } } // dom diff --git a/src/lib/Lib/Corpus.cpp b/src/lib/Lib/Corpus.cpp index 7f4e60b64..ebc4a1fdc 100644 --- a/src/lib/Lib/Corpus.cpp +++ b/src/lib/Lib/Corpus.cpp @@ -13,6 +13,7 @@ #include #include #include +#include namespace clang { namespace mrdox { @@ -50,7 +51,14 @@ getFullyQualifiedName( std::string& temp) const { temp.clear(); - for(auto const& ns_id : llvm::reverse(I.Namespace)) + if(I.id == SymbolID::zero) + return temp; + + MRDOX_ASSERT(! I.Namespace.empty()); + MRDOX_ASSERT(I.Namespace.back() == SymbolID::zero); + for(auto const& ns_id : I.Namespace | + std::views::reverse | + std::views::drop(1)) { if(const Info* ns = find(ns_id)) temp.append(ns->Name.data(), ns->Name.size()); diff --git a/src/lib/Metadata/DomMetadata.cpp b/src/lib/Metadata/DomMetadata.cpp index fbc8a4b2d..90cadd3f2 100644 --- a/src/lib/Metadata/DomMetadata.cpp +++ b/src/lib/Metadata/DomMetadata.cpp @@ -10,6 +10,7 @@ // #include "lib/Support/Radix.hpp" +#include "lib/Support/SafeNames.hpp" #include #include #include @@ -292,11 +293,8 @@ domCreate( { entries.emplace_back("name", t.Name); - // KRYSTIAN NOTE: hack for missing SymbolIDs - if(t.Template != SymbolID::zero && - domCorpus.corpus.find(t.Template)) - entries.emplace_back("template", - toBase16(t.Template)); + entries.emplace_back("template", + domCorpus.getOptional(t.Template)); } }); return dom::Object(std::move(entries)); @@ -376,11 +374,7 @@ domCreate( entries.emplace_back("name", t.Name); if constexpr(requires { t.id; }) - { - // VFALCO hack for missing symbols? - if(t.id != SymbolID::zero && domCorpus.corpus.find(t.id)) - entries.emplace_back("id", toBase16(t.id)); - } + entries.emplace_back("symbol", domCorpus.getOptional(t.id)); if constexpr(T::isSpecialization()) entries.emplace_back("args", @@ -534,7 +528,7 @@ class DomTrancheArray : public dom::ArrayImpl dom::Value get(std::size_t i) const override { MRDOX_ASSERT(i < list_.size()); - return domCorpus_.get(*list_[i]); + return domCorpus_.get(list_[i]->id); } }; @@ -594,7 +588,7 @@ class DomInterface : public dom::LazyObjectImpl dom::Object construct() const override { - sp_ = std::make_shared(makeInterface(I_, domCorpus_.corpus)); + sp_ = std::make_shared(makeInterface(I_, domCorpus_.getCorpus())); return dom::Object({ { "public", dom::newObject(sp_->Public, sp_, domCorpus_) }, { "protected", dom::newObject(sp_->Protected, sp_, domCorpus_) }, @@ -787,73 +781,56 @@ DomInfo::construct() const class DomCorpus::Impl { - struct value_type - { - std::weak_ptr weak; - std::shared_ptr strong; - }; + using value_type = std::weak_ptr; DomCorpus const& domCorpus_; Corpus const& corpus_; - llvm::StringMap infoCache_; + std::unordered_map cache_; std::mutex mutex_; public: Impl( DomCorpus const& domCorpus, - Corpus const& corpus) noexcept + Corpus const& corpus) : domCorpus_(domCorpus) , corpus_(corpus) { } - dom::Object - create(SymbolID const& id) + Corpus const& + getCorpus() const { - // VFALCO Hack to deal with symbol IDs - // being emitted without the corresponding data. - auto I = corpus_.find(id); - if(I) - { - return visit(*I, - [&](T const& I) - { - return dom::newObject>(I, domCorpus_); - }); - } - return {}; // VFALCO Hack + return corpus_; } dom::Object - get(Info const& I) + create(Info const& I) { - return visit(I, - [&](T const& I) - { - return dom::newObject>(I, domCorpus_); - }); + return domCorpus_.construct(I); } dom::Object get(SymbolID const& id) { + // VFALCO Hack to deal with symbol IDs + // being emitted without the corresponding data. + const Info* I = corpus_.find(id); + if(! I) + return {}; // VFALCO Hack + std::lock_guard lock(mutex_); - auto it = infoCache_.find(llvm::StringRef(id)); - if(it == infoCache_.end()) + auto it = cache_.find(id); + if(it == cache_.end()) { - auto obj = create(id); - auto impl = obj.impl(); - infoCache_.insert( - { llvm::StringRef(id), { impl, nullptr } }); + auto obj = create(*I); + cache_.insert( + { id, obj.impl() }); return obj; } - if(it->second.strong) - return dom::Object(it->second.strong); - auto sp = it->second.weak.lock(); - if(sp) + if(auto sp = it->second.lock()) return dom::Object(sp); - auto obj = create(id); - it->second.weak = obj.impl(); + auto obj = create(*I); + it->second = obj.impl(); return obj; } }; @@ -862,25 +839,35 @@ DomCorpus:: ~DomCorpus() = default; DomCorpus:: -DomCorpus( - Corpus const& corpus_) - : impl_(std::make_unique(*this, corpus_)) - , corpus(corpus_) +DomCorpus(Corpus const& corpus_) + : impl_(std::make_unique( + *this, corpus_)) +{ +} + +Corpus const& +DomCorpus:: +getCorpus() const { + return impl_->getCorpus(); } dom::Object DomCorpus:: -get(SymbolID const& id) const +construct(Info const& I) const { - return impl_->get(id); + return visit(I, + [&](T const& I) + { + return dom::newObject>(I, *this); + }); } dom::Object DomCorpus:: -get(Info const& I) const +get(SymbolID const& id) const { - return impl_->get(I); + return impl_->get(id); } dom::Value @@ -889,7 +876,7 @@ getOptional(SymbolID const& id) const { if(id == SymbolID::zero) return nullptr; - return impl_->get(id); + return get(id); } dom::Value diff --git a/src/lib/Metadata/Function.cpp b/src/lib/Metadata/Function.cpp index 8dcf527fa..e79e21c00 100644 --- a/src/lib/Metadata/Function.cpp +++ b/src/lib/Metadata/Function.cpp @@ -36,52 +36,52 @@ static constinit Item const Table[] = { ::= ad # & (unary) ::= de # * (unary) */ - { "", "", "", OperatorKind::None }, - { "new", "new", "nw", OperatorKind::New }, - { "delete", "del", "dl", OperatorKind::Delete }, - { "new[]", "arr_new", "na", OperatorKind::ArrayNew }, - { "delete[]", "arr_del", "da", OperatorKind::ArrayDelete }, - { "+", "plus", "pl", OperatorKind::Plus }, - { "-", "minus", "mi", OperatorKind::Minus }, - { "*", "star", "ml", OperatorKind::Star }, - { "/", "slash", "dv", OperatorKind::Slash }, - { "%", "mod", "rm", OperatorKind::Percent }, - { "^", "xor", "eo", OperatorKind::Caret }, - { "&", "bitand", "an", OperatorKind::Amp }, - { "|", "bitor", "or", OperatorKind::Pipe }, - { "~", "bitnot", "co", OperatorKind::Tilde }, - { "!", "not", "nt", OperatorKind::Exclaim }, - { "=", "assign", "as", OperatorKind::Equal }, - { "<", "lt", "lt", OperatorKind::Less }, - { ">", "gt", "gt", OperatorKind::Greater }, - { "+=", "plus_eq", "ple", OperatorKind::PlusEqual }, - { "-=", "minus_eq", "mie", OperatorKind::MinusEqual }, - { "*=", "star_eq", "mle", OperatorKind::StarEqual }, - { "/=", "slash_eq", "dve", OperatorKind::SlashEqual }, - { "%=", "mod_eq", "rme", OperatorKind::PercentEqual }, - { "^=", "xor_eq", "eoe", OperatorKind::CaretEqual }, - { "&=", "and_eq", "ane", OperatorKind::AmpEqual }, - { "|=", "or_eq", "ore", OperatorKind::PipeEqual }, - { "<<", "lshift", "ls", OperatorKind::LessLess }, - { ">>", "rshift", "rs", OperatorKind::GreaterGreater }, - { "<<=", "lshift_eq", "lse", OperatorKind::LessLessEqual }, - { ">>=", "rshift_eq", "rse", OperatorKind::GreaterGreaterEqual }, - { "==", "eq", "eq", OperatorKind::EqualEqual }, - { "!=", "not_eq", "ne", OperatorKind::ExclaimEqual }, - { "<=", "le", "le", OperatorKind::LessEqual }, - { ">=", "ge", "ge", OperatorKind::GreaterEqual }, - { "<=>", "3way", "ss", OperatorKind::Spaceship }, - { "&&", "and", "aa", OperatorKind::AmpAmp }, - { "||", "or", "oo", OperatorKind::PipePipe }, - { "++", "inc", "pp", OperatorKind::PlusPlus }, - { "--", "dec", "mm", OperatorKind::MinusMinus }, - { ",", "comma", "cm", OperatorKind::Comma }, - { "->*", "ptrmem", "pm", OperatorKind::ArrowStar }, - { "->", "ptr", "pt", OperatorKind::Arrow }, - { "()", "call", "cl", OperatorKind::Call }, - { "[]", "subs", "ix", OperatorKind::Subscript }, - { "?", "ternary", "qu", OperatorKind::Conditional }, - { "co_await", "coawait", "ca", OperatorKind::Coawait }, + { "", "", "", OperatorKind::None }, + { "operator new", "operator_new", "nw", OperatorKind::New }, + { "operator delete", "operator_del", "dl", OperatorKind::Delete }, + { "operator new[]", "operator_arr_new", "na", OperatorKind::ArrayNew }, + { "operator delete[]", "operator_arr_del", "da", OperatorKind::ArrayDelete }, + { "operator+", "operator_plus", "pl", OperatorKind::Plus }, + { "operator-", "operator_minus", "mi", OperatorKind::Minus }, + { "operator*", "operator_star", "ml", OperatorKind::Star }, + { "operator/", "operator_slash", "dv", OperatorKind::Slash }, + { "operator%", "operator_mod", "rm", OperatorKind::Percent }, + { "operator^", "operator_xor", "eo", OperatorKind::Caret }, + { "operator&", "operator_bitand", "an", OperatorKind::Amp }, + { "operator|", "operator_bitor", "or", OperatorKind::Pipe }, + { "operator~", "operator_bitnot", "co", OperatorKind::Tilde }, + { "operator!", "operator_not", "nt", OperatorKind::Exclaim }, + { "operator=", "operator_assign", "as", OperatorKind::Equal }, + { "operator<", "operator_lt", "lt", OperatorKind::Less }, + { "operator>", "operator_gt", "gt", OperatorKind::Greater }, + { "operator+=", "operator_plus_eq", "ple", OperatorKind::PlusEqual }, + { "operator-=", "operator_minus_eq", "mie", OperatorKind::MinusEqual }, + { "operator*=", "operator_star_eq", "mle", OperatorKind::StarEqual }, + { "operator/=", "operator_slash_eq", "dve", OperatorKind::SlashEqual }, + { "operator%=", "operator_mod_eq", "rme", OperatorKind::PercentEqual }, + { "operator^=", "operator_xor_eq", "eoe", OperatorKind::CaretEqual }, + { "operator&=", "operator_and_eq", "ane", OperatorKind::AmpEqual }, + { "operator|=", "operator_or_eq", "ore", OperatorKind::PipeEqual }, + { "operator<<", "operator_lshift", "ls", OperatorKind::LessLess }, + { "operator>>", "operator_rshift", "rs", OperatorKind::GreaterGreater }, + { "operator<<=", "operator_lshift_eq", "lse", OperatorKind::LessLessEqual }, + { "operator>>=", "operator_rshift_eq", "rse", OperatorKind::GreaterGreaterEqual }, + { "operator==", "operator_eq", "eq", OperatorKind::EqualEqual }, + { "operator!=", "operator_not_eq", "ne", OperatorKind::ExclaimEqual }, + { "operator<=", "operator_le", "le", OperatorKind::LessEqual }, + { "operator>=", "operator_ge", "ge", OperatorKind::GreaterEqual }, + { "operator<=>", "operator_3way", "ss", OperatorKind::Spaceship }, + { "operator&&", "operator_and", "aa", OperatorKind::AmpAmp }, + { "operator||", "operator_or", "oo", OperatorKind::PipePipe }, + { "operator++", "operator_inc", "pp", OperatorKind::PlusPlus }, + { "operator--", "operator_dec", "mm", OperatorKind::MinusMinus }, + { "operator,", "operator_comma", "cm", OperatorKind::Comma }, + { "operator->*", "operator_ptrmem", "pm", OperatorKind::ArrowStar }, + { "operator->", "operator_ptr", "pt", OperatorKind::Arrow }, + { "operator()", "operator_call", "cl", OperatorKind::Call }, + { "operator[]", "operator_subs", "ix", OperatorKind::Subscript }, + { "operator?", "operator_ternary", "qu", OperatorKind::Conditional }, + { "operator co_await", "operator_coawait", "ca", OperatorKind::Coawait }, // { "~", "dt", FunctionKind::Destructor }, // { "", "ct", FunctionKind::Constructor }, // { "", "cv", FunctionKind::Conversion } @@ -92,10 +92,20 @@ static constinit Item const Table[] = { std::string_view getOperatorName( - OperatorKind kind) noexcept + OperatorKind kind, + bool include_keyword) noexcept { MRDOX_ASSERT(Table[to_underlying(kind)].kind == kind); - return Table[to_underlying(kind)].name; + std::string_view full = + Table[to_underlying(kind)].name; + if(include_keyword || kind == OperatorKind::None) + return full; + // remove "operator" + full.remove_prefix(8); + // remove the space, if any + if(full.front() == ' ') + full.remove_prefix(1); + return full; } std::string_view @@ -108,10 +118,15 @@ getShortOperatorName( std::string_view getSafeOperatorName( - OperatorKind kind) noexcept + OperatorKind kind, + bool include_keyword) noexcept { MRDOX_ASSERT(Table[to_underlying(kind)].kind == kind); - return Table[to_underlying(kind)].safe_name; + std::string_view full = Table[to_underlying(kind)].safe_name; + if(include_keyword || kind == OperatorKind::None) + return full; + // remove "operator_" + return full.substr(9); } dom::String diff --git a/src/lib/Support/SafeNames.cpp b/src/lib/Support/SafeNames.cpp index 5d67d54fa..449133241 100644 --- a/src/lib/Support/SafeNames.cpp +++ b/src/lib/Support/SafeNames.cpp @@ -4,6 +4,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// Copyright (c) 2023 Krystian Stasiowski (sdkrystian@gmail.com) // // Official repository: https://github.com/cppalliance/mrdox // @@ -11,294 +12,356 @@ #include "lib/Support/Radix.hpp" #include "lib/Support/SafeNames.hpp" #include "lib/Support/Validate.hpp" +#include "lib/Support/Debug.hpp" #include #include #include -#include -#include -#include +#include +#include #include +#include +#include +#include namespace clang { namespace mrdox { -namespace { +class SafeNames::Impl +{ + Corpus const& corpus_; -/* - Unsafe names: + // store all info required to generate a safename + struct SafeNameInfo + { + // safename without disambiguation characters + std::string_view unqualified; + // number of characters from the SymbolID string + // required to uniquely identify this symbol + std::uint8_t disambig_chars; + // SymbolID converted to a string + std::string id_str; + }; - destructors - overloaded operators - function templates - class templates -*/ -class PrettyBuilder -{ - llvm::raw_ostream* os_ = nullptr; - std::string prefix_; - std::string temp_; + std::unordered_map map_; -public: - explicit - PrettyBuilder( - Corpus const& corpus) - : corpus_(corpus) + std::string_view + getReserved(const Info& I) { - prefix_.reserve(512); - visit(corpus_.globalNamespace(), *this); - /* auto result =*/ map.try_emplace( - llvm::StringRef(SymbolID::zero), std::string()); + // all valid c++ identifiers begin with + // an underscore or alphabetic character, + // so a numeric prefix ensures no conflicts + static + std::string_view + reserved[] = { + "0namespace", + "1record", + "2function", + "3enum", + "4typedef", + "5variable", + "6field", + "7specialization", + }; + if(I.isFunction()) + { + static + std::string_view + func_reserved[] = { + "2function", + "2constructor", + "2conversion", + "2destructor", + "2deduction_guide", + }; + const auto& FI = static_cast< + const FunctionInfo&>(I); + // don't use the reserved prefix for overloaded operators + if(FI.Class == FunctionClass::Normal && + FI.specs0.overloadedOperator.get() != + OperatorKind::None) + { + return getSafeOperatorName( + FI.specs0.overloadedOperator.get(), true); + } + std::size_t func_idx = to_underlying(FI.Class); + MRDOX_ASSERT(func_idx < std::size(func_reserved)); + return func_reserved[func_idx]; + } - #ifndef NDEBUG - //for(auto const& N : map) - //MRDOX_ASSERT(validAdocSectionID(N.second)); - #endif + std::size_t idx = to_underlying(I.Kind); + MRDOX_ASSERT(idx < std::size(reserved)); + return reserved[idx]; } - PrettyBuilder( - llvm::raw_ostream& os, - Corpus const& corpus) - : - //os_(&os), - corpus_(corpus) + std::string_view + getUnqualified( + const Info& I) { - prefix_.reserve(512); - visit(corpus_.globalNamespace(), *this); - /* auto result =*/ map.try_emplace( - llvm::StringRef(SymbolID::zero), std::string()); - if(os_) - *os_ << "\n\n"; - } + return visit(I, [&]( + const T& t) -> std::string_view + { + // namespaces can be unnamed (i.e. anonymous) + if constexpr(T::isNamespace()) + { + // special case for the global namespace + if(t.id == SymbolID::zero) + return std::string_view(); - llvm::StringMap map; + if(t.specs.isAnonymous.get()) + return getReserved(t); + MRDOX_ASSERT(! t.Name.empty()); + return t.Name; + } + // fields and typedefs cannot be overloaded + // or partially/explicitly specialized, + // but must have names + if constexpr( + T::isField() || + T::isTypedef()) + { + MRDOX_ASSERT(! t.Name.empty()); + return t.Name; + } - using ScopeInfos = std::vector; + // variables can be partially/explicitly + // specialized, but must have names and + // cannot be overloaded + if constexpr(T::isVariable()) + { + MRDOX_ASSERT(! t.Name.empty()); + return t.Name; + } - ScopeInfos - buildScope( - NamespaceInfo const& I) - { - ScopeInfos infos; - infos.reserve(I.Members.size()); - for(auto const& id : I.Members) - infos.emplace_back(corpus_.find(id)); - // KRYSTIAN FIXME: include specializations - if(infos.size() < 2) - return infos; - std::string s0, s1; - llvm::sort(infos, - [&](Info const* I0, Info const* I1) - { - return compareSymbolNames(I0->Name, I1->Name) < 0; - }); - return infos; - } + // enums cannot be overloaded or partially/ + // explicitly specialized, but can be unnamed + if constexpr(T::isEnum()) + { + /** KRYSTIAN FIXME: [dcl.enum] p12 states (paraphrased): - ScopeInfos - buildScope( - RecordInfo const& I) - { - ScopeInfos infos; - infos.reserve(I.Members.size()); - for(auto const& id : I.Members) - infos.emplace_back(corpus_.find(id)); - // KRYSTIAN FIXME: include specializations and friends - if(infos.size() < 2) - return infos; - std::string s0, s1; - llvm::sort(infos, - [&](Info const* I0, Info const* I1) - { - return compareSymbolNames(I0->Name, I1->Name) < 0; + an unnamed enumeration type that has a first enumerator + and does not have a typedef name for linkage purposes + is denoted by its underlying type and its + first enumerator for linkage purposes. + + should we also take this approach? note that this would not + address unnamed enumeration types without any enumerators. + */ + if(t.Name.empty()) + return getReserved(t); + return t.Name; + } + + // records can be partially/explicitly specialized, + // and can be unnamed, but cannot be overloaded + if constexpr(T::isRecord()) + { + if(t.Name.empty()) + return getReserved(t); + return t.Name; + } + + // functions must have named, + // can be explicitly specialized, + // and can be overloaded + if constexpr(T::isFunction()) + { + if(t.Class != FunctionClass::Normal || + t.specs0.overloadedOperator.get() != OperatorKind::None) + return getReserved(t); + MRDOX_ASSERT(! t.Name.empty()); + return t.Name; + } + + if constexpr(T::isSpecialization()) + { + MRDOX_ASSERT(! t.Name.empty()); + return t.Name; + } + + MRDOX_UNREACHABLE(); }); - return infos; } - llvm::StringRef - getSafe(Info const& I) - { - if(I.Kind != InfoKind::Function) - return I.Name; - auto const& FI = static_cast< - FunctionInfo const&>(I); - auto OOK = FI.specs0.overloadedOperator.get(); - if(OOK == OperatorKind::None) - return I.Name; - temp_ = '0'; - temp_.append(getSafeOperatorName(OOK)); - return temp_; - } + //-------------------------------------------- - void insertScope(ScopeInfos const& infos) + template + void + buildSafeMembers( + const Range& Members) { - if(os_) - { - std::string temp; - if( infos.size() > 0 && - infos.front()->Namespace.size() > 0) - { - auto const& P = corpus_.get(infos.front()->Namespace[0]); - corpus_.getFullyQualifiedName(P, temp); - temp.push_back(' '); - } - *os_ << - "------------------------\n" << - "Scope " << temp << - "with " << infos.size() << " names:\n\n"; - for(auto const& I : infos) - *os_ << I->Name << '\n'; - *os_ << '\n'; - } + // maps unqualified names to a vector of all symbols + // with that name within the current scope + std::unordered_map> disambiguation_map; + disambiguation_map.reserve(Members.size()); - auto it0 = infos.begin(); - while(it0 != infos.end()) + for(const SymbolID& id : Members) { - auto it = std::find_if( - it0 + 1, infos.end(), - [it0](auto I) - { - return - llvm::StringRef((*it0)->Name).compare_insensitive( - llvm::StringRef(I->Name)) != 0; - }); - std::size_t n = std::distance(it0, it); - if(n < 2) - { - // unique - std::string s; - s.assign(prefix_); - s.append(getSafe(**it0)); - if(os_) - *os_ << getSafe(**it0) << "\n"; - /*auto result =*/ map.try_emplace( - llvm::StringRef((*it0)->id), - std::move(s)); - it0 = it; + const Info* I = corpus_.find(id); + if(! I) continue; - } - // conflicting - for(std::size_t i = 0; i < n; ++i) + // generate the unqualified name and SymbolID string + auto [it, emplaced] = map_.emplace(I->id, SafeNameInfo( + getUnqualified(*I), 0, toBase16(I->id, true))); + // update the disambiguation map + auto [disambig_it, disambig_emplaced] = + disambiguation_map.try_emplace(it->second.unqualified); + + // if there are other symbols with the same name, then disambiguation + // is required. iterate over the other symbols with the same unqualified name, + // and calculate the minimum number of characters from the SymbolID needed + // to uniquely identify each symbol. then, update all symbols with the new value. + if(! disambig_emplaced) { - std::string s; - s.assign(prefix_); - std::string suffix; - suffix = std::to_string(i + 1); - //s.push_back('@'); - suffix.append(getSafe(**it0)); - if(os_) - *os_ << suffix << "\n"; - s.append(suffix); - /*auto result =*/ map.try_emplace( - llvm::StringRef(it0[i]->id), - std::move(s)); + std::uint8_t n_chars = 1; + std::string_view id_str = it->second.id_str; + for(const SymbolID& other : disambig_it->second) + { + std::string_view other_id_str = + map_.find(other)->second.id_str; + auto [mismatch_id, mismatch_other] = + std::mismatch(id_str.begin(), id_str.end(), + other_id_str.begin(), other_id_str.end()); + const auto n_required = std::distance( + id_str.begin(), mismatch_id) + 1; + n_chars = std::max(n_chars, + static_cast(n_required)); + } + + // update the number of disambiguation characters for each symbol + it->second.disambig_chars = n_chars; + for(const SymbolID& other : disambig_it->second) + map_.find(other)->second.disambig_chars = n_chars; + } - it0 = it; + disambig_it->second.push_back(I->id); } } - void visitInfos(ScopeInfos const& infos) + //-------------------------------------------- + +public: + explicit + Impl(Corpus const& corpus) + : corpus_(corpus) + { + map_.try_emplace(SymbolID::zero, SafeNameInfo( + "global_namespace", 0, toBase16(SymbolID::zero, true))); + + visit(corpus_.globalNamespace(), *this); + } + + void + getSafeUnqualified( + std::string& result, + const SymbolID& id) { - auto const n0 = prefix_.size(); - for(auto const I : infos) + MRDOX_ASSERT(corpus_.exists(id)); + auto const it = map_.find(id); + MRDOX_ASSERT(it != map_.end()); + auto& [unqualified, n_disambig, id_str] = it->second; + result.reserve( + result.size() + + unqualified.size() + + n_disambig ? n_disambig + 2 : 0); + result.append(unqualified); + if(n_disambig) { - prefix_.append(getSafe(*I)); - prefix_.push_back('-'); - ::clang::mrdox::visit(*I, *this); - prefix_.resize(n0); + // KRYSTIAN FIXME: the SymbolID chars must be prefixed with + // a reserved character, otherwise there could be a + // conflict with a name in an inner scope. this could be + // resolved by using the base-10 representation of the SymbolID + result.append("-0"); + result.append(id_str.c_str(), n_disambig); } } - //-------------------------------------------- + void + getSafeQualified( + std::string& result, + const SymbolID& id, + char delim) + { + MRDOX_ASSERT(corpus_.exists(id)); + auto const& parents = corpus_.get(id).Namespace; + if(parents.size() > 1) + { + for(auto const& parent : parents | + std::views::reverse | + std::views::drop(1)) + { + getSafeUnqualified(result, parent); + result.push_back(delim); + } + } + getSafeUnqualified(result, id); + } template void operator()(T const& I) { - if constexpr( - T::isNamespace() || - T::isRecord()) + if constexpr(T::isNamespace() || T::isRecord()) { - auto infos = buildScope(I); - insertScope(infos); - visitInfos(infos); + buildSafeMembers(I.Members); + for(const SymbolID& C : I.Members) + { + if(const Info* CI = corpus_.find(C)) + { + visit(*CI, *this); + } + } } - else + + if constexpr(T::isSpecialization()) { + buildSafeMembers( + std::views::transform(I.Members, + [](const SpecializedMember& M) -> + const SymbolID& + { + return M.Specialized; + })); + for(const SpecializedMember& M : I.Members) + { + if(const Info* CI = corpus_.find(M.Specialized)) + { + visit(*CI, *this); + } + } } } - -private: - Corpus const& corpus_; -}; - -//------------------------------------------------ - -// Always works but isn't the prettiest... -class UglyBuilder -{ - Corpus const& corpus_; - -public: - llvm::StringMap map; - - explicit - UglyBuilder( - Corpus const& corpus) - : corpus_(corpus) - { - llvm::SmallString<64> temp; - for(Info const* I : corpus_.index()) - map.try_emplace( - llvm::StringRef(I->id), - toBase16(I->id, true)); - } }; -} // (anon) - //------------------------------------------------ SafeNames:: -SafeNames( - llvm::raw_ostream& os, - Corpus const& corpus) - : corpus_(corpus) - //, map_(PrettyBuilder(corpus).map) - , map_(UglyBuilder(corpus).map) +SafeNames(Corpus const& corpus) + : impl_(std::make_unique(corpus)) { } SafeNames:: -SafeNames( - Corpus const& corpus) - : corpus_(corpus) - //, map_(PrettyBuilder(corpus).map) - , map_(UglyBuilder(corpus).map) -{ -} +~SafeNames() noexcept = default; -llvm::StringRef +std::string SafeNames:: -get( - SymbolID const &id) const noexcept +getUnqualified( + SymbolID const& id) const { - auto const it = map_.find(llvm::StringRef(id)); - MRDOX_ASSERT(it != map_.end()); - return it->getValue(); + std::string result; + impl_->getSafeUnqualified(result, id); + return result; } -std::vector& +std::string SafeNames:: -getPath( - std::vector& dest, - SymbolID id) const +getQualified( + SymbolID const& id, + char delim) const { - auto const& Parents = corpus_.get(id).Namespace; - dest.clear(); - dest.reserve(1 + Parents.size()); - dest.push_back(get(id)); - for(auto const& id : llvm::reverse(Parents)) - dest.push_back(get(id)); - return dest; + std::string result; + impl_->getSafeQualified(result, id, delim); + return result; } } // mrdox diff --git a/src/lib/Support/SafeNames.hpp b/src/lib/Support/SafeNames.hpp index 6f8be8788..a111968cb 100644 --- a/src/lib/Support/SafeNames.hpp +++ b/src/lib/Support/SafeNames.hpp @@ -13,9 +13,7 @@ #include #include -#include -#include -#include +#include #include namespace clang { @@ -32,12 +30,9 @@ namespace mrdox { */ class SafeNames { - Corpus const& corpus_; - llvm::StringMap map_; + class Impl; - SafeNames( - llvm::raw_ostream& os, - Corpus const&); + std::unique_ptr impl_; public: /** Constructor. @@ -46,24 +41,18 @@ class SafeNames safe names is built from the corpus. */ explicit - SafeNames( - Corpus const& corpus); + SafeNames(Corpus const& corpus); - llvm::StringRef - get(SymbolID const& id) const noexcept; + ~SafeNames() noexcept; - std::vector& - getPath( - std::vector& dest, - SymbolID id) const; + std::string + getUnqualified( + SymbolID const& id) const; - std::vector - getPath(SymbolID const& id) const - { - std::vector v; - getPath(v, id); - return v; - } + std::string + getQualified( + SymbolID const& id, + char delim = '-') const; }; } // mrdox diff --git a/src/tool/ToolMain.cpp b/src/tool/ToolMain.cpp index e2e0b15f4..9437c8a62 100644 --- a/src/tool/ToolMain.cpp +++ b/src/tool/ToolMain.cpp @@ -75,7 +75,7 @@ int mrdox_main(int argc, char const** argv) // Generate if(auto err = DoGenerateAction()) - report::error("Generating reference failed: ", err); + report::error("Generating reference failed: {}", err); if( report::results.errorCount > 0 || report::results.fatalCount > 0)