diff --git a/include/mrdox/mrdox.hpp b/include/mrdox/mrdox.hpp index 8277b0cbc..041142b1f 100644 --- a/include/mrdox/mrdox.hpp +++ b/include/mrdox/mrdox.hpp @@ -21,7 +21,7 @@ namespace doc { llvm::Expected renderXML( - llvm::StringRef path); + llvm::StringRef fileName); } // doc } // clang diff --git a/source/lib/Representation.h b/source/lib/Representation.h index 28d9154ed..714eb1353 100644 --- a/source/lib/Representation.h +++ b/source/lib/Representation.h @@ -234,9 +234,30 @@ struct TypeInfo { // This is a very simple serialization of the text of the source code of the // template parameter. It is saved in a struct so there is a place to add the // name and default values in the future if needed. -struct TemplateParamInfo { +// +/** A tempalte parameter. +*/ +struct TemplateParamInfo +{ + enum class Kind + { + Class, + Typename, + Nttp + }; + TemplateParamInfo() = default; - explicit TemplateParamInfo(StringRef Contents) : Contents(Contents) {} + + TemplateParamInfo( + //StringRef Name, + StringRef Contents) + : Contents(Contents) + { + } + + Kind kind = Kind::Class; + + //SmallString<16> Name; // The literal contents of the code for that specifies this template parameter // for this declaration. Typical values will be "class T" and diff --git a/source/lib/Serialize.cpp b/source/lib/Serialize.cpp index 45362d130..f0b32ffc2 100644 --- a/source/lib/Serialize.cpp +++ b/source/lib/Serialize.cpp @@ -381,17 +381,22 @@ void PopulateTemplateParameters(std::optional& TemplateInfo, if (!TemplateInfo) { TemplateInfo.emplace(); } - for (const NamedDecl* ND : *ParamList) { + for (const NamedDecl* ND : *ParamList) + { TemplateInfo->Params.emplace_back( getSourceCode(ND, ND->getSourceRange())); } } } -TemplateParamInfo TemplateArgumentToInfo(const clang::Decl* D, - const TemplateArgument& Arg) { - // The TemplateArgument's pretty printing handles all the normal cases - // well enough for our requirements. +TemplateParamInfo +TemplateArgumentToInfo( + clang::Decl const* D, + TemplateArgument const & Arg) +{ + // The TemplateArgument's pretty printing + // handles all the normal cases well enough + // for our requirements. std::string Str; llvm::raw_string_ostream Stream(Str); Arg.print(PrintingPolicy(D->getLangOpts()), Stream, false); diff --git a/source/lib/XMLGenerator.cpp b/source/lib/XMLGenerator.cpp index 514ff598c..19091a487 100644 --- a/source/lib/XMLGenerator.cpp +++ b/source/lib/XMLGenerator.cpp @@ -17,11 +17,92 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +//------------------------------------------------ +/* + DTD + + Tags + ns namespace + udt class, struct, union + fn + en + ty + + Attributes + n name + r return type + a Access +*/ //------------------------------------------------ namespace clang { namespace doc { +namespace { + +//------------------------------------------------ + +struct escape +{ + explicit + escape( + llvm::StringRef const& s) noexcept + : s_(s) + { + } + + friend + llvm::raw_ostream& + operator<<( + llvm::raw_ostream& os, + escape const& t) + { + std::size_t pos = 0; + auto const size = t.s_.size(); + while(pos < size) + { + unescaped: + auto const found = t.s_.find_first_of("<>&'\"", pos); + if(found == llvm::StringRef::npos) + { + os.write(t.s_.data() + pos, t.s_.size() - pos); + break; + } + os.write(t.s_.data() + pos, found - pos); + pos = found; + while(pos < size) + { + auto const c = t.s_[pos]; + switch(c) + { + case '<': + os.write("<", 4); + break; + case '>': + os.write(">", 4); + break; + case '&': + os.write("&", 5); + break; + case '\'': + os.write("'", 6); + break; + case '\"': + os.write(""", 6); + break; + default: + goto unescaped; + } + ++pos; + } + } + return os; + } + +private: + llvm::StringRef s_; +}; + //------------------------------------------------ namespace fs = llvm::sys::fs; @@ -69,16 +150,15 @@ class XMLGenerator void writeTag(llvm::StringRef); void writeTag(llvm::StringRef, Attrs); - void writeHeader(); - void write(NamespaceInfo const& I); - void write(RecordInfo const& I); - void write(FunctionInfo const& I); - void write(EnumInfo const& I); - void write(TypedefInfo const& I); - void write(FunctionOverloads const& fns); - void write(FunctionList const& fnList); - void write(std::vector const& v); - void write(std::vector const& v); + void writeNamespace(NamespaceInfo const& I); + void writeRecord(RecordInfo const& I); + void writeFunction(FunctionInfo const& I); + void writeEnum(EnumInfo const& I); + void writeTypedef(TypedefInfo const& I); + void writeOverloads(FunctionOverloads const& fns); + void writeFunctions(FunctionList const& fnList); + void writeEnums(std::vector const& v); + void writeTypedefs(std::vector const& v); void writeNamespaces(std::vector const& v); void writeRecords(std::vector const& v); @@ -88,6 +168,9 @@ class XMLGenerator InfoMap const* infos_ = nullptr; }; +//------------------------------------------------ + + //------------------------------------------------ llvm::Error @@ -120,10 +203,21 @@ generateDocs( return llvm::createStringError( ec, "output file could not be opened"); - os_ = &os; - writeHeader(); level_ = {}; - write(*ns); + os_ = &os; +#if 0 + *os_ << + "\n" << + "\n" << + "\n"; +#endif + writeNamespace(*ns); +#if 0 + *os_ << + "\n"; +#endif + // VFALCO the error handling needs to be + // propagated through all write functions if(os_->error()) return llvm::createStringError( ec, @@ -174,7 +268,6 @@ openTag( { *os_ << level_ << '<' << tag << ">\n"; level_.push_back(' '); - level_.push_back(' '); } void @@ -187,10 +280,9 @@ openTag( for(auto const& attr : init) *os_ << ' ' << attr.first << '=' << - "\"" << attr.second << "\""; + "\"" << escape(attr.second) << "\""; *os_ << ">\n"; level_.push_back(' '); - level_.push_back(' '); } void @@ -198,7 +290,6 @@ XMLGenerator:: closeTag( llvm::StringRef tag) { - level_.pop_back(); level_.pop_back(); *os_ << level_ << "\n"; } @@ -221,7 +312,7 @@ writeTag( for(auto const& attr : init) *os_ << ' ' << attr.first << '=' << - "\"" << attr.second << "\""; + "\"" << escape(attr.second) << "\""; *os_ << "/>\n"; } @@ -229,97 +320,117 @@ writeTag( void XMLGenerator:: -writeHeader() -{ - *os_ << - "\n" << - "\n"; -} - -void -XMLGenerator:: -write( +writeNamespace( NamespaceInfo const& I) { - openTag("namespace", { - { "name", I.Name } + openTag( + "ns", { + { "n", I.Name } }); writeNamespaces(I.Children.Namespaces); writeRecords(I.Children.Records); - write(I.Children.functions); - write(I.Children.Enums); - write(I.Children.Typedefs); - closeTag("namespace"); + writeFunctions(I.Children.functions); + writeEnums(I.Children.Enums); + writeTypedefs(I.Children.Typedefs); + closeTag("ns"); } //------------------------------------------------ void XMLGenerator:: -write( +writeRecord( RecordInfo const& I) { - openTag("compound", { - { "name", I.Name }, - { "type", getTagType(I.TagType) } + openTag( + "udt", { + { "n", I.Name }, + { "t", getTagType(I.TagType) } }); writeNamespaces(I.Children.Namespaces); writeRecords(I.Children.Records); - write(I.Children.functions); - write(I.Children.Enums); - write(I.Children.Typedefs); - closeTag("compound"); + writeFunctions(I.Children.functions); + writeEnums(I.Children.Enums); + writeTypedefs(I.Children.Typedefs); + closeTag("udt"); } //------------------------------------------------ +static +llvm::StringRef +toString( + AccessSpecifier access) +{ + switch(access) + { + case AccessSpecifier::AS_public: + return "0"; + case AccessSpecifier::AS_protected: + return "1"; + case AccessSpecifier::AS_private: + return "2"; + case AccessSpecifier::AS_none: + default: + return "3"; + } +} + void XMLGenerator:: -write( +writeFunction( FunctionInfo const& I) { - openTag("function", { - { "name", I.Name }, - { "returns", I.ReturnType.Type.Name } + openTag("fn", { + { "n", I.Name }, + { "r", I.ReturnType.Type.Name }, + { "a", toString(I.Access) } }); + if(I.Template) + { + for(TemplateParamInfo const& tp : I.Template->Params) + writeTag( + "tp", { + { "n", tp.Contents } + }); + } for(FieldTypeInfo const& p : I.Params) - writeTag("param", { - { "name", p.Name }, - { "type", p.Type.Name } + writeTag("p", { + { "n", p.Name }, + { "t", p.Type.Name } }); - - closeTag("function"); + closeTag("fn"); } //------------------------------------------------ void XMLGenerator:: -write( +writeEnum( EnumInfo const& I) { - openTag("enum", { - { "name", I.Name }, + openTag("en", { + { "n", I.Name }, }); for(auto const& v : I.Members) { writeTag("value", { - { "name", v.Name }, - { "value", v.Value }, + { "n", v.Name }, + { "v", v.Value }, }); } - - closeTag("enum"); + closeTag("en"); } //------------------------------------------------ void XMLGenerator:: -write( +writeTypedef( TypedefInfo const& I) { - writeTag("typedef", { - { "name", I.Name } + writeTag( + "ty", { + { "n", I.Name } }); } @@ -327,38 +438,38 @@ write( void XMLGenerator:: -write( +writeOverloads( FunctionOverloads const& fns) { for(auto const& fn : fns) - write(fn); + writeFunction(fn); } void XMLGenerator:: -write( +writeFunctions( FunctionList const& fnList) { for(auto const& fns : fnList) - write(fns); + writeOverloads(fns); } void XMLGenerator:: -write( +writeEnums( std::vector const& v) { for(auto const& I : v) - write(I); + writeEnum(I); } void XMLGenerator:: -write( +writeTypedefs( std::vector const& v) { for(auto const& I : v) - write(I); + writeTypedef(I); } //------------------------------------------------ @@ -374,8 +485,9 @@ writeNamespaces( auto it = infos_->find( llvm::toHex(llvm::toStringRef(ref.USR))); assert(it != infos_->end()); - write(*static_cast( - it->second.get())); + writeNamespace( + *static_cast( + it->second.get())); } } @@ -390,8 +502,9 @@ writeRecords( auto it = infos_->find( llvm::toHex(llvm::toStringRef(ref.USR))); assert(it != infos_->end()); - write(*static_cast( - it->second.get())); + writeRecord( + *static_cast( + it->second.get())); } } @@ -401,12 +514,26 @@ char const* XMLGenerator:: Format = "xml"; +} // (anon) + //------------------------------------------------ llvm::Expected renderXML( - llvm::StringRef path) + llvm::StringRef fileName) { + if(! path::extension(fileName).equals_insensitive(".cpp")) + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "not a .cpp file"); + llvm::SmallString<256> dir( + path::parent_path(fileName)); +#if 0 + tooling::FixedCompilationDatabase cdb( + dir, +#endif + + return llvm::Twine(); } diff --git a/source/tests/test_main.cpp b/source/tests/test_main.cpp index 21155efb0..e9e94f815 100644 --- a/source/tests/test_main.cpp +++ b/source/tests/test_main.cpp @@ -51,7 +51,7 @@ do_main(int argc, const char** argv) llvm::SmallString<128> xmlPath(name); path::remove_dots(cppPath, true); path::remove_dots(xmlPath, true); - if(path::extension(name).equals_insensitive("cpp")) + if(path::extension(name).equals_insensitive(".cpp")) { if(! fs::is_regular_file(name)) { @@ -68,7 +68,7 @@ do_main(int argc, const char** argv) return EXIT_FAILURE; } } - else if(path::extension(name).equals_insensitive("xml")) + else if(path::extension(name).equals_insensitive(".xml")) { path::replace_extension(cppPath, "cpp"); if( ! fs::exists(cppPath) || diff --git a/testfiles/1.cpp b/testfiles/1.cpp index fe71f4004..f3c598fb0 100644 --- a/testfiles/1.cpp +++ b/testfiles/1.cpp @@ -1 +1,2 @@ -namespace N {} +int f(double d, char const* p) noexcept; + diff --git a/testfiles/1.xml b/testfiles/1.xml index 6c2bd1f32..e69de29bb 100644 --- a/testfiles/1.xml +++ b/testfiles/1.xml @@ -1,2 +0,0 @@ - -