diff --git a/include/mrdox/Config.hpp b/include/mrdox/Config.hpp index 5a690affb..5e313aaff 100644 --- a/include/mrdox/Config.hpp +++ b/include/mrdox/Config.hpp @@ -82,7 +82,8 @@ setupContext( llvm::Error doMapping( - Config& cfg); + Corpus& corpus, + Config const& cfg); /** Build the internal index of the program under analysis. @@ -90,8 +91,8 @@ doMapping( */ llvm::Error buildIndex( - Config const& cfg, - Corpus& corpus); + Corpus& corpus, + Config const& cfg); } // mrdox } // clang diff --git a/source/lib/ClangDoc.cpp b/source/lib/ClangDoc.cpp index 9406e6956..e8980cb18 100644 --- a/source/lib/ClangDoc.cpp +++ b/source/lib/ClangDoc.cpp @@ -25,19 +25,16 @@ namespace mrdox { namespace { -// VFALCO It looks like each created action needs -// its own copy of the Config? -// Maybe because of concurrency. - //------------------------------------------------ struct action : public clang::ASTFrontendAction { - explicit action( - Config& cfg) - : cfg(cfg) + Corpus& corpus, + Config const& cfg) noexcept + : corpus_(corpus) + , cfg_(cfg) { } @@ -46,11 +43,12 @@ struct action clang::CompilerInstance& Compiler, llvm::StringRef InFile) override { - return std::make_unique(cfg); + return std::make_unique(corpus_, cfg_); } private: - Config& cfg; + Corpus& corpus_; + Config const& cfg_; }; //------------------------------------------------ @@ -58,20 +56,23 @@ struct action struct factory : public tooling::FrontendActionFactory { - explicit factory( - Config& cfg) - : cfg(cfg) + Corpus& corpus, + Config const& cfg) noexcept + : corpus_(corpus) + , cfg_(cfg) { } std::unique_ptr create() override { - return std::make_unique(cfg); + return std::make_unique(corpus_, cfg_); } - - Config& cfg; + +private: + Corpus& corpus_; + Config const& cfg_; }; } // (anon) @@ -81,18 +82,20 @@ struct factory std::unique_ptr< clang::FrontendAction> makeFrontendAction( - Config& cfg) + Corpus& corpus, + Config const& cfg) { - return std::make_unique(cfg); + return std::make_unique(corpus, cfg); } std::unique_ptr< tooling::FrontendActionFactory> newMapperActionFactory( - Config& cfg) + Corpus& corpus, + Config const& cfg) { - return std::make_unique(cfg); + return std::make_unique(corpus, cfg); } -} // namespace mrdox -} // namespace clang +} // mrdox +} // clang diff --git a/source/lib/ClangDoc.h b/source/lib/ClangDoc.h index 139d4ae2d..57b2cdd64 100644 --- a/source/lib/ClangDoc.h +++ b/source/lib/ClangDoc.h @@ -29,12 +29,14 @@ namespace mrdox { std::unique_ptr< clang::FrontendAction> makeFrontendAction( - Config& cfg); + Corpus& corpus, + Config const& cfg); std::unique_ptr< tooling::FrontendActionFactory> newMapperActionFactory( - Config& cfg); + Corpus& corpus, + Config const& cfg); } // namespace mrdox } // namespace clang diff --git a/source/lib/Config.cpp b/source/lib/Config.cpp index 2f3aa5191..f02d842f2 100644 --- a/source/lib/Config.cpp +++ b/source/lib/Config.cpp @@ -197,14 +197,15 @@ setupContext( llvm::Error doMapping( - Config& cfg) + Corpus& corpus, + Config const& cfg) { // // Mapping phase // llvm::outs() << "Mapping declarations\n"; auto Err = cfg.Executor->execute( - newMapperActionFactory(cfg), + newMapperActionFactory(corpus, cfg), cfg.ArgAdjuster); if(Err) { @@ -225,8 +226,8 @@ doMapping( llvm::Error buildIndex( - Config const& cfg, - Corpus& corpus) + Corpus& corpus, + Config const& cfg) { // Collect values into output by key. // In ToolResults, the Key is the hashed USR and the value is the diff --git a/source/lib/Error.hpp b/source/lib/Error.hpp new file mode 100644 index 000000000..79140174e --- /dev/null +++ b/source/lib/Error.hpp @@ -0,0 +1,23 @@ +// +// This is a derivative work. originally part of the LLVM Project. +// 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) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdox +// + +#ifndef MRDOX_SOURCE_ERROR_HPP +#define MRDOX_SOURCE_ERROR_HPP + +#include + +namespace clang { +namespace mrdox { + +} // mrdox +} // clang + +#endif diff --git a/source/lib/Mapper.cpp b/source/lib/Mapper.cpp index ce1b54892..7f9582bc5 100644 --- a/source/lib/Mapper.cpp +++ b/source/lib/Mapper.cpp @@ -11,6 +11,7 @@ #include "Mapper.h" #include "BitcodeWriter.h" +#include "Error.hpp" #include "Serialize.h" #ifdef _MSC_VER #pragma warning(push) @@ -52,18 +53,20 @@ mapDecl(T const* D) return true; bool IsFileInRootDir; llvm::SmallString<128> File = - getFile(D, D->getASTContext(), cfg.SourceRoot, IsFileInRootDir); + getFile(D, D->getASTContext(), cfg_.SourceRoot, IsFileInRootDir); auto I = serialize::emitInfo(D, getComment(D, D->getASTContext()), getLine(D, D->getASTContext()), File, - IsFileInRootDir, cfg.PublicOnly); + IsFileInRootDir, cfg_.PublicOnly); // A null in place of I indicates that the serializer is skipping this decl // for some reason (e.g. we're only reporting public decls). if (I.first) - cfg.ECtx->reportResult(llvm::toHex(llvm::toStringRef(I.first->USR)), + cfg_.ECtx->reportResult( + llvm::toHex(llvm::toStringRef(I.first->USR)), serialize::serialize(I.first)); if (I.second) - cfg.ECtx->reportResult(llvm::toHex(llvm::toStringRef(I.second->USR)), + cfg_.ECtx->reportResult( + llvm::toHex(llvm::toStringRef(I.second->USR)), serialize::serialize(I.second)); return true; } diff --git a/source/lib/Mapper.h b/source/lib/Mapper.h index 057c7438b..65727a42d 100644 --- a/source/lib/Mapper.h +++ b/source/lib/Mapper.h @@ -38,8 +38,10 @@ class MapASTVisitor public: explicit MapASTVisitor( + Corpus& corpus, Config const& cfg) - : cfg(cfg) + : corpus_(corpus) + , cfg_(cfg) { } @@ -73,7 +75,8 @@ class MapASTVisitor NamedDecl const* D, ASTContext const& Context) const; - Config const& cfg; + Corpus& corpus_; + Config const& cfg_; }; } // mrdox diff --git a/source/lib/Representation.h b/source/lib/Representation.h index baf8ecfff..100b4e5f8 100644 --- a/source/lib/Representation.h +++ b/source/lib/Representation.h @@ -111,20 +111,40 @@ struct CommentInfo Children; // List of child comments for this CommentInfo. }; -struct Reference { +struct Reference +{ // This variant (that takes no qualified name parameter) uses the Name as the // QualName (very useful in unit tests to reduce verbosity). This can't use an // empty string to indicate the default because we need to accept the empty // string as a valid input for the global namespace (it will have // "GlobalNamespace" as the name, but an empty QualName). - Reference(SymbolID USR = SymbolID(), StringRef Name = StringRef(), + Reference( + SymbolID USR = SymbolID(), + StringRef Name = StringRef(), InfoType IT = InfoType::IT_default) - : USR(USR), Name(Name), QualName(Name), RefType(IT) {} - Reference(SymbolID USR, StringRef Name, InfoType IT, StringRef QualName, + : USR(USR) + , Name(Name) + , QualName(Name) + , RefType(IT) + { + } + + Reference( + SymbolID USR, + StringRef Name, + InfoType IT, + StringRef QualName, StringRef Path = StringRef()) - : USR(USR), Name(Name), QualName(QualName), RefType(IT), Path(Path) {} + : USR(USR) + , Name(Name) + , QualName(QualName) + , RefType(IT) + , Path(Path) + { + } - bool operator==(const Reference& Other) const { + bool operator==(const Reference& Other) const + { return std::tie(USR, Name, QualName, RefType) == std::tie(Other.USR, Other.Name, QualName, Other.RefType); } @@ -151,10 +171,10 @@ struct Reference { SmallString<16> QualName; InfoType RefType = InfoType::IT_default; // Indicates the type of this - // Reference (namespace, record, - // function, enum, default). -// Path of directory where the clang-doc generated file will be saved -// (possibly unresolved) + // Reference (namespace, record, function, enum, default). + + // Path of directory where the mrdox generated file will be saved + // (possibly unresolved) llvm::SmallString<128> Path; }; @@ -215,7 +235,8 @@ struct AccessScope }; // A base struct for TypeInfos -struct TypeInfo { +struct TypeInfo +{ TypeInfo() = default; TypeInfo(const Reference& R) : Type(R) {} diff --git a/source/lib/XML.cpp b/source/lib/XML.cpp index b20cedfc3..bbca33f24 100644 --- a/source/lib/XML.cpp +++ b/source/lib/XML.cpp @@ -564,13 +564,17 @@ renderCodeAsXML( Config const& cfg) { std::unique_ptr astUnit = - clang::tooling::buildASTFromCodeWithArgs(cppCode, {}); - MapASTVisitor visitor(cfg); - visitor.HandleTranslationUnit(astUnit->getASTContext()); + clang::tooling::buildASTFromCodeWithArgs(cppCode, {}); Corpus corpus; - if(llvm::Error err = buildIndex(cfg, corpus)) + MapASTVisitor visitor(corpus, cfg); + visitor.HandleTranslationUnit(astUnit->getASTContext()); + if(llvm::Error err = buildIndex(corpus, cfg)) return ! err; - return XMLGenerator(cfg).render(xml, corpus, cfg); + bool success = XMLGenerator(cfg).render(xml, corpus, cfg); + // VFALCO oops, cfg.Executor->getToolResults() + // holds information from the previous corpus... + //cfg.Executor->getToolResults()-> + return success; } //------------------------------------------------ diff --git a/source/mrdox/ToolMain.cpp b/source/mrdox/ToolMain.cpp index f6b3c8456..800d844e6 100644 --- a/source/mrdox/ToolMain.cpp +++ b/source/mrdox/ToolMain.cpp @@ -85,8 +85,10 @@ main(int argc, const char** argv) return EXIT_FAILURE; } + clang::mrdox::Corpus corpus; + // Extract the AST first - if(llvm::Error err = doMapping(cfg)) + if(llvm::Error err = doMapping(corpus, cfg)) { llvm::errs() << toString(std::move(err)) << "\n"; @@ -95,8 +97,7 @@ main(int argc, const char** argv) // Build the internal representation of // the C++ declarations to be documented. - clang::mrdox::Corpus corpus; - if(llvm::Error err = buildIndex(cfg, corpus)) + if(llvm::Error err = buildIndex(corpus, cfg)) { llvm::errs() << toString(std::move(err)) << "\n"; diff --git a/source/tests/TestMain.cpp b/source/tests/TestMain.cpp index 5f6569f33..7100f0977 100644 --- a/source/tests/TestMain.cpp +++ b/source/tests/TestMain.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include // VFALCO GARBAGE @@ -35,6 +36,11 @@ namespace mrdox { namespace { +void +testDir() +{ +} + //------------------------------------------------ int @@ -59,12 +65,15 @@ do_main(int argc, const char** argv) return EXIT_FAILURE; } + std::atomic gotFailure = false; + std::string xml; for(int i = 1; i < argc; ++i) { std::error_code ec; llvm::SmallString<256> dir(argv[i]); path::remove_dots(dir, true); + fs::recursive_directory_iterator const end{}; fs::recursive_directory_iterator iter(dir, ec, false); if(ec) { @@ -73,71 +82,89 @@ do_main(int argc, const char** argv) dir << "\"\n"; return EXIT_FAILURE; } - auto const& name = iter->path(); - llvm::SmallString<128> cppPath(name); - llvm::SmallString<128> xmlPath(name); - path::remove_dots(cppPath, true); - path::remove_dots(xmlPath, true); - if(path::extension(name).equals_insensitive(".cpp")) + while(iter != end) { - if(! fs::is_regular_file(name)) { - llvm::errs() << - "invalid file: \"" << name << "\"\n"; - return EXIT_FAILURE; + auto const& name = iter->path(); + llvm::SmallString<128> cppPath(name); + llvm::SmallString<128> xmlPath(name); + path::remove_dots(cppPath, true); + path::remove_dots(xmlPath, true); + if(path::extension(name).equals_insensitive(".cpp")) + { + if(! fs::is_regular_file(name)) + { + llvm::errs() << + "invalid file: \"" << name << "\"\n"; + return EXIT_FAILURE; + } + path::replace_extension(xmlPath, "xml"); + if( ! fs::exists(xmlPath) || + ! fs::is_regular_file(xmlPath)) + { + llvm::errs() << + "missing or invalid file: \"" << xmlPath << "\"\n"; + return EXIT_FAILURE; + } + } + else if(path::extension(name).equals_insensitive(".xml")) + { + path::replace_extension(cppPath, "cpp"); + if( ! fs::exists(cppPath) || + ! fs::is_regular_file(cppPath)) + { + llvm::errs() << + "missing or invalid file: \"" << cppPath << "\"\n"; + return EXIT_FAILURE; + } + + // don't process the same test twice + goto loop; + } + else + { + // not .cpp or .xml + goto loop; + } + + llvm::StringRef cppCode; + auto cppResult = llvm::MemoryBuffer::getFile(cppPath, true); + if(! cppResult) + { + llvm::errs() << + cppResult.getError().message() << ": \"" << xmlPath << "\"\n"; + return EXIT_FAILURE; + } + cppCode = cppResult->get()->getBuffer(); + + llvm::StringRef expectedXml; + auto xmlResult = llvm::MemoryBuffer::getFile(xmlPath, true); + if(! xmlResult) + { + llvm::errs() << + xmlResult.getError().message() << ": \"" << xmlPath << "\"\n"; + return EXIT_FAILURE; + } + expectedXml = xmlResult->get()->getBuffer(); + + if(! renderCodeAsXML(xml, cppCode, cfg)) + return EXIT_FAILURE; + + if(xml != expectedXml) + { + gotFailure = true; + llvm::errs() << + "Failed: \"" << xmlPath << "\", got\n" << + xml; + } } - path::replace_extension(xmlPath, "xml"); - if( ! fs::exists(xmlPath) || - ! fs::is_regular_file(xmlPath)) - { - llvm::errs() << - "missing or invalid file: \"" << xmlPath << "\"\n"; - return EXIT_FAILURE; - } - } - else if(path::extension(name).equals_insensitive(".xml")) - { - path::replace_extension(cppPath, "cpp"); - if( ! fs::exists(cppPath) || - ! fs::is_regular_file(cppPath)) - { - llvm::errs() << - "missing or invalid file: \"" << cppPath << "\"\n"; - return EXIT_FAILURE; - } - - // don't process the same test twice - continue; - } - - llvm::StringRef cppCode; - auto cppResult = llvm::MemoryBuffer::getFile(cppPath, true); - if(! cppResult) - { - llvm::errs() << - cppResult.getError().message() << ": \"" << xmlPath << "\"\n"; - return EXIT_FAILURE; + loop: + iter.increment(ec); } - cppCode = cppResult->get()->getBuffer(); - - llvm::StringRef expectedXml; - auto xmlResult = llvm::MemoryBuffer::getFile(xmlPath, true); - if(! xmlResult) - { - llvm::errs() << - xmlResult.getError().message() << ": \"" << xmlPath << "\"\n"; - return EXIT_FAILURE; - } - expectedXml = xmlResult->get()->getBuffer(); - - if(! renderCodeAsXML(xml, cppCode, cfg)) - return EXIT_FAILURE; - - if(xml != expectedXml) - llvm::errs() << - "Failed: \"" << xmlPath << "\"\n"; } + if(gotFailure) + return EXIT_FAILURE; return EXIT_SUCCESS; } diff --git a/testfiles/bare/ns.cpp b/testfiles/bare/ns.cpp new file mode 100644 index 000000000..fe71f4004 --- /dev/null +++ b/testfiles/bare/ns.cpp @@ -0,0 +1 @@ +namespace N {} diff --git a/testfiles/bare/ns.xml b/testfiles/bare/ns.xml new file mode 100644 index 000000000..792e15c77 --- /dev/null +++ b/testfiles/bare/ns.xml @@ -0,0 +1,2 @@ + +