/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */
 
#include <sal/config.h>
#include <sal/log.hxx>
 
#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <map>
#include <set>
#include <string_view>
#include <memory>
#include <utility>
#include <vector>
#include <iostream>
 
#include <rtl/alloc.h>
#include <rtl/ref.hxx>
#include <rtl/ustrbuf.hxx>
#include <rtl/ustring.hxx>
#include <rtl/strbuf.hxx>
#include <unoidl/unoidl.hxx>
 
#include <codemaker/commoncpp.hxx>
#include <codemaker/exceptiontree.hxx>
#include <codemaker/generatedtypeset.hxx>
#include <codemaker/typemanager.hxx>
#include <codemaker/unotype.hxx>
 
#include "cpputype.hxx"
#include "cppuoptions.hxx"
#include "dependencies.hxx"
#include "dumputils.hxx"
#include "includes.hxx"
 
namespace
{
 
using FileType = codemaker::cppumaker::FileType;
 
bool isBootstrapType(OUString const & name)
{
    static char const * const names[] = {
        "com.sun.star.beans.Property",
        "com.sun.star.beans.PropertyAttribute",
        "com.sun.star.beans.PropertyChangeEvent",
        "com.sun.star.beans.PropertyState",
        "com.sun.star.beans.PropertyValue",
        "com.sun.star.beans.XFastPropertySet",
        "com.sun.star.beans.XMultiPropertySet",
        "com.sun.star.beans.XPropertiesChangeListener",
        "com.sun.star.beans.XPropertyAccess",
        "com.sun.star.beans.XPropertyChangeListener",
        "com.sun.star.beans.XPropertySet",
        "com.sun.star.beans.XPropertySetInfo",
        "com.sun.star.beans.XPropertySetOption",
        "com.sun.star.beans.XVetoableChangeListener",
        "com.sun.star.bridge.UnoUrlResolver",
        "com.sun.star.bridge.XUnoUrlResolver",
        "com.sun.star.connection.SocketPermission",
        "com.sun.star.container.XElementAccess",
        "com.sun.star.container.XEnumeration",
        "com.sun.star.container.XEnumerationAccess",
        "com.sun.star.container.XHierarchicalNameAccess",
        "com.sun.star.container.XNameAccess",
        "com.sun.star.container.XNameContainer",
        "com.sun.star.container.XNameReplace",
        "com.sun.star.container.XSet",
        "com.sun.star.io.FilePermission",
        "com.sun.star.io.IOException",
        "com.sun.star.lang.DisposedException",
        "com.sun.star.lang.EventObject",
        "com.sun.star.lang.WrappedTargetRuntimeException",
        "com.sun.star.lang.XComponent",
        "com.sun.star.lang.XEventListener",
        "com.sun.star.lang.XInitialization",
        "com.sun.star.lang.XMultiComponentFactory",
        "com.sun.star.lang.XMultiServiceFactory",
        "com.sun.star.lang.XServiceInfo",
        "com.sun.star.lang.XSingleComponentFactory",
        "com.sun.star.lang.XSingleServiceFactory",
        "com.sun.star.lang.XTypeProvider",
        "com.sun.star.loader.XImplementationLoader",
        "com.sun.star.reflection.FieldAccessMode",
        "com.sun.star.reflection.MethodMode",
        "com.sun.star.reflection.ParamInfo",
        "com.sun.star.reflection.ParamMode",
        "com.sun.star.reflection.TypeDescriptionSearchDepth",
        "com.sun.star.reflection.XCompoundTypeDescription",
        "com.sun.star.reflection.XEnumTypeDescription",
        "com.sun.star.reflection.XIdlArray",
        "com.sun.star.reflection.XIdlClass",
        "com.sun.star.reflection.XIdlField",
        "com.sun.star.reflection.XIdlField2",
        "com.sun.star.reflection.XIdlMethod",
        "com.sun.star.reflection.XIdlReflection",
        "com.sun.star.reflection.XIndirectTypeDescription",
        "com.sun.star.reflection.XInterfaceAttributeTypeDescription",
        "com.sun.star.reflection.XInterfaceAttributeTypeDescription2",
        "com.sun.star.reflection.XInterfaceMemberTypeDescription",
        "com.sun.star.reflection.XInterfaceMethodTypeDescription",
        "com.sun.star.reflection.XInterfaceTypeDescription",
        "com.sun.star.reflection.XInterfaceTypeDescription2",
        "com.sun.star.reflection.XMethodParameter",
        "com.sun.star.reflection.XStructTypeDescription",
        "com.sun.star.reflection.XTypeDescription",
        "com.sun.star.reflection.XTypeDescriptionEnumeration",
        "com.sun.star.reflection.XTypeDescriptionEnumerationAccess",
        "com.sun.star.registry.RegistryKeyType",
        "com.sun.star.registry.RegistryValueType",
        "com.sun.star.registry.XImplementationRegistration",
        "com.sun.star.registry.XRegistryKey",
        "com.sun.star.registry.XSimpleRegistry",
        "com.sun.star.security.RuntimePermission",
        "com.sun.star.security.XAccessControlContext",
        "com.sun.star.security.XAccessController",
        "com.sun.star.security.XAction",
        "com.sun.star.uno.DeploymentException",
        "com.sun.star.uno.RuntimeException",
        "com.sun.star.uno.TypeClass",
        "com.sun.star.uno.Uik",
        "com.sun.star.uno.XAdapter",
        "com.sun.star.uno.XAggregation",
        "com.sun.star.uno.XComponentContext",
        "com.sun.star.uno.XCurrentContext",
        "com.sun.star.uno.XInterface",
        "com.sun.star.uno.XReference",
        "com.sun.star.uno.XUnloadingPreference",
        "com.sun.star.uno.XWeak",
        "com.sun.star.util.XMacroExpander" };
        // cf. cppuhelper/unotypes/Makefile UNOTYPES (plus missing dependencies)
    auto const pred = [&name](const char* aName) {
            return name.equalsAscii(aName);
    };
    return std::any_of(std::begin(names), std::end(names), pred);
}
 
OString getFileExtension(FileType eFileType)
{
    switch(eFileType)
    {
        default:
        case FileType::HDL: return ".hdl"_ostr;
        case FileType::HPP: return ".hpp"_ostr;
    }
}
 
class CppuType
{
public:
    CppuType(OUString name, rtl::Reference< TypeManager > const & typeMgr);
 
    virtual ~CppuType() {}
 
    CppuType(const CppuType&) = delete;
    const CppuType& operator=(const CppuType&) = delete;
 
    void dump(CppuOptions const & options);
 
    void dumpFile(
        std::u16string_view uri, std::u16string_view name, FileType eFileType,
        CppuOptions const & options);
 
    void dumpDependedTypes(
        codemaker::GeneratedTypeSet & generated, CppuOptions const & options) const;
 
    virtual void dumpHdlFile(
        FileStream & out, codemaker::cppumaker::Includes & includes) {
        dumpHFileContent(out, includes);
    }
 
    virtual void dumpHppFile(FileStream& o, codemaker::cppumaker::Includes & includes) = 0;
 
    OUString dumpHeaderDefine(FileStream& o, std::u16string_view extension) const;
 
    void dumpGetCppuType(FileStream & out);
 
    virtual void dumpLightGetCppuType(FileStream & out);
 
    virtual void dumpNormalGetCppuType(FileStream &) {
        assert(false);    // this cannot happen
    }
 
    virtual void dumpComprehensiveGetCppuType(FileStream &) {
        assert(false);    // this cannot happen
    }
 
    void dumpType(
        FileStream & out, std::u16string_view name, bool isConst = false,
        bool isRef = false, bool native = false, bool cppuUnoType = false)
    const;
 
    OUString getTypeClass(OUString const & name, bool cStyle = false);
 
    void dumpCppuGetType(
        FileStream & out, std::u16string_view name, OUString const * ownName = nullptr) const;
 
    sal_uInt32 getInheritedMemberCount();
 
    void            inc(sal_Int32 num=4);
    void            dec(sal_Int32 num=4);
    OUString indent() const;
protected:
    virtual sal_uInt32 checkInheritedMemberCount() const {
        assert(false);    // this cannot happen
        return 0;
    }
 
    bool passByReference(OUString const & name) const;
 
    bool canBeWarnUnused(OUString const & name) const;
    bool canBeWarnUnused(OUString const & name, int depth) const;
 
    OUString resolveOuterTypedefs(OUString const & name) const;
 
    OUString resolveAllTypedefs(std::u16string_view name) const;
 
    codemaker::cpp::IdentifierTranslationMode isGlobal() const;
 
    virtual void dumpDeclaration(FileStream &) {
        assert(false);    // this cannot happen
    }
 
    virtual void dumpFiles(OUString const & uri, CppuOptions const & options);
 
    virtual void addLightGetCppuTypeIncludes(
        codemaker::cppumaker::Includes & includes) const;
 
    virtual void addNormalGetCppuTypeIncludes(
        codemaker::cppumaker::Includes & includes) const;
 
    virtual void addComprehensiveGetCppuTypeIncludes(
        codemaker::cppumaker::Includes & includes) const;
 
    virtual bool isPolymorphic() const;
 
    virtual void dumpTemplateHead(FileStream &) const {}
 
    virtual void dumpTemplateParameters(FileStream &) const {}
 
    void dumpGetCppuTypePreamble(FileStream & out);
 
    void dumpGetCppuTypePostamble(FileStream & out);
 
    void addDefaultHIncludes(codemaker::cppumaker::Includes & includes) const;
    void addDefaultHxxIncludes(codemaker::cppumaker::Includes & includes) const;
 
    void dumpInitializer(
        FileStream & out, bool parameterized, std::u16string_view name) const;
 
    void dumpHFileContent(
        FileStream & out, codemaker::cppumaker::Includes & includes);
 
protected:
    sal_uInt32          m_inheritedMemberCount;
 
    bool                m_cppuTypeLeak;
    bool                m_cppuTypeDynamic;
    sal_Int32           m_indentLength;
    OUString name_;
    OUString id_;
    rtl::Reference< TypeManager > m_typeMgr;
    codemaker::cppumaker::Dependencies m_dependencies;
 
private:
    void addGetCppuTypeIncludes(codemaker::cppumaker::Includes & includes)
    const;
};
 
CppuType::CppuType(
    OUString name, rtl::Reference< TypeManager > const & typeMgr):
    m_inheritedMemberCount(0)
    , m_cppuTypeLeak(false)
    , m_cppuTypeDynamic(true)
    , m_indentLength(0)
    , name_(std::move(name))
    , id_(name_.copy(name_.lastIndexOf('.') + 1))
    , m_typeMgr(typeMgr)
    , m_dependencies(typeMgr, name_)
{}
 
void CppuType::addGetCppuTypeIncludes(codemaker::cppumaker::Includes & includes)
const
{
    if (name_ == "com.sun.star.uno.XInterface"
        || name_ == "com.sun.star.uno.Exception") {
        includes.addType();
        includes.addCppuUnotypeHxx();
        includes.addSalTypesH();
        includes.addTypelibTypeclassH();
        includes.addTypelibTypedescriptionH();
    } else if (m_cppuTypeLeak) {
        addLightGetCppuTypeIncludes(includes);
    } else if (m_cppuTypeDynamic) {
        addNormalGetCppuTypeIncludes(includes);
    } else {
        addComprehensiveGetCppuTypeIncludes(includes);
    }
}
 
void CppuType::dumpFiles(OUString const & uri, CppuOptions const & options)
{
    dumpFile(uri, name_, FileType::HDL, options);
    dumpFile(uri, name_, FileType::HPP, options);
}
 
void CppuType::addLightGetCppuTypeIncludes(
    codemaker::cppumaker::Includes & includes) const
{
    //TODO: Determine what is really needed, instead of relying on
    // addDefaultHxxIncludes
    includes.addCppuUnotypeHxx();
}
 
void CppuType::addNormalGetCppuTypeIncludes(
    codemaker::cppumaker::Includes & includes) const
{
    //TODO: Determine what is really needed, instead of relying on
    // addDefaultHxxIncludes
    includes.addCppuUnotypeHxx();
}
 
void CppuType::addComprehensiveGetCppuTypeIncludes(
    codemaker::cppumaker::Includes & includes) const
{
    //TODO: Determine what is really needed, instead of relying on
    // addDefaultHxxIncludes
    includes.addCppuUnotypeHxx();
}
 
bool CppuType::isPolymorphic() const
{
    return false;
}
 
void CppuType::dumpGetCppuTypePreamble(FileStream & out)
{
    if (isPolymorphic()) {
        out << "namespace cppu {\n\n";
        dumpTemplateHead(out);
        out << "class UnoType< ";
        dumpType(out, name_);
        dumpTemplateParameters(out);
        out << " > {\npublic:\n";
        inc();
        out << indent()
            << "static inline ::css::uno::Type const & get() {\n";
    } else {
        if (codemaker::cppumaker::dumpNamespaceOpen(out, name_, false)) {
            out << "\n\n";
        }
        out << ("inline ::css::uno::Type const &"
                " cppu_detail_getUnoType(SAL_UNUSED_PARAMETER ");
        dumpType(out, name_, false, false, true);
        out << " const *) {\n";
    }
    inc();
}
 
void CppuType::dumpGetCppuTypePostamble(FileStream & out)
{
    dec();
    if (isPolymorphic()) {
        out << indent() << "}\n\nprivate:\n"
            << indent() << "UnoType(UnoType &); // not defined\n"
            << indent() << "~UnoType(); // not defined\n"
            << indent()
            << "void operator =(UnoType); // not defined\n};\n\n}\n\n";
    } else {
        out << "}\n\n";
        if (codemaker::cppumaker::dumpNamespaceClose(out, name_, false)) {
            out << "\n\n";
        }
    }
    dumpTemplateHead(out);
    out << ("SAL_DEPRECATED(\"use cppu::UnoType\") inline ::css::uno::Type const & SAL_CALL"
            " getCppuType(SAL_UNUSED_PARAMETER ");
    dumpType(out, name_);
    dumpTemplateParameters(out);
    out << " const *) {\n";
    inc();
    out << indent() << "return ::cppu::UnoType< ";
    dumpType(out, name_);
    dumpTemplateParameters(out);
    out << " >::get();\n";
    dec();
    out << indent() << "}\n";
}
 
void CppuType::dump(CppuOptions const & options)
{
    if (isBootstrapType(name_)) {
        m_cppuTypeDynamic = false;
    } else {
        // -CS was used as an undocumented option to generate static getCppuType
        // functions; since the introduction of cppu::UnoType this no longer is
        // meaningful (getCppuType is just a forward to cppu::UnoType::get now),
        // and -CS is handled the same way as -C now:
        if (options.isValid("-L"_ostr))
            m_cppuTypeLeak = true;
        if (options.isValid("-C"_ostr) || options.isValid("-CS"_ostr))
            m_cppuTypeDynamic = false;
    }
    dumpFiles(
        options.isValid("-O"_ostr) ? b2u(options.getOption("-O"_ostr)) : u""_ustr, options);
}
 
void CppuType::dumpFile(
    std::u16string_view uri, std::u16string_view name, FileType eFileType,
    CppuOptions const & options)
{
    OUString fileUri(
        b2u(createFileNameFromType(
                u2b(uri), u2b(name), getFileExtension(eFileType))));
    if (fileUri.isEmpty()) {
        throw CannotDumpException(OUString::Concat("empty target URI for entity ") + name);
    }
    bool exists = fileExists(u2b(fileUri));
    if (exists && options.isValid("-G"_ostr)) {
        return;
    }
    FileStream out;
    out.createTempFile(getTempDir(u2b(fileUri)));
    OUString tmpUri(b2u(out.getName()));
    if(!out.isValid()) {
        throw CannotDumpException("cannot open " + tmpUri + " for writing");
    }
    codemaker::cppumaker::Includes includes(m_typeMgr, m_dependencies, eFileType);
    try {
        switch(eFileType)
        {
            case FileType::HPP:
                addGetCppuTypeIncludes(includes);
                dumpHppFile(out, includes);
                break;
            case FileType::HDL:
                dumpHdlFile(out, includes);
                break;
        }
    } catch (...) {
        out.close();
        // Remove existing type file if something goes wrong to ensure
        // consistency:
        if (fileExists(u2b(fileUri))) {
            removeTypeFile(u2b(fileUri));
        }
        removeTypeFile(u2b(tmpUri));
        throw;
    }
    out.close();
    (void)makeValidTypeFile(
               u2b(fileUri), u2b(tmpUri), exists && options.isValid("-Gc"_ostr));
}
 
void CppuType::dumpDependedTypes(
    codemaker::GeneratedTypeSet & generated, CppuOptions const & options) const
{
    if (!options.isValid("-nD"_ostr)) {
        codemaker::cppumaker::Dependencies::Map const & map
            = m_dependencies.getMap();
        for (const auto& entry : map) {
            produce(entry.first, m_typeMgr, generated, options);
        }
    }
}
 
OUString CppuType::dumpHeaderDefine(
    FileStream & out, std::u16string_view extension) const
{
    OUString def(
        "INCLUDED_" + name_.replace('.', '_').toAsciiUpperCase() + "_"
        + extension);
    out << "#ifndef " << def << "\n#define " << def << "\n";
    return def;
}
 
void CppuType::addDefaultHIncludes(codemaker::cppumaker::Includes & includes)
const
{
    //TODO: Only include what is really needed
    includes.addCppuMacrosHxx();
    if (m_typeMgr->getSort(name_)
        == codemaker::UnoType::Sort::Interface) {
        includes.addReference();
    }
}
 
void CppuType::addDefaultHxxIncludes(codemaker::cppumaker::Includes & includes)
const
{
    //TODO: Only include what is really needed
    includes.addType();
    if (m_typeMgr->getSort(name_)
        == codemaker::UnoType::Sort::Interface) {
        includes.addReference();
    }
}
 
void CppuType::dumpInitializer(
    FileStream & out, bool parameterized, std::u16string_view name) const
{
    out << "(";
    if (!parameterized) {
        sal_Int32 k;
        std::vector< OString > args;
        OUString n(
            b2u(codemaker::UnoType::decompose(
                    u2b(resolveAllTypedefs(name)), &k, &args)));
        if (k == 0) {
            rtl::Reference< unoidl::Entity > ent;
            switch (m_typeMgr->getSort(n, &ent)) {
            case codemaker::UnoType::Sort::Boolean:
                out << "false";
                break;
            case codemaker::UnoType::Sort::Byte:
            case codemaker::UnoType::Sort::Short:
            case codemaker::UnoType::Sort::UnsignedShort:
            case codemaker::UnoType::Sort::Long:
            case codemaker::UnoType::Sort::UnsignedLong:
            case codemaker::UnoType::Sort::Hyper:
            case codemaker::UnoType::Sort::UnsignedHyper:
            case codemaker::UnoType::Sort::Float:
            case codemaker::UnoType::Sort::Double:
            case codemaker::UnoType::Sort::Char:
                out << "0";
                break;
            case codemaker::UnoType::Sort::Enum:
                out << codemaker::cpp::scopedCppName(u2b(n)) << "_"
                    << (dynamic_cast<unoidl::EnumTypeEntity&>(*ent).
                        getMembers()[0].name);
                break;
            case codemaker::UnoType::Sort::String:
            case codemaker::UnoType::Sort::Type:
            case codemaker::UnoType::Sort::Any:
            case codemaker::UnoType::Sort::PlainStruct:
            case codemaker::UnoType::Sort::PolymorphicStructTemplate:
            case codemaker::UnoType::Sort::Interface:
                break;
            default:
                throw CannotDumpException(
                    OUString::Concat("unexpected entity \"") + name
                    + "\" in call to CppuType::dumpInitializer");
            }
        }
    }
    out << ")";
}
 
void CppuType::dumpHFileContent(
    FileStream & out, codemaker::cppumaker::Includes & includes)
{
    addDefaultHIncludes(includes);
    dumpHeaderDefine(out, u"HDL");
    out << "\n";
    includes.dump(out, nullptr, false);
        // 'exceptions = false' would be wrong for services/singletons, but
        // those don't dump .hdl files anyway
    out << ("\nnamespace com { namespace sun { namespace star { namespace uno"
            " { class Type; } } } }\n\n");
    if (codemaker::cppumaker::dumpNamespaceOpen(out, name_, false)) {
        out << "\n";
    }
    dumpDeclaration(out);
    if (!(name_ == "com.sun.star.uno.XInterface"
          || name_ == "com.sun.star.uno.Exception"
          || isPolymorphic())) {
        out << "\n" << indent()
            << ("inline ::css::uno::Type const &"
                " cppu_detail_getUnoType(SAL_UNUSED_PARAMETER ");
        dumpType(out, name_, false, false, true);
        out << " const *);\n";
    }
    if (codemaker::cppumaker::dumpNamespaceClose(out, name_, false)) {
        out << "\n";
    }
    out << "\n";
    dumpTemplateHead(out);
    out << "SAL_DEPRECATED(\"use cppu::UnoType\") inline ::css::uno::Type const & SAL_CALL getCppuType(";
    dumpType(out, name_, true);
    dumpTemplateParameters(out);
    out << " *);\n\n#endif\n";
}
 
void CppuType::dumpGetCppuType(FileStream & out)
{
    if (name_ == "com.sun.star.uno.XInterface") {
        out << indent()
            << ("SAL_DEPRECATED(\"use cppu::UnoType\") inline ::css::uno::Type const & SAL_CALL"
                " getCppuType(SAL_UNUSED_PARAMETER ");
        dumpType(out, name_, true);
        out << " *) {\n";
        inc();
        out << indent()
            << ("return ::cppu::UnoType< ::css::uno::XInterface"
                " >::get();\n");
        dec();
        out << indent() << "}\n";
    } else if (name_ == "com.sun.star.uno.Exception") {
        out << indent()
            << ("SAL_DEPRECATED(\"use cppu::UnoType\") inline ::css::uno::Type const & SAL_CALL"
                " getCppuType(SAL_UNUSED_PARAMETER ");
        dumpType(out, name_, true);
        out << " *) {\n";
        inc();
        out << indent()
            << ("return ::cppu::UnoType< ::css::uno::Exception"
                " >::get();\n");
        dec();
        out << indent() << "}\n";
    } else if (m_cppuTypeLeak) {
        dumpLightGetCppuType(out);
    } else if (m_cppuTypeDynamic) {
        dumpNormalGetCppuType(out);
    } else {
        dumpComprehensiveGetCppuType(out);
    }
}
 
void CppuType::dumpLightGetCppuType(FileStream & out)
{
    dumpGetCppuTypePreamble(out);
    out << indent()
        << "static typelib_TypeDescriptionReference * the_type = 0;\n"
        << indent() << "if ( !the_type )\n" << indent() << "{\n";
    inc();
    out << indent() << "typelib_static_type_init( &the_type, "
        << getTypeClass(name_, true) << ", \"" << name_ << "\" );\n";
    dec();
    out << indent() << "}\n" << indent()
        << ("return * reinterpret_cast< ::css::uno::Type * >("
            " &the_type );\n");
    dumpGetCppuTypePostamble(out);
}
 
codemaker::cpp::IdentifierTranslationMode CppuType::isGlobal() const
{
    return name_.indexOf('.') == -1
           ? codemaker::cpp::IdentifierTranslationMode::Global : codemaker::cpp::IdentifierTranslationMode::NonGlobal;
}
 
sal_uInt32 CppuType::getInheritedMemberCount()
{
    if (m_inheritedMemberCount == 0) {
        m_inheritedMemberCount = checkInheritedMemberCount();
    }
 
    return m_inheritedMemberCount;
}
 
OUString CppuType::getTypeClass(OUString const & name, bool cStyle)
{
    rtl::Reference< unoidl::Entity > ent;
    switch (m_typeMgr->getSort(name, &ent)) {
    case codemaker::UnoType::Sort::Void:
        return cStyle
               ? u"typelib_TypeClass_VOID"_ustr
               : u"::css::uno::TypeClass_VOID"_ustr;
    case codemaker::UnoType::Sort::Boolean:
        return cStyle
               ? u"typelib_TypeClass_BOOLEAN"_ustr
               : u"::css::uno::TypeClass_BOOLEAN"_ustr;
    case codemaker::UnoType::Sort::Byte:
        return cStyle
               ? u"typelib_TypeClass_BYTE"_ustr
               : u"::css::uno::TypeClass_BYTE"_ustr;
    case codemaker::UnoType::Sort::Short:
        return cStyle
               ? u"typelib_TypeClass_SHORT"_ustr
               : u"::css::uno::TypeClass_SHORT"_ustr;
    case codemaker::UnoType::Sort::UnsignedShort:
        return cStyle
               ? u"typelib_TypeClass_UNSIGNED_SHORT"_ustr
               : u"::css::uno::TypeClass_UNSIGNED_SHORT"_ustr;
    case codemaker::UnoType::Sort::Long:
        return cStyle
               ? u"typelib_TypeClass_LONG"_ustr
               : u"::css::uno::TypeClass_LONG"_ustr;
    case codemaker::UnoType::Sort::UnsignedLong:
        return cStyle
               ? u"typelib_TypeClass_UNSIGNED_LONG"_ustr
               : u"::css::uno::TypeClass_UNSIGNED_LONG"_ustr;
    case codemaker::UnoType::Sort::Hyper:
        return cStyle
               ? u"typelib_TypeClass_HYPER"_ustr
               : u"::css::uno::TypeClass_HYPER"_ustr;
    case codemaker::UnoType::Sort::UnsignedHyper:
        return cStyle
               ? u"typelib_TypeClass_UNSIGNED_HYPER"_ustr
               : u"::css::uno::TypeClass_UNSIGNED_HYPER"_ustr;
    case codemaker::UnoType::Sort::Float:
        return cStyle
               ? u"typelib_TypeClass_FLOAT"_ustr
               : u"::css::uno::TypeClass_FLOAT"_ustr;
    case codemaker::UnoType::Sort::Double:
        return cStyle
               ? u"typelib_TypeClass_DOUBLE"_ustr
               : u"::css::uno::TypeClass_DOUBLE"_ustr;
    case codemaker::UnoType::Sort::Char:
        return cStyle
               ? u"typelib_TypeClass_CHAR"_ustr
               : u"::css::uno::TypeClass_CHAR"_ustr;
    case codemaker::UnoType::Sort::String:
        return cStyle
               ? u"typelib_TypeClass_STRING"_ustr
               : u"::css::uno::TypeClass_STRING"_ustr;
    case codemaker::UnoType::Sort::Type:
        return cStyle
               ? u"typelib_TypeClass_TYPE"_ustr
               : u"::css::uno::TypeClass_TYPE"_ustr;
    case codemaker::UnoType::Sort::Any:
        return cStyle
               ? u"typelib_TypeClass_ANY"_ustr
               : u"::css::uno::TypeClass_ANY"_ustr;
    case codemaker::UnoType::Sort::Sequence:
        return cStyle
               ? u"typelib_TypeClass_SEQUENCE"_ustr
               : u"::css::uno::TypeClass_SEQUENCE"_ustr;
    case codemaker::UnoType::Sort::Enum:
        return cStyle
               ? u"typelib_TypeClass_ENUM"_ustr
               : u"::css::uno::TypeClass_ENUM"_ustr;
    case codemaker::UnoType::Sort::PlainStruct:
    case codemaker::UnoType::Sort::PolymorphicStructTemplate:
    case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct:
        return cStyle
               ? u"typelib_TypeClass_STRUCT"_ustr
               : u"::css::uno::TypeClass_STRUCT"_ustr;
    case codemaker::UnoType::Sort::Exception:
        return cStyle
               ? u"typelib_TypeClass_EXCEPTION"_ustr
               : u"::css::uno::TypeClass_EXCEPTION"_ustr;
    case codemaker::UnoType::Sort::Interface:
        return cStyle
               ? u"typelib_TypeClass_INTERFACE"_ustr
               : u"::css::uno::TypeClass_INTERFACE"_ustr;
    case codemaker::UnoType::Sort::Typedef:
        return getTypeClass(dynamic_cast<unoidl::TypedefEntity&>(*ent).getType(), cStyle);
    default:
        for (;;) {
            std::abort();
        }
    }
}
 
void CppuType::dumpType(
    FileStream & out, std::u16string_view name, bool isConst, bool isRef,
    bool native, bool cppuUnoType) const
{
    sal_Int32 k;
    std::vector< OString > args;
    OUString n(
        b2u(codemaker::UnoType::decompose(
                u2b(resolveAllTypedefs(name)), &k, &args)));
    if (isConst) {
        out << "const ";
    }
    for (sal_Int32 i = 0; i != k; ++i) {
        out << (cppuUnoType
                ? "::cppu::UnoSequenceType" : "::css::uno::Sequence")
            << "< ";
    }
    switch (m_typeMgr->getSort(n)) {
    case codemaker::UnoType::Sort::Void:
        out << "void";
        break;
    case codemaker::UnoType::Sort::Boolean:
        out << "::sal_Bool";
        break;
    case codemaker::UnoType::Sort::Byte:
        out << "::sal_Int8";
        break;
    case codemaker::UnoType::Sort::Short:
        out << "::sal_Int16";
        break;
    case codemaker::UnoType::Sort::UnsignedShort:
        out << (cppuUnoType ? "::cppu::UnoUnsignedShortType" : "::sal_uInt16");
        break;
    case codemaker::UnoType::Sort::Long:
        out << "::sal_Int32";
        break;
    case codemaker::UnoType::Sort::UnsignedLong:
        out << "::sal_uInt32";
        break;
    case codemaker::UnoType::Sort::Hyper:
        out << "::sal_Int64";
        break;
    case codemaker::UnoType::Sort::UnsignedHyper:
        out << "::sal_uInt64";
        break;
    case codemaker::UnoType::Sort::Float:
        out << "float";
        break;
    case codemaker::UnoType::Sort::Double:
        out << "double";
        break;
    case codemaker::UnoType::Sort::Char:
        out << (cppuUnoType ? "::cppu::UnoCharType" : "::sal_Unicode");
        break;
    case codemaker::UnoType::Sort::String:
        out << "::rtl::OUString";
        break;
    case codemaker::UnoType::Sort::Type:
        out << "::css::uno::Type";
        break;
    case codemaker::UnoType::Sort::Any:
        out << "::css::uno::Any";
        break;
    case codemaker::UnoType::Sort::Enum:
    case codemaker::UnoType::Sort::PlainStruct:
    case codemaker::UnoType::Sort::Exception:
        out << codemaker::cpp::scopedCppName(u2b(n));
        break;
    case codemaker::UnoType::Sort::PolymorphicStructTemplate:
        out << codemaker::cpp::scopedCppName(u2b(n));
        if (!args.empty()) {
            out << "< ";
            for (std::vector< OString >::iterator i(args.begin());
                 i != args.end(); ++i) {
                if (i != args.begin()) {
                    out << ", ";
                }
                dumpType(out, b2u(*i));
            }
            out << " >";
        }
        break;
    case codemaker::UnoType::Sort::Interface:
        if (!native) {
            out << "::css::uno::Reference< ";
        }
        out << codemaker::cpp::scopedCppName(u2b(n));
        if (!native) {
            out << " >";
        }
        break;
    default:
        throw CannotDumpException(
            OUString::Concat("unexpected entity \"") + name + "\" in call to CppuType::dumpType");
    }
    for (sal_Int32 i = 0; i != k; ++i) {
        out << " >";
    }
    if (isRef) {
        out << "&";
    }
}
 
void CppuType::dumpCppuGetType(
    FileStream & out, std::u16string_view name, OUString const * ownName) const
{
    //TODO: What are these calls good for?
    OUString nucleus;
    sal_Int32 rank;
    codemaker::UnoType::Sort sort = m_typeMgr->decompose(
                                        name, true, &nucleus, &rank, nullptr, nullptr);
    switch (rank == 0 ? sort : codemaker::UnoType::Sort::Sequence) {
    case codemaker::UnoType::Sort::Void:
    case codemaker::UnoType::Sort::Boolean:
    case codemaker::UnoType::Sort::Byte:
    case codemaker::UnoType::Sort::Short:
    case codemaker::UnoType::Sort::UnsignedShort:
    case codemaker::UnoType::Sort::Long:
    case codemaker::UnoType::Sort::UnsignedLong:
    case codemaker::UnoType::Sort::Hyper:
    case codemaker::UnoType::Sort::UnsignedHyper:
    case codemaker::UnoType::Sort::Float:
    case codemaker::UnoType::Sort::Double:
    case codemaker::UnoType::Sort::Char:
    case codemaker::UnoType::Sort::String:
    case codemaker::UnoType::Sort::Type:
    case codemaker::UnoType::Sort::Any:
        break;
    case codemaker::UnoType::Sort::Sequence:
    case codemaker::UnoType::Sort::Enum:
    case codemaker::UnoType::Sort::PlainStruct:
    case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct:
    case codemaker::UnoType::Sort::Exception:
    case codemaker::UnoType::Sort::Interface:
        // Take care of recursion like struct S { sequence<S> x; }:
        if (ownName == nullptr || nucleus != *ownName) {
            out << indent() << "::cppu::UnoType< ";
            dumpType(out, name, false, false, false, true);
            out << " >::get();\n";
        }
        break;
    case codemaker::UnoType::Sort::Typedef:
        for (;;) std::abort(); // this cannot happen
    default:
        throw CannotDumpException(
            OUString::Concat("unexpected entity \"") + name
            + "\" in call to CppuType::dumpCppuGetType");
    }
}
 
bool CppuType::passByReference(OUString const & name) const
{
    switch (m_typeMgr->getSort(resolveOuterTypedefs(name))) {
    case codemaker::UnoType::Sort::Boolean:
    case codemaker::UnoType::Sort::Byte:
    case codemaker::UnoType::Sort::Short:
    case codemaker::UnoType::Sort::UnsignedShort:
    case codemaker::UnoType::Sort::Long:
    case codemaker::UnoType::Sort::UnsignedLong:
    case codemaker::UnoType::Sort::Hyper:
    case codemaker::UnoType::Sort::UnsignedHyper:
    case codemaker::UnoType::Sort::Float:
    case codemaker::UnoType::Sort::Double:
    case codemaker::UnoType::Sort::Char:
    case codemaker::UnoType::Sort::Enum:
        return false;
    case codemaker::UnoType::Sort::String:
    case codemaker::UnoType::Sort::Type:
    case codemaker::UnoType::Sort::Any:
    case codemaker::UnoType::Sort::Sequence:
    case codemaker::UnoType::Sort::PlainStruct:
    case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct:
    case codemaker::UnoType::Sort::Interface:
        return true;
    default:
        throw CannotDumpException(
            "unexpected entity \"" + name
            + "\" in call to CppuType::passByReference");
    }
}
 
bool CppuType::canBeWarnUnused(OUString const & name) const
{
    return canBeWarnUnused(name, 0);
}
bool CppuType::canBeWarnUnused(OUString const & name, int depth) const
{
    // prevent infinite recursion and blowing the stack
    if (depth > 10)
        return false;
    OUString aResolvedName = resolveOuterTypedefs(name);
    switch (m_typeMgr->getSort(aResolvedName)) {
    case codemaker::UnoType::Sort::Boolean:
    case codemaker::UnoType::Sort::Byte:
    case codemaker::UnoType::Sort::Short:
    case codemaker::UnoType::Sort::UnsignedShort:
    case codemaker::UnoType::Sort::Long:
    case codemaker::UnoType::Sort::UnsignedLong:
    case codemaker::UnoType::Sort::Hyper:
    case codemaker::UnoType::Sort::UnsignedHyper:
    case codemaker::UnoType::Sort::Float:
    case codemaker::UnoType::Sort::Double:
    case codemaker::UnoType::Sort::Char:
    case codemaker::UnoType::Sort::Enum:
    case codemaker::UnoType::Sort::String:
    case codemaker::UnoType::Sort::Type:
        return true;
    case codemaker::UnoType::Sort::PlainStruct: {
        rtl::Reference< unoidl::Entity > ent;
        m_typeMgr->getSort(aResolvedName, &ent);
        rtl::Reference< unoidl::PlainStructTypeEntity > ent2(
            dynamic_cast< unoidl::PlainStructTypeEntity * >(ent.get()));
        if (!ent2->getDirectBase().isEmpty() && !canBeWarnUnused(ent2->getDirectBase(), depth+1))
            return false;
        for ( const unoidl::PlainStructTypeEntity::Member& rMember : ent2->getDirectMembers()) {
            if (!canBeWarnUnused(rMember.type, depth+1))
                return false;
        }
        return true;
    }
    case codemaker::UnoType::Sort::Sequence: {
        OUString aInnerType = aResolvedName.copy(2);
        return canBeWarnUnused(aInnerType, depth+1);
    }
    case codemaker::UnoType::Sort::Any:
    case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct:
    case codemaker::UnoType::Sort::Interface:
        return false;
    default:
        throw CannotDumpException(
            "unexpected entity \"" + name
            + "\" in call to CppuType::canBeWarnUnused");
    }
}
 
OUString CppuType::resolveOuterTypedefs(OUString const & name) const
{
    for (OUString n(name);;) {
        rtl::Reference< unoidl::Entity > ent;
        if (m_typeMgr->getSort(n, &ent) != codemaker::UnoType::Sort::Typedef) {
            return n;
        }
        n = dynamic_cast<unoidl::TypedefEntity&>(*ent).getType();
    }
}
 
OUString CppuType::resolveAllTypedefs(std::u16string_view name) const
{
    sal_Int32 k1;
    OUString n(b2u(codemaker::UnoType::decompose(u2b(name), &k1)));
    for (;;) {
        rtl::Reference< unoidl::Entity > ent;
        if (m_typeMgr->getSort(n, &ent) != codemaker::UnoType::Sort::Typedef) {
            break;
        }
        sal_Int32 k2;
        n = b2u(codemaker::UnoType::decompose(
            u2b(dynamic_cast<unoidl::TypedefEntity&>(*ent).getType()), &k2));
        k1 += k2; //TODO: overflow
    }
    OUStringBuffer b(k1*2 + n.getLength());
    for (sal_Int32 i = 0; i != k1; ++i) {
        b.append("[]");
    }
    b.append(n);
    return b.makeStringAndClear();
}
 
void CppuType::inc(sal_Int32 num)
{
    m_indentLength += num;
}
 
void CppuType::dec(sal_Int32 num)
{
    m_indentLength = std::max< sal_Int32 >(m_indentLength - num, 0);
}
 
OUString CppuType::indent() const
{
    OUStringBuffer buf(m_indentLength);
    for (sal_Int32 i = 0; i != m_indentLength; ++i) {
        buf.append(' ');
    }
    return buf.makeStringAndClear();
}
 
bool isDeprecated(std::vector< OUString > const & annotations)
{
    for (const OUString& r : annotations) {
        if (r == "deprecated") {
            return true;
        }
    }
    return false;
}
 
void dumpDeprecation(FileStream & out, bool deprecated)
{
    if (deprecated) {
        out << "SAL_DEPRECATED_INTERNAL(\"marked @deprecated in UNOIDL\") ";
    }
}
 
class BaseOffset
{
public:
    BaseOffset(
        rtl::Reference< TypeManager > manager,
        rtl::Reference< unoidl::InterfaceTypeEntity > const & entity):
        manager_(std::move(manager)), offset_(0) {
        calculateBases(entity);
    }
    BaseOffset(const BaseOffset&) = delete;
    const BaseOffset& operator=(const BaseOffset&) = delete;
 
    sal_Int32 get() const {
        return offset_;
    }
 
private:
    void calculateBases(
        rtl::Reference< unoidl::InterfaceTypeEntity > const & entity);
 
    rtl::Reference< TypeManager > manager_;
    std::set< OUString > set_;
    sal_Int32 offset_;
};
 
void BaseOffset::calculateBases(
    rtl::Reference< unoidl::InterfaceTypeEntity > const & entity)
{
    assert(entity.is());
    for (const unoidl::AnnotatedReference& ar : entity->getDirectMandatoryBases()) {
        if (set_.insert(ar.name).second) {
            rtl::Reference< unoidl::Entity > ent;
            codemaker::UnoType::Sort sort = manager_->getSort(ar.name, &ent);
            if (sort != codemaker::UnoType::Sort::Interface) {
                throw CannotDumpException(
                    "interface type base " + ar.name
                    + " is not an interface type");
            }
            rtl::Reference< unoidl::InterfaceTypeEntity > ent2(
                dynamic_cast< unoidl::InterfaceTypeEntity * >(ent.get()));
            assert(ent2.is());
            calculateBases(ent2);
            offset_ += ent2->getDirectAttributes().size()
                       + ent2->getDirectMethods().size(); //TODO: overflow
        }
    }
}
 
class InterfaceType: public CppuType
{
public:
    InterfaceType(
        rtl::Reference< unoidl::InterfaceTypeEntity > const & entity,
        OUString const & name, rtl::Reference< TypeManager > const & typeMgr);
 
    virtual void dumpDeclaration(FileStream& o) override;
    void dumpHppFile(FileStream& o, codemaker::cppumaker::Includes & includes) override;
 
    void        dumpAttributes(FileStream& o) const;
    void        dumpMethods(FileStream& o) const;
    void        dumpNormalGetCppuType(FileStream& o) override;
    void        dumpComprehensiveGetCppuType(FileStream& o) override;
    void        dumpCppuAttributeRefs(FileStream& o, sal_uInt32& index);
    void        dumpCppuMethodRefs(FileStream& o, sal_uInt32& index);
    void        dumpCppuAttributes(FileStream& o, sal_uInt32& index);
    void        dumpCppuMethods(FileStream& o, sal_uInt32& index);
    void dumpAttributesCppuDecl(FileStream & out, std::set< OUString > * seen) const;
    void dumpMethodsCppuDecl(FileStream & out, std::set< OUString > * seen) const;
 
private:
    virtual void addComprehensiveGetCppuTypeIncludes(
        codemaker::cppumaker::Includes & includes) const override;
 
    virtual sal_uInt32 checkInheritedMemberCount() const override {
        return BaseOffset(m_typeMgr, entity_).get();
    }
 
    void dumpExceptionTypeName(
        FileStream & out, std::u16string_view prefix, sal_uInt32 index,
        std::u16string_view name) const;
 
    sal_Int32 dumpExceptionTypeNames(
        FileStream & out, std::u16string_view prefix,
        std::vector< OUString > const & exceptions, bool runtimeException) const;
 
    rtl::Reference< unoidl::InterfaceTypeEntity > entity_;
    bool m_isDeprecated;
};
 
InterfaceType::InterfaceType(
    rtl::Reference< unoidl::InterfaceTypeEntity > const & entity,
    OUString const & name, rtl::Reference< TypeManager > const & typeMgr):
    CppuType(name, typeMgr), entity_(entity),
    m_isDeprecated(isDeprecated(entity->getAnnotations()))
{
    assert(entity.is());
}
 
void InterfaceType::dumpDeclaration(FileStream & out)
{
    out << "\nclass SAL_NO_VTABLE SAL_DLLPUBLIC_RTTI " << id_;
    for (std::vector< unoidl::AnnotatedReference >::const_iterator i(
             entity_->getDirectMandatoryBases().begin());
         i != entity_->getDirectMandatoryBases().end(); ++i) {
        out << (i == entity_->getDirectMandatoryBases().begin() ? " :" : ",")
            << " public " << codemaker::cpp::scopedCppName(u2b(i->name));
    }
    out << "\n{\npublic:\n";
    inc();
    out << "#if defined LIBO_INTERNAL_ONLY\n"
        << indent() << id_ << "() = default;\n"
        << indent() << id_ << "(" << id_ << " const &) = default;\n"
        << indent() << id_ << "(" << id_ << " &&) = default;\n"
        << indent() << id_ << " & operator =(" << id_ << " const &) = default;\n"
        << indent() << id_ << " & operator =(" << id_ << " &&) = default;\n#endif\n\n";
    dumpAttributes(out);
    dumpMethods(out);
    out << "\n" << indent()
        << ("static inline ::css::uno::Type const & SAL_CALL"
            " static_type(void * = 0);\n\n");
    dec();
    out << "protected:\n";
    inc();
    out << indent() << "~" << id_
        << ("() SAL_NOEXCEPT {} // avoid warnings about virtual members and"
            " non-virtual dtor\n");
    dec();
    out << "};\n\n";
}
 
void InterfaceType::dumpHppFile(
    FileStream & out, codemaker::cppumaker::Includes & includes)
{
    OUString headerDefine(dumpHeaderDefine(out, u"HPP"));
    out << "\n";
    addDefaultHxxIncludes(includes);
    includes.dump(out, &name_, !(m_cppuTypeLeak || m_cppuTypeDynamic));
    out << "\n#if defined LIBO_INTERNAL_ONLY\n#include <type_traits>\n#endif\n\n";
    dumpGetCppuType(out);
    out << "\n::css::uno::Type const & "
        << codemaker::cpp::scopedCppName(u2b(name_))
        << "::static_type(SAL_UNUSED_PARAMETER void *) {\n";
    inc();
    out << indent() << "return ::cppu::UnoType< ";
    dumpType(out, name_, false, false, true);
    out << " >::get();\n";
    dec();
    out << "}\n\n#if defined LIBO_INTERNAL_ONLY\nnamespace cppu::detail {\n";
    if (name_ == "com.sun.star.uno.XInterface") {
        out << "template<typename> struct IsUnoInterfaceType: ::std::false_type {};\n"
               "template<typename T> inline constexpr auto isUnoInterfaceType ="
                   " sizeof (T) && IsUnoInterfaceType<T>::value;\n";
    }
    out << "template<> struct IsUnoInterfaceType<";
    dumpType(out, name_, false, false, true);
    out << ">: ::std::true_type {};\n}\n#endif\n\n#endif // "<< headerDefine << "\n";
}
 
void InterfaceType::dumpAttributes(FileStream & out) const
{
    if (!entity_->getDirectAttributes().empty()) {
        out << "\n" << indent() << "// Attributes\n";
    }
    for (const unoidl::InterfaceTypeEntity::Attribute& attr : entity_->getDirectAttributes()) {
        bool depr = m_isDeprecated || isDeprecated(attr.annotations);
        out << indent();
        dumpDeprecation(out, depr);
        out << "virtual ";
        dumpType(out, attr.type);
        out << " SAL_CALL get" << attr.name << "() = 0;\n";
        if (!attr.readOnly) {
            bool byRef = passByReference(attr.type);
            out << indent();
            dumpDeprecation(out, depr);
            out << "virtual void SAL_CALL set" << attr.name << "( ";
            dumpType(out, attr.type, byRef, byRef);
            out << " _" << attr.name.toAsciiLowerCase() << " ) = 0;\n";
        }
    }
}
 
void InterfaceType::dumpMethods(FileStream & out) const
{
    if (!entity_->getDirectMethods().empty()) {
        out << "\n" << indent() << "// Methods\n";
    }
    for (const unoidl::InterfaceTypeEntity::Method& method : entity_->getDirectMethods()) {
        out << indent();
        dumpDeprecation(out, m_isDeprecated || isDeprecated(method.annotations));
        out << "virtual ";
        dumpType(out, method.returnType);
        out << " SAL_CALL " << method.name << "(";
        if (!method.parameters.empty()) {
            out << " ";
            for (std::vector< unoidl::InterfaceTypeEntity::Method::Parameter >::
                 const_iterator j(method.parameters.begin());
                 j != method.parameters.end();) {
                bool isConst;
                bool isRef;
                if (j->direction
                    == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN)
                {
                    isConst = passByReference(j->type);
                    isRef = isConst;
                } else {
                    isConst = false;
                    isRef = true;
                }
                dumpType(out, j->type, isConst, isRef);
                out << " " << j->name;
                ++j;
                if (j != method.parameters.end()) {
                    out << ", ";
                }
            }
            out << " ";
        }
        out << ") = 0;\n";
    }
}
 
void InterfaceType::dumpNormalGetCppuType(FileStream & out)
{
    dumpGetCppuTypePreamble(out);
    out << indent()
        << "static typelib_TypeDescriptionReference * the_type = 0;\n"
        << indent() << "if ( !the_type )\n" << indent() << "{\n";
    inc();
    std::vector< unoidl::AnnotatedReference >::size_type bases(
        entity_->getDirectMandatoryBases().size());
    if (bases == 1
        && (entity_->getDirectMandatoryBases()[0].name
            == "com.sun.star.uno.XInterface")) {
        bases = 0;
    }
    if (bases != 0) {
        out << indent() << "typelib_TypeDescriptionReference * aSuperTypes["
            << entity_->getDirectMandatoryBases().size() << "];\n";
        std::vector< unoidl::AnnotatedReference >::size_type n = 0;
        for (const unoidl::AnnotatedReference& ar : entity_->getDirectMandatoryBases()) {
            out << indent() << "aSuperTypes[" << n++ << "] = ::cppu::UnoType< ";
            dumpType(out, ar.name, true, false, false, true);
            out << " >::get().getTypeLibType();\n";
        }
    }
    out << indent() << "typelib_static_mi_interface_type_init( &the_type, \""
        << name_ << "\", " << bases << ", "
        << (bases == 0 ? "0" : "aSuperTypes") << " );\n";
    dec();
    out << indent() << "}\n" << indent()
        << ("return * reinterpret_cast< ::css::uno::Type * >("
            " &the_type );\n");
    dumpGetCppuTypePostamble(out);
}
 
void InterfaceType::dumpComprehensiveGetCppuType(FileStream & out)
{
    codemaker::cppumaker::dumpNamespaceOpen(out, name_, false);
    OUString staticTypeClass("the" + id_ + "Type");
    out << " namespace detail {\n\n" << indent() << "struct " << staticTypeClass
        << " : public rtl::StaticWithInit< ::css::uno::Type *, "
        << staticTypeClass << " >\n" << indent() << "{\n";
    inc();
    out << indent() << "::css::uno::Type * operator()() const\n"
        << indent() << "{\n";
    inc();
    out << indent() << "::rtl::OUString sTypeName( \"" << name_ << "\" );\n\n"
        << indent() << "// Start inline typedescription generation\n"
        << indent() << "typelib_InterfaceTypeDescription * pTD = 0;\n\n";
    out << indent() << "typelib_TypeDescriptionReference * aSuperTypes["
        << entity_->getDirectMandatoryBases().size() << "];\n";
    std::vector< unoidl::AnnotatedReference >::size_type n = 0;
    for (const unoidl::AnnotatedReference& ar : entity_->getDirectMandatoryBases()) {
        out << indent() << "aSuperTypes[" << n++ << "] = ::cppu::UnoType< ";
        dumpType(out, ar.name, false, false, false, true);
        out << " >::get().getTypeLibType();\n";
    }
    std::size_t count = entity_->getDirectAttributes().size()
                        + entity_->getDirectMethods().size(); //TODO: overflow
    if (count != 0) {
        out << indent() << "typelib_TypeDescriptionReference * pMembers["
            << count << "] = { ";
        for (std::size_t i = 0; i != count; ++i) {
            out << "0";
            if (i + 1 != count) {
                out << ",";
            }
        }
        out << " };\n";
        sal_uInt32 index = 0;
        dumpCppuAttributeRefs(out, index);
        dumpCppuMethodRefs(out, index);
    }
    out << "\n" << indent() << "typelib_typedescription_newMIInterface(\n";
    inc();
    out << indent() << "&pTD,\n" << indent()
        << "sTypeName.pData, 0, 0, 0, 0, 0,\n" << indent()
        << entity_->getDirectMandatoryBases().size() << ", aSuperTypes,\n"
        << indent() << count << ",\n" << indent()
        << (count == 0 ? "0" : "pMembers") << " );\n\n";
    dec();
    out << indent()
        << ("typelib_typedescription_register( (typelib_TypeDescription**)&pTD"
            " );\n");
    for (std::size_t i = 0; i != count; ++i) {
        out << indent() << "typelib_typedescriptionreference_release( pMembers["
            << i << "] );\n";
    }
    out << indent()
        << ("typelib_typedescription_release( (typelib_TypeDescription*)pTD"
            " );\n\n")
        << indent() << "return new ::css::uno::Type( "
        << getTypeClass(name_) << ", sTypeName ); // leaked\n";
    dec();
    out << indent() << "}\n";
    dec();
    out << indent() << "};\n\n";
    codemaker::cppumaker::dumpNamespaceClose(out, name_, false);
    out << " }\n\n";
    dumpGetCppuTypePreamble(out);
    out << indent() << "const ::css::uno::Type &rRet = *detail::"
        << staticTypeClass << "::get();\n" << indent()
        << "// End inline typedescription generation\n" << indent()
        << "static bool bInitStarted = false;\n" << indent()
        << "if (!bInitStarted)\n" << indent() << "{\n";
    inc();
    out << indent()
        << "::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );\n"
        << indent() << "if (!bInitStarted)\n" << indent() << "{\n";
    inc();
    out << indent() << "OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();\n"
        << indent() << "bInitStarted = true;\n";
    std::set< OUString > seen;
    // Type for RuntimeException is always needed:
    seen.insert(u"com.sun.star.uno.RuntimeException"_ustr);
    dumpCppuGetType(out, u"com.sun.star.uno.RuntimeException");
    dumpAttributesCppuDecl(out, &seen);
    dumpMethodsCppuDecl(out, &seen);
    if (count != 0) {
        sal_uInt32 index = getInheritedMemberCount();
        dumpCppuAttributes(out, index);
        dumpCppuMethods(out, index);
    }
    dec();
    out << indent() << "}\n";
    dec();
    out << indent() << "}\n" << indent() << "else\n" << indent() << "{\n";
    inc();
    out << indent() << "OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();\n";
    dec();
    out << indent() << "}\n" << indent() << "return rRet;\n";
    dumpGetCppuTypePostamble(out);
}
 
void InterfaceType::dumpCppuAttributeRefs(FileStream & out, sal_uInt32 & index)
{
    std::vector< unoidl::InterfaceTypeEntity::Attribute >::size_type n = 0;
    for (const unoidl::InterfaceTypeEntity::Attribute& attr : entity_->getDirectAttributes()) {
        out << indent() << "::rtl::OUString sAttributeName" << n << "( \""
            << name_ << "::" << attr.name << "\" );\n" << indent()
            << "typelib_typedescriptionreference_new( &pMembers[" << index++
            << "],\n";
        inc(38);
        out << indent()
            << "(typelib_TypeClass)::css::uno::TypeClass_INTERFACE_ATTRIBUTE,\n"
            << indent() << "sAttributeName" << n << ".pData );\n";
        dec(38);
        ++n;
    }
}
 
void InterfaceType::dumpCppuMethodRefs(FileStream & out, sal_uInt32 & index)
{
    std::vector< unoidl::InterfaceTypeEntity::Method >::size_type n = 0;
    for (const unoidl::InterfaceTypeEntity::Method& method : entity_->getDirectMethods()) {
        out << indent() << "::rtl::OUString sMethodName" << n << "( \"" << name_
            << "::" << method.name << "\" );\n" << indent()
            << "typelib_typedescriptionreference_new( &pMembers[" << index++
            << "],\n";
        inc(38);
        out << indent()
            << "(typelib_TypeClass)::css::uno::TypeClass_INTERFACE_METHOD,\n"
            << indent() << "sMethodName" << n << ".pData );\n";
        dec(38);
        ++n;
    }
}
 
void InterfaceType::addComprehensiveGetCppuTypeIncludes(
    codemaker::cppumaker::Includes & includes) const
{
    // The comprehensive getCppuType method always includes a line
    // "getCppuType( (const ::css::uno::RuntimeException*)0 );":
    includes.addCppuUnotypeHxx();
    includes.addRtlInstanceHxx(); // using rtl::StaticWithInit
    includes.addOslMutexHxx();
    includes.add("com.sun.star.uno.RuntimeException"_ostr);
}
 
void InterfaceType::dumpCppuAttributes(FileStream & out, sal_uInt32 & index)
{
    if (entity_->getDirectAttributes().empty())
        return;
 
    out << "\n" << indent()
        << "typelib_InterfaceAttributeTypeDescription * pAttribute = 0;\n";
    std::vector< unoidl::InterfaceTypeEntity::Attribute >::size_type n = 0;
    for (const unoidl::InterfaceTypeEntity::Attribute& attr : entity_->getDirectAttributes()) {
        OUString type(resolveAllTypedefs(attr.type));
        out << indent() << "{\n";
        inc();
        out << indent() << "::rtl::OUString sAttributeType" << n << "( \""
            << type << "\" );\n" << indent()
            << "::rtl::OUString sAttributeName" << n << "( \"" << name_
            << "::" << attr.name << "\" );\n";
        sal_Int32 getExcn = dumpExceptionTypeNames(
                                out, u"get", attr.getExceptions, false);
        sal_Int32 setExcn = dumpExceptionTypeNames(
                                out, u"set", attr.setExceptions, false);
        out << indent()
            << ("typelib_typedescription_newExtendedInterfaceAttribute("
                " &pAttribute,\n");
        inc();
        out << indent() << index++ << ", sAttributeName" << n
            << ".pData,\n" << indent() << "(typelib_TypeClass)"
            << getTypeClass(type) << ", sAttributeType" << n << ".pData,\n"
            << indent() << "sal_" << (attr.readOnly ? "True" : "False")
            << ", " << getExcn << ", "
            << (getExcn == 0 ? "0" : "the_getExceptions") << ", " << setExcn
            << ", " << (setExcn == 0 ? "0" : "the_setExceptions")
            << " );\n";
        dec();
        out << indent()
            << ("typelib_typedescription_register("
                " (typelib_TypeDescription**)&pAttribute );\n");
        dec();
        out << indent() << "}\n";
        ++n;
    }
    out << indent()
        << ("typelib_typedescription_release("
            " (typelib_TypeDescription*)pAttribute );\n");
}
 
void InterfaceType::dumpCppuMethods(FileStream & out, sal_uInt32 & index)
{
    if (entity_->getDirectMethods().empty())
        return;
 
    out << "\n" << indent()
        << "typelib_InterfaceMethodTypeDescription * pMethod = 0;\n";
    std::vector< unoidl::InterfaceTypeEntity::Method >::size_type n = 0;
    for (const unoidl::InterfaceTypeEntity::Method& method : entity_->getDirectMethods()) {
        OUString returnType(resolveAllTypedefs(method.returnType));
        out << indent() << "{\n";
        inc();
        if (!method.parameters.empty()) {
            out << indent() << "typelib_Parameter_Init aParameters["
                << method.parameters.size() << "];\n";
        }
        std::vector< unoidl::InterfaceTypeEntity::Method::Parameter >::
        size_type m = 0;
        for (const unoidl::InterfaceTypeEntity::Method::Parameter& param : method.parameters) {
            OUString type(resolveAllTypedefs(param.type));
            out << indent() << "::rtl::OUString sParamName" << m << "( \""
                << param.name << "\" );\n" << indent()
                << "::rtl::OUString sParamType" << m << "( \"" << type
                << "\" );\n" << indent() << "aParameters[" << m
                << "].pParamName = sParamName" << m << ".pData;\n"
                << indent() << "aParameters[" << m
                << "].eTypeClass = (typelib_TypeClass)"
                << getTypeClass(type) << ";\n" << indent() << "aParameters["
                << m << "].pTypeName = sParamType" << m << ".pData;\n"
                << indent() << "aParameters[" << m << "].bIn = "
                << ((param.direction
                     == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_OUT)
                    ? "sal_False" : "sal_True")
                << ";\n" << indent() << "aParameters[" << m << "].bOut = "
                << ((param.direction
                     == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN)
                    ? "sal_False" : "sal_True")
                << ";\n";
            ++m;
        }
        sal_Int32 excn = dumpExceptionTypeNames(
                             out, u"", method.exceptions,
                             method.name != "acquire" && method.name != "release");
        out << indent() << "::rtl::OUString sReturnType" << n << "( \""
            << returnType << "\" );\n" << indent()
            << "::rtl::OUString sMethodName" << n << "( \"" << name_ << "::"
            << method.name << "\" );\n" << indent()
            << "typelib_typedescription_newInterfaceMethod( &pMethod,\n";
        inc();
        out << indent() << index++ << ", sal_False,\n" << indent()
            << "sMethodName" << n << ".pData,\n" << indent()
            << "(typelib_TypeClass)" << getTypeClass(returnType)
            << ", sReturnType" << n << ".pData,\n" << indent()
            << method.parameters.size() << ", "
            << (method.parameters.empty() ? "0" : "aParameters") << ",\n"
            << indent() << excn << ", "
            << (excn == 0 ? "0" : "the_Exceptions") << " );\n";
        dec();
        out << indent()
            << ("typelib_typedescription_register("
                " (typelib_TypeDescription**)&pMethod );\n");
        dec();
        out << indent() << "}\n";
        ++n;
    }
    out << indent()
        << ("typelib_typedescription_release("
            " (typelib_TypeDescription*)pMethod );\n");
}
 
void InterfaceType::dumpAttributesCppuDecl(
    FileStream & out, std::set< OUString > * seen) const
{
    assert(seen != nullptr);
    for (const unoidl::InterfaceTypeEntity::Attribute& attr : entity_->getDirectAttributes()) {
        if (seen->insert(attr.type).second) {
            dumpCppuGetType(out, attr.type);
        }
        for (const OUString& exc : attr.getExceptions) {
            if (seen->insert(exc).second) {
                dumpCppuGetType(out, exc);
            }
        }
        for (const OUString& exc : attr.setExceptions) {
            if (seen->insert(exc).second) {
                dumpCppuGetType(out, exc);
            }
        }
    }
}
 
void InterfaceType::dumpMethodsCppuDecl(
    FileStream & out, std::set< OUString > * seen) const
{
    assert(seen != nullptr);
    for (const unoidl::InterfaceTypeEntity::Method& method : entity_->getDirectMethods()) {
        for (const OUString& ex : method.exceptions) {
            if (seen->insert(ex).second) {
                dumpCppuGetType(out, ex);
            }
        }
    }
}
 
void InterfaceType::dumpExceptionTypeName(
    FileStream & out, std::u16string_view prefix, sal_uInt32 index,
    std::u16string_view name) const
{
    out << indent() << "::rtl::OUString the_" << prefix << "ExceptionName"
        << index << "( \"" << name << "\" );\n";
}
 
sal_Int32 InterfaceType::dumpExceptionTypeNames(
    FileStream & out, std::u16string_view prefix,
    std::vector< OUString > const & exceptions, bool runtimeException) const
{
    sal_Int32 count = 0;
    for (const OUString& ex : exceptions) {
        if (ex != "com.sun.star.uno.RuntimeException") {
            dumpExceptionTypeName(out, prefix, count++, ex);
        }
    }
    if (runtimeException) {
        dumpExceptionTypeName(
            out, prefix, count++, u"com.sun.star.uno.RuntimeException");
    }
    if (count != 0) {
        out << indent() << "rtl_uString * the_" << prefix << "Exceptions[] = {";
        for (sal_Int32 i = 0; i != count; ++i) {
            out << (i == 0 ? " " : ", ") << "the_" << prefix << "ExceptionName"
                << i << ".pData";
        }
        out << " };\n";
    }
    return count;
}
 
class ConstantGroup: public CppuType
{
public:
    ConstantGroup(
        rtl::Reference< unoidl::ConstantGroupEntity > const & entity,
        OUString const & name, rtl::Reference< TypeManager > const & typeMgr):
        CppuType(name, typeMgr), entity_(entity) {
        assert(entity.is());
    }
 
    bool hasConstants() const {
        return !entity_->getMembers().empty();
    }
 
private:
    virtual void dumpHdlFile(
        FileStream & out, codemaker::cppumaker::Includes & includes) override;
 
    virtual void dumpHppFile(
        FileStream & out, codemaker::cppumaker::Includes & includes) override;
 
    virtual void dumpDeclaration(FileStream & out) override;
 
    rtl::Reference< unoidl::ConstantGroupEntity > entity_;
};
 
void ConstantGroup::dumpHdlFile(
    FileStream & out, codemaker::cppumaker::Includes & includes)
{
    OUString headerDefine(dumpHeaderDefine(out, u"HDL"));
    out << "\n";
    addDefaultHIncludes(includes);
    includes.dump(out, nullptr, true);
    out << "\n";
    if (codemaker::cppumaker::dumpNamespaceOpen(out, name_, true)) {
        out << "\n";
    }
    out << "\n";
    dumpDeclaration(out);
    out << "\n";
    if (codemaker::cppumaker::dumpNamespaceClose(out, name_, true)) {
        out << "\n";
    }
    out << "\n#endif // "<< headerDefine << "\n";
}
 
void ConstantGroup::dumpHppFile(
    FileStream & out, codemaker::cppumaker::Includes &)
{
    OUString headerDefine(dumpHeaderDefine(out, u"HPP"));
    out << "\n";
    codemaker::cppumaker::Includes::dumpInclude(out, u2b(name_), false);
    out << "\n#endif // "<< headerDefine << "\n";
}
 
void ConstantGroup::dumpDeclaration(FileStream & out)
{
    for (const unoidl::ConstantGroupEntity::Member& member : entity_->getMembers()) {
        out << "static const ";
        switch (member.value.type) {
        case unoidl::ConstantValue::TYPE_BOOLEAN:
            out << "::sal_Bool";
            break;
        case unoidl::ConstantValue::TYPE_BYTE:
            out << "::sal_Int8";
            break;
        case unoidl::ConstantValue::TYPE_SHORT:
            out << "::sal_Int16";
            break;
        case unoidl::ConstantValue::TYPE_UNSIGNED_SHORT:
            out << "::sal_uInt16";
            break;
        case unoidl::ConstantValue::TYPE_LONG:
            out << "::sal_Int32";
            break;
        case unoidl::ConstantValue::TYPE_UNSIGNED_LONG:
            out << "::sal_uInt32";
            break;
        case unoidl::ConstantValue::TYPE_HYPER:
            out << "::sal_Int64";
            break;
        case unoidl::ConstantValue::TYPE_UNSIGNED_HYPER:
            out << "::sal_uInt64";
            break;
        case unoidl::ConstantValue::TYPE_FLOAT:
            out << "float";
            break;
        case unoidl::ConstantValue::TYPE_DOUBLE:
            out << "double";
            break;
        }
        out << " "
            << codemaker::cpp::translateUnoToCppIdentifier(
                u2b(member.name), "constant",
                codemaker::cpp::IdentifierTranslationMode::KeywordsOnly)
            << " = ";
        switch (member.value.type) {
        case unoidl::ConstantValue::TYPE_BOOLEAN:
            out << (member.value.booleanValue ? "sal_True" : "sal_False");
            break;
        case unoidl::ConstantValue::TYPE_BYTE:
            out << "(sal_Int8)" << OUString::number(member.value.byteValue);
            break;
        case unoidl::ConstantValue::TYPE_SHORT:
            out << "(sal_Int16)" << OUString::number(member.value.shortValue);
            break;
        case unoidl::ConstantValue::TYPE_UNSIGNED_SHORT:
            out << "(sal_uInt16)"
                << OUString::number(member.value.unsignedShortValue);
            break;
        case unoidl::ConstantValue::TYPE_LONG:
            // Avoid C++ compiler warnings about (un)signedness of literal
            // -2^31:
            if (member.value.longValue == SAL_MIN_INT32) {
                out << "SAL_MIN_INT32";
            } else {
                out << "(sal_Int32)" << OUString::number(member.value.longValue);
            }
            break;
        case unoidl::ConstantValue::TYPE_UNSIGNED_LONG:
            out << "(sal_uInt32)"
                << OUString::number(member.value.unsignedLongValue) << "U";
            break;
        case unoidl::ConstantValue::TYPE_HYPER:
            // Avoid C++ compiler warnings about (un)signedness of literal
            // -2^63:
            if (member.value.hyperValue == SAL_MIN_INT64) {
                out << "SAL_MIN_INT64";
            } else {
                out << "(sal_Int64) SAL_CONST_INT64("
                    << OUString::number(member.value.hyperValue) << ")";
            }
            break;
        case unoidl::ConstantValue::TYPE_UNSIGNED_HYPER:
            out << "SAL_CONST_UINT64("
                << OUString::number(member.value.unsignedHyperValue) << ")";
            break;
        case unoidl::ConstantValue::TYPE_FLOAT:
            out << "(float)" << OUString::number(member.value.floatValue);
            break;
        case unoidl::ConstantValue::TYPE_DOUBLE:
            out << "(double)" << OUString::number(member.value.doubleValue);
            break;
        }
        out << ";\n";
    }
}
 
void dumpTypeParameterName(FileStream & out, std::u16string_view name)
{
    // Prefix all type parameters with "typeparam_" to avoid problems when a
    // struct member has the same name as a type parameter, as in
    // struct<T> { T T; };
    out << "typeparam_" << name;
}
 
class PlainStructType: public CppuType
{
public:
    PlainStructType(
        rtl::Reference< unoidl::PlainStructTypeEntity > const & entity,
        OUString const & name, rtl::Reference< TypeManager > const & typeMgr):
        CppuType(name, typeMgr), entity_(entity) {
        assert(entity.is());
    }
 
private:
    virtual sal_uInt32 checkInheritedMemberCount() const override {
        return getTotalMemberCount(entity_->getDirectBase());
    }
 
    virtual void dumpDeclaration(FileStream& o) override;
 
    void dumpHppFile(FileStream& o, codemaker::cppumaker::Includes & includes) override;
 
    virtual void dumpLightGetCppuType(FileStream & out) override;
 
    virtual void dumpNormalGetCppuType(FileStream & out) override;
 
    virtual void dumpComprehensiveGetCppuType(FileStream & out) override;
 
    virtual void addLightGetCppuTypeIncludes(
        codemaker::cppumaker::Includes & includes) const override;
 
    virtual void addNormalGetCppuTypeIncludes(
        codemaker::cppumaker::Includes & includes) const override;
 
    virtual void addComprehensiveGetCppuTypeIncludes(
        codemaker::cppumaker::Includes & includes) const override;
 
    bool dumpBaseMembers(
        FileStream & out, OUString const & base, bool withType);
 
    sal_uInt32 getTotalMemberCount(OUString const & base) const;
 
    rtl::Reference< unoidl::PlainStructTypeEntity > entity_;
};
 
void PlainStructType::dumpDeclaration(FileStream & out)
{
    out << "\n#ifdef _WIN32\n#   pragma pack(push, 8)\n#endif\n\n" << indent();
    out << "struct SAL_DLLPUBLIC_RTTI ";
    if (canBeWarnUnused(name_))
        out << "SAL_WARN_UNUSED ";
    out << id_;
    OUString base(entity_->getDirectBase());
    if (!base.isEmpty()) {
        out << ": public " << codemaker::cpp::scopedCppName(u2b(base));
    }
    out << " {\n";
    inc();
    out << indent() << "inline " << id_ << "();\n";
    if (!entity_->getDirectMembers().empty() || getInheritedMemberCount() > 0) {
        out << "\n" << indent() << "inline " << id_ << "(";
        bool bFirst = !dumpBaseMembers(out, base, true);
        for (const unoidl::PlainStructTypeEntity::Member& member : entity_->getDirectMembers()) {
            if (!bFirst) {
                out << ", ";
            }
            dumpType(out, member.type, true, true);
            out << " " << member.name << "_";
            bFirst = false;
        }
        out << ");\n";
    }
    if (!entity_->getDirectMembers().empty()) {
        out << "\n";
        for (std::vector< unoidl::PlainStructTypeEntity::Member >::
             const_iterator i(entity_->getDirectMembers().begin());
             i != entity_->getDirectMembers().end(); ++i) {
            out << indent();
            dumpType(out, i->type);
            out << " " << i->name;
            if (i == entity_->getDirectMembers().begin() && !base.isEmpty()
                && i->type != "hyper" && i->type != "unsigned hyper"
                && i->type != "double") {
                out << " CPPU_GCC3_ALIGN("
                    << codemaker::cpp::scopedCppName(u2b(base)) << ")";
            }
            out << ";\n";
        }
    }
    dec();
    out << "};\n\n#ifdef _WIN32\n#   pragma pack(pop)\n#endif\n\n";
}
 
void PlainStructType::dumpHppFile(
    FileStream & out, codemaker::cppumaker::Includes & includes)
{
    OUString headerDefine(dumpHeaderDefine(out, u"HPP"));
    out << "\n";
    includes.dump(out, &name_, true);
    out << "\n";
    if (codemaker::cppumaker::dumpNamespaceOpen(out, name_, false)) {
        out << "\n";
    }
    out << "\ninline " << id_ << "::" << id_ << "()\n";
    inc();
    OUString base(entity_->getDirectBase());
    bool bFirst = true;
    if (!base.isEmpty()) {
        out << indent() << ": " << codemaker::cpp::scopedCppName(u2b(base))
            << "()\n";
        bFirst = false;
    }
    for (const unoidl::PlainStructTypeEntity::Member& member : entity_->getDirectMembers()) {
        out << indent() << (bFirst ? ":" : ",") << " " << member.name;
        dumpInitializer(out, false, member.type);
        out << "\n";
        bFirst = false;
    }
    dec();
    out << "{\n}\n\n";
    if (!entity_->getDirectMembers().empty() || getInheritedMemberCount() > 0) {
        out << "inline " << id_;
        out << "::" << id_ << "(";
        bFirst = !dumpBaseMembers(out, base, true);
        for (const unoidl::PlainStructTypeEntity::Member& member : entity_->getDirectMembers()) {
            if (!bFirst) {
                out << ", ";
            }
            dumpType(out, member.type, true, true);
            out << " " << member.name << "_";
            bFirst = false;
        }
        out << ")\n";
        inc();
        bFirst = true;
        if (!base.isEmpty()) {
            out << indent() << ": " << codemaker::cpp::scopedCppName(u2b(base))
                << "(";
            dumpBaseMembers(out, base, false);
            out << ")\n";
            bFirst = false;
        }
        for (const unoidl::PlainStructTypeEntity::Member& member : entity_->getDirectMembers()) {
            out << indent() << (bFirst ? ":" : ",") << " " << member.name << "("
                << member.name << "_)\n";
            bFirst = false;
        }
        dec();
        out << "{\n}\n\n";
    }
    // print the operator==
    out << "\ninline bool operator==(const " << id_ << "& the_lhs, const " << id_ << "& the_rhs)\n";
    out << "{\n";
    inc();
    out << indent() << "return ";
    bFirst = true;
    if (!base.isEmpty()) {
        out << "operator==( static_cast<const " << codemaker::cpp::scopedCppName(u2b(base))
            << "&>(the_lhs), static_cast<const " << codemaker::cpp::scopedCppName(u2b(base)) << "&>(the_rhs) )\n";
        bFirst = false;
    }
    for (const unoidl::PlainStructTypeEntity::Member& member : entity_->getDirectMembers()) {
        if (!bFirst)
            out << "\n" << indent() << indent() << "&& ";
        out << "the_lhs." << member.name << " == the_rhs." << member.name;
        bFirst = false;
    }
    out << ";\n";
    dec();
    out << "}\n";
    // print the operator!=
    out << "\ninline bool operator!=(const " << id_ << "& the_lhs, const " << id_ << "& the_rhs)\n";
    out << "{\n";
    out << indent() << "return !operator==(the_lhs, the_rhs);\n";
    out << "}\n";
    // close namespace
    if (codemaker::cppumaker::dumpNamespaceClose(out, name_, false)) {
        out << "\n";
    }
    out << "\n";
    dumpGetCppuType(out);
    out << "\n#endif // "<< headerDefine << "\n";
}
 
void PlainStructType::dumpLightGetCppuType(FileStream & out)
{
    dumpGetCppuTypePreamble(out);
    out << indent()
        << ("//TODO: On certain platforms with weak memory models, the"
            " following code can result in some threads observing that the_type"
            " points to garbage\n")
        << indent()
        << "static ::typelib_TypeDescriptionReference * the_type = 0;\n"
        << indent() << "if (the_type == 0) {\n";
    inc();
    out << indent() << "::typelib_static_type_init(&the_type, "
        << getTypeClass(name_, true) << ", \"" << name_ << "\");\n";
    dec();
    out << indent() << "}\n" << indent()
        << "return *reinterpret_cast< ::css::uno::Type * >(&the_type);\n";
    dumpGetCppuTypePostamble(out);
}
 
void PlainStructType::dumpNormalGetCppuType(FileStream & out)
{
    dumpGetCppuTypePreamble(out);
    out << indent()
        << ("//TODO: On certain platforms with weak memory models, the"
            " following code can result in some threads observing that the_type"
            " points to garbage\n")
        << indent()
        << "static ::typelib_TypeDescriptionReference * the_type = 0;\n"
        << indent() << "if (the_type == 0) {\n";
    inc();
    out << indent()
        << "::typelib_TypeDescriptionReference * the_members[] = {\n";
    inc();
    for (std::vector< unoidl::PlainStructTypeEntity::Member >::const_iterator i(
             entity_->getDirectMembers().begin());
         i != entity_->getDirectMembers().end();) {
        out << indent() << "::cppu::UnoType< ";
        dumpType(out, i->type, false, false, false, true);
        ++i;
        out << " >::get().getTypeLibType()"
            << (i == entity_->getDirectMembers().end() ? " };" : ",") << "\n";
    }
    dec();
    out << indent() << "::typelib_static_struct_type_init(&the_type, \""
        << name_ << "\", ";
    if (entity_->getDirectBase().isEmpty()) {
        out << "0";
    } else {
        out << "::cppu::UnoType< ";
        dumpType(out, entity_->getDirectBase(), false, false, false, true);
        out << " >::get().getTypeLibType()";
    }
    out << ", " << entity_->getDirectMembers().size() << ", the_members, 0);\n";
    dec();
    out << indent() << "}\n" << indent()
        << "return *reinterpret_cast< ::css::uno::Type * >(&the_type);\n";
    dumpGetCppuTypePostamble(out);
}
 
void PlainStructType::dumpComprehensiveGetCppuType(FileStream & out)
{
    OUString staticTypeClass("the" + id_ + "Type");
    codemaker::cppumaker::dumpNamespaceOpen(out, name_, false);
    out << " namespace detail {\n\n" << indent() << "struct "
        << staticTypeClass
        << " : public rtl::StaticWithInit< ::css::uno::Type *, "
        << staticTypeClass << " >\n" << indent() << "{\n";
    inc();
    out << indent() << "::css::uno::Type * operator()() const\n"
        << indent() << "{\n";
    inc();
    out << indent() << "::rtl::OUString the_name( \"" << name_ << "\" );\n";
    std::map< OUString, sal_uInt32 > types;
    std::vector< unoidl::PlainStructTypeEntity::Member >::size_type n = 0;
    for (const unoidl::PlainStructTypeEntity::Member& member : entity_->getDirectMembers()) {
        if (types.emplace(
                    member.type, static_cast< sal_uInt32 >(types.size())).
            second) {
            dumpCppuGetType(out, member.type, &name_);
            // For typedefs, use the resolved type name, as there will be no
            // information available about the typedef itself at runtime (the
            // above getCppuType call will make available information about the
            // resolved type); no extra #include for the resolved type is
            // needed, as the header for the typedef includes it already:
            out << indent() << "::rtl::OUString the_tname"
                << static_cast< sal_uInt32 >(types.size() - 1) << "( \""
                << resolveAllTypedefs(member.type) << "\" );\n";
        }
        out << indent() << "::rtl::OUString the_name" << n++ << "( \""
            << member.name << "\" );\n";
    }
    out << indent() << "::typelib_StructMember_Init the_members[] = {\n";
    inc();
    n = 0;
    for (std::vector< unoidl::PlainStructTypeEntity::Member >::const_iterator i(
             entity_->getDirectMembers().begin());
         i != entity_->getDirectMembers().end();) {
        const auto iter = types.find(i->type);
        assert(iter != types.end());
        out << indent() << "{ { " << getTypeClass(i->type, true)
            << ", the_tname" << iter->second
            << ".pData, the_name" << n++ << ".pData }, false }";
        ++i;
        out << (i == entity_->getDirectMembers().end() ? " };" : ",") << "\n";
    }
    dec();
    out << indent() << "::typelib_TypeDescription * the_newType = 0;\n"
        << indent()
        << "::typelib_typedescription_newStruct(&the_newType, the_name.pData, ";
    if (entity_->getDirectBase().isEmpty()) {
        out << "0";
    } else {
        out << "::cppu::UnoType< ";
        dumpType(out, entity_->getDirectBase(), false, false, false, true);
        out << " >::get().getTypeLibType()";
    }
    out << ", " << entity_->getDirectMembers().size() << ", the_members);\n"
        << indent() << "::typelib_typedescription_register(&the_newType);\n"
        << indent() << "::typelib_typedescription_release(the_newType);\n"
        << indent() << "return new ::css::uno::Type("
        << getTypeClass(name_) << ", the_name); // leaked\n";
    dec();
    out << indent() << "}\n";
    dec();
    out << indent() << "};\n";
    codemaker::cppumaker::dumpNamespaceClose(out, name_, false);
    out << " }\n\n";
    dumpGetCppuTypePreamble(out);
    out << indent() << "return *detail::" << staticTypeClass << "::get();\n";
    dumpGetCppuTypePostamble(out);
}
 
bool PlainStructType::dumpBaseMembers(
    FileStream & out, OUString const & base, bool withType)
{
    if (base.isEmpty())
        return false;
 
    rtl::Reference< unoidl::Entity > ent;
    codemaker::UnoType::Sort sort = m_typeMgr->getSort(base, &ent);
    if (sort != codemaker::UnoType::Sort::PlainStruct) {
        throw CannotDumpException(
            "plain struct type base " + base
            + " is not a plain struct type");
    }
    rtl::Reference< unoidl::PlainStructTypeEntity > ent2(
        dynamic_cast< unoidl::PlainStructTypeEntity * >(ent.get()));
    assert(ent2.is());
    if (!ent2.is()) {
        return false;
    }
    bool hasMember = dumpBaseMembers(out, ent2->getDirectBase(), withType);
    for (const unoidl::PlainStructTypeEntity::Member& member : ent2->getDirectMembers()) {
        if (hasMember) {
            out << ", ";
        }
        if (withType) {
            dumpType(out, member.type, true, true);
            out << " ";
        }
        out << member.name << "_";
        hasMember = true;
    }
    return hasMember;
}
 
void PlainStructType::addLightGetCppuTypeIncludes(
    codemaker::cppumaker::Includes & includes) const
{
    includes.addType();
    includes.addCppuUnotypeHxx();
    includes.addSalTypesH();
    includes.addTypelibTypeclassH();
    includes.addTypelibTypedescriptionH();
}
 
void PlainStructType::addNormalGetCppuTypeIncludes(
    codemaker::cppumaker::Includes & includes) const
{
    includes.addType();
    includes.addCppuUnotypeHxx();
    includes.addSalTypesH();
    includes.addTypelibTypeclassH();
    includes.addTypelibTypedescriptionH();
}
 
void PlainStructType::addComprehensiveGetCppuTypeIncludes(
    codemaker::cppumaker::Includes & includes) const
{
    includes.addType();
    includes.addCppuUnotypeHxx();
    includes.addRtlInstanceHxx();
    includes.addRtlUstringH();
    includes.addRtlUstringHxx();
    includes.addSalTypesH();
    includes.addTypelibTypeclassH();
    includes.addTypelibTypedescriptionH();
}
 
sal_uInt32 PlainStructType::getTotalMemberCount(OUString const & base) const
{
    if (base.isEmpty()) {
        return 0;
    }
    rtl::Reference< unoidl::Entity > ent;
    codemaker::UnoType::Sort sort = m_typeMgr->getSort(base, &ent);
    if (sort != codemaker::UnoType::Sort::PlainStruct) {
        throw CannotDumpException(
            "plain struct type base " + base + " is not a plain struct type");
    }
    rtl::Reference< unoidl::PlainStructTypeEntity > ent2(
        dynamic_cast< unoidl::PlainStructTypeEntity * >(ent.get()));
    assert(ent2.is());
    if (!ent2.is()) {
        return 0;
    }
    return getTotalMemberCount(ent2->getDirectBase())
           + ent2->getDirectMembers().size(); //TODO: overflow
}
 
class PolyStructType: public CppuType
{
public:
    PolyStructType(
        rtl::Reference< unoidl::PolymorphicStructTypeTemplateEntity > const &
        entity,
        OUString const & name, rtl::Reference< TypeManager > const & typeMgr):
        CppuType(name, typeMgr), entity_(entity) {
        assert(entity.is());
    }
 
private:
    virtual void dumpDeclaration(FileStream& o) override;
 
    void dumpHppFile(FileStream& o, codemaker::cppumaker::Includes & includes) override;
 
    virtual void dumpLightGetCppuType(FileStream & out) override;
 
    virtual void dumpNormalGetCppuType(FileStream & out) override;
 
    virtual void dumpComprehensiveGetCppuType(FileStream & out) override;
 
    virtual void addLightGetCppuTypeIncludes(
        codemaker::cppumaker::Includes & includes) const override;
 
    virtual void addNormalGetCppuTypeIncludes(
        codemaker::cppumaker::Includes & includes) const override;
 
    virtual void addComprehensiveGetCppuTypeIncludes(
        codemaker::cppumaker::Includes & includes) const override;
 
    virtual bool isPolymorphic() const override {
        return true;
    }
 
    virtual void dumpTemplateHead(FileStream & out) const override;
 
    virtual void dumpTemplateParameters(FileStream & out) const override;
 
    rtl::Reference< unoidl::PolymorphicStructTypeTemplateEntity > entity_;
};
 
void PolyStructType::dumpDeclaration(FileStream & out)
{
    out << "\n#ifdef _WIN32\n#   pragma pack(push, 8)\n#endif\n\n" << indent();
    dumpTemplateHead(out);
    out << "struct SAL_DLLPUBLIC_RTTI " << id_ << " {\n";
    inc();
    out << indent() << "inline " << id_ << "();\n";
    if (!entity_->getMembers().empty()) {
        out << "\n" << indent() << "inline " << id_ << "(";
        for (std::vector<
             unoidl::PolymorphicStructTypeTemplateEntity::Member >::
             const_iterator i(entity_->getMembers().begin());
             i != entity_->getMembers().end(); ++i) {
            if (i != entity_->getMembers().begin()) {
                out << ", ";
            }
            if (i->parameterized) {
                dumpTypeParameterName(out, i->type);
                out << " const &";
            } else {
                dumpType(out, i->type, true, true);
            }
            out << " " << i->name << "_";
        }
        out << ");\n\n";
        // print the member fields
        for (const unoidl::PolymorphicStructTypeTemplateEntity::Member& member :
             entity_->getMembers()) {
            out << indent();
            if (member.parameterized) {
                dumpTypeParameterName(out, member.type);
            } else {
                dumpType(out, member.type);
            }
            out << " " << member.name << ";\n";
        }
    }
    dec();
    out << "};\n\n#ifdef _WIN32\n#   pragma pack(pop)\n#endif\n\n";
}
 
void PolyStructType::dumpHppFile(
    FileStream & out, codemaker::cppumaker::Includes & includes)
{
    OUString headerDefine(dumpHeaderDefine(out, u"HPP"));
    out << "\n";
    includes.dump(out, &name_, true);
    out << "\n";
    if (codemaker::cppumaker::dumpNamespaceOpen(out, name_, false)) {
        out << "\n";
    }
    out << "\n";
    // dump default (no-arg) constructor
    dumpTemplateHead(out);
    out << "inline " << id_;
    dumpTemplateParameters(out);
    out << "::" << id_ << "()\n";
    inc();
    for (std::vector< unoidl::PolymorphicStructTypeTemplateEntity::Member >::
         const_iterator i(entity_->getMembers().begin());
         i != entity_->getMembers().end(); ++i) {
        out << indent() << (i == entity_->getMembers().begin() ? ":" : ",")
            << " " << i->name;
        dumpInitializer(out, i->parameterized, i->type);
        out << "\n";
    }
    dec();
    out << "{\n}\n\n";
    if (!entity_->getMembers().empty()) {
        // dump takes-all-fields constructor
        dumpTemplateHead(out);
        out << "inline " << id_;
        dumpTemplateParameters(out);
        out << "::" << id_ << "(";
        for (std::vector<
             unoidl::PolymorphicStructTypeTemplateEntity::Member >::
             const_iterator i(entity_->getMembers().begin());
             i != entity_->getMembers().end(); ++i) {
            if (i != entity_->getMembers().begin()) {
                out << ", ";
            }
            if (i->parameterized) {
                dumpTypeParameterName(out, i->type);
                out << " const &";
            } else {
                dumpType(out, i->type, true, true);
            }
            out << " " << i->name << "_";
        }
        out << ")\n";
        inc();
        for (std::vector<
             unoidl::PolymorphicStructTypeTemplateEntity::Member >::
             const_iterator i(entity_->getMembers().begin());
             i != entity_->getMembers().end(); ++i) {
            out << indent() << (i == entity_->getMembers().begin() ? ":" : ",")
                << " " << i->name << "(" << i->name << "_)\n";
        }
        dec();
        out << "{\n}\n\n" << indent();
        // dump make_T method
        dumpTemplateHead(out);
        out << "\n" << indent() << "inline " << id_;
        dumpTemplateParameters(out);
        out << "\n" << indent() << "make_" << id_ << "(";
        for (std::vector<
             unoidl::PolymorphicStructTypeTemplateEntity::Member >::
             const_iterator i(entity_->getMembers().begin());
             i != entity_->getMembers().end(); ++i) {
            if (i != entity_->getMembers().begin()) {
                out << ", ";
            }
            if (i->parameterized) {
                dumpTypeParameterName(out, i->type);
                out << " const &";
            } else {
                dumpType(out, i->type, true, true);
            }
            out << " " << i->name << "_";
        }
        out << ")\n" << indent() << "{\n";
        inc();
        out << indent() << "return " << id_;
        dumpTemplateParameters(out);
        out << "(";
        for (std::vector<
             unoidl::PolymorphicStructTypeTemplateEntity::Member >::
             const_iterator i(entity_->getMembers().begin());
             i != entity_->getMembers().end(); ++i) {
            if (i != entity_->getMembers().begin()) {
                out << ", ";
            }
            out << i->name << "_";
        }
        out << ");\n";
        dec();
        out << indent() << "}\n\n";
    }
    // print the operator==
    dumpTemplateHead(out);
    out << " inline bool operator==(const " << id_;
    dumpTemplateParameters(out);
    out << "& the_lhs, const " << id_;
    dumpTemplateParameters(out);
    out << "& the_rhs)\n";
    out << "{\n";
    inc();
    out << indent() << "return ";
    bool bFirst = true;
    for (const unoidl::PolymorphicStructTypeTemplateEntity::Member& member : entity_->getMembers()) {
        if (!bFirst)
            out << "\n" << indent() << indent() << "&& ";
        out << "the_lhs." << member.name << " == the_rhs." << member.name;
        bFirst = false;
    }
    out << ";\n";
    dec();
    out << "}\n";
    // print the operator!=
    dumpTemplateHead(out);
    out << " inline bool operator!=(const " << id_;
    dumpTemplateParameters(out);
    out << "& the_lhs, const " << id_;
    dumpTemplateParameters(out);
    out << "& the_rhs)\n";
    out << "{\n";
    out << indent() << "return !operator==(the_lhs, the_rhs);\n";
    out << "}\n";
    // close namespace
    if (codemaker::cppumaker::dumpNamespaceClose(out, name_, false)) {
        out << "\n";
    }
    out << "\n";
    dumpGetCppuType(out);
    out << "\n#endif // "<< headerDefine << "\n";
}
 
void PolyStructType::dumpLightGetCppuType(FileStream & out)
{
    dumpGetCppuTypePreamble(out);
    out << indent()
        << ("//TODO: On certain platforms with weak memory models, the"
            " following code can result in some threads observing that the_type"
            " points to garbage\n")
        << indent()
        << "static ::typelib_TypeDescriptionReference * the_type = 0;\n"
        << indent() << "if (the_type == 0) {\n";
    inc();
 
    out << "#ifdef LIBO_INTERNAL_ONLY\n";
 
    out << indent() << "::rtl::OString the_buffer = \"" << name_
        << "<\" +\n";
    for (std::vector< OUString >::const_iterator i(
             entity_->getTypeParameters().begin());
         i != entity_->getTypeParameters().end();) {
        out << indent()
            << ("::rtl::OUStringToOString("
                "::cppu::getTypeFavourChar(static_cast< ");
        dumpTypeParameterName(out, *i);
        out << " * >(0)).getTypeName(), RTL_TEXTENCODING_UTF8) +\n";
        ++i;
        if (i != entity_->getTypeParameters().end()) {
            out << indent() << "\",\" +\n";
        }
    }
    out << indent() << "\">\";\n";
 
    out << "#else\n";
 
    out << indent() << "::rtl::OStringBuffer the_buffer(\"" << name_
        << "<\");\n";
    for (std::vector< OUString >::const_iterator i(
             entity_->getTypeParameters().begin());
         i != entity_->getTypeParameters().end();) {
        out << indent()
            << ("the_buffer.append(::rtl::OUStringToOString("
                "::cppu::getTypeFavourChar(static_cast< ");
        dumpTypeParameterName(out, *i);
        out << " * >(0)).getTypeName(), RTL_TEXTENCODING_UTF8));\n";
        ++i;
        if (i != entity_->getTypeParameters().end()) {
            out << indent() << "the_buffer.append(',');\n";
        }
    }
    out << indent() << "the_buffer.append('>');\n";
 
    out << "#endif\n";
 
    out << indent()
        << "::typelib_static_type_init(&the_type, " << getTypeClass(name_, true)
        << ", the_buffer.getStr());\n";
 
    dec();
    out << indent() << "}\n" << indent()
        << "return *reinterpret_cast< ::css::uno::Type * >(&the_type);\n";
    dumpGetCppuTypePostamble(out);
}
 
void PolyStructType::dumpNormalGetCppuType(FileStream & out)
{
    dumpGetCppuTypePreamble(out);
    out << indent()
        << ("//TODO: On certain platforms with weak memory models, the"
            " following code can result in some threads observing that the_type"
            " points to garbage\n")
        << indent()
        << "static ::typelib_TypeDescriptionReference * the_type = 0;\n"
        << indent() << "if (the_type == 0) {\n";
    inc();
    out << indent() << "::rtl::OStringBuffer the_buffer(\"" << name_
        << "<\");\n";
    for (std::vector< OUString >::const_iterator i(
             entity_->getTypeParameters().begin());
         i != entity_->getTypeParameters().end();) {
        out << indent()
            << ("the_buffer.append(::rtl::OUStringToOString("
                "::cppu::getTypeFavourChar(static_cast< ");
        dumpTypeParameterName(out, *i);
        out << " * >(0)).getTypeName(), RTL_TEXTENCODING_UTF8));\n";
        ++i;
        if (i != entity_->getTypeParameters().end()) {
            out << indent() << "the_buffer.append(',');\n";
        }
    }
    out << indent() << "the_buffer.append('>');\n" << indent()
        << "::typelib_TypeDescriptionReference * the_members[] = {\n";
    inc();
    for (std::vector< unoidl::PolymorphicStructTypeTemplateEntity::Member >::
         const_iterator i(entity_->getMembers().begin());
         i != entity_->getMembers().end();) {
        out << indent();
        if (i->parameterized) {
            out << "::cppu::getTypeFavourChar(static_cast< ";
            dumpTypeParameterName(out, i->type);
            out << " * >(0))";
        } else {
            out << "::cppu::UnoType< ";
            dumpType(out, i->type, false, false, false, true);
            out << " >::get()";
        }
        ++i;
        out << ".getTypeLibType()"
            << (i == entity_->getMembers().end() ? " };" : ",") << "\n";
    }
    dec();
    out << indent() << "static ::sal_Bool const the_parameterizedTypes[] = { ";
    for (std::vector< unoidl::PolymorphicStructTypeTemplateEntity::Member >::
         const_iterator i(entity_->getMembers().begin());
         i != entity_->getMembers().end(); ++i) {
        if (i != entity_->getMembers().begin()) {
            out << ", ";
        }
        out << (i->parameterized ? "true" : "false");
    }
    out << " };\n" << indent()
        << ("::typelib_static_struct_type_init(&the_type, the_buffer.getStr(),"
            " 0, ")
        << entity_->getMembers().size()
        << ", the_members, the_parameterizedTypes);\n";
    dec();
    out << indent() << "}\n" << indent()
        << ("return *reinterpret_cast< ::css::uno::Type * >("
            "&the_type);\n");
    dumpGetCppuTypePostamble(out);
}
 
void PolyStructType::dumpComprehensiveGetCppuType(FileStream & out)
{
    out << "namespace cppu {  namespace detail {\n\n" << indent();
    dumpTemplateHead(out);
    OUString staticTypeClass("the" + id_ + "Type");
    out << "struct " << staticTypeClass
        << " : public rtl::StaticWithInit< ::css::uno::Type *, "
        << staticTypeClass;
    dumpTemplateParameters(out);
    out << " >\n" << indent() << "{\n";
    inc();
    out << indent() << "::css::uno::Type * operator()() const\n"
        << indent() << "{\n";
    inc();
 
    out << "#ifdef LIBO_INTERNAL_ONLY\n";
    out << indent()
        << "::rtl::OUString the_name =\n";
    out << indent() << "\"" << name_ << "<\" +\n";
    for (std::vector< OUString >::const_iterator i(
             entity_->getTypeParameters().begin());
         i != entity_->getTypeParameters().end();) {
        out << indent()
            << "::cppu::getTypeFavourChar(static_cast< ";
        dumpTypeParameterName(out, *i);
        out << " * >(0)).getTypeName() +\n";
        ++i;
        if (i != entity_->getTypeParameters().end()) {
            out << indent()
                << "\",\" +\n";
        }
    }
    out << indent()
        << "\">\";\n";
    out << "#else\n";
    out << indent() << "::rtl::OUStringBuffer the_buffer;\n" << indent()
        << "the_buffer.append(\"" << name_ << "<\");\n";
    for (std::vector< OUString >::const_iterator i(
             entity_->getTypeParameters().begin());
         i != entity_->getTypeParameters().end();) {
        out << indent()
            << "the_buffer.append(::cppu::getTypeFavourChar(static_cast< ";
        dumpTypeParameterName(out, *i);
        out << " * >(0)).getTypeName());\n";
        ++i;
        if (i != entity_->getTypeParameters().end()) {
            out << indent()
                << ("the_buffer.append("
                    "static_cast< ::sal_Unicode >(','));\n");
        }
    }
    out << indent() << "the_buffer.append(static_cast< ::sal_Unicode >('>'));\n";
    out << indent()
        << "::rtl::OUString the_name(the_buffer.makeStringAndClear());\n";
    out << "#endif\n";
    std::map< OUString, sal_uInt32 > parameters;
    std::map< OUString, sal_uInt32 > types;
    std::vector< unoidl::PolymorphicStructTypeTemplateEntity::Member >::
    size_type n = 0;
    for (const unoidl::PolymorphicStructTypeTemplateEntity::Member& member : entity_->getMembers()) {
        if (member.parameterized) {
            if (parameters.emplace(
                        member.type, static_cast< sal_uInt32 >(parameters.size())).
                second) {
                sal_uInt32 k = static_cast< sal_uInt32 >(parameters.size() - 1);
                out << indent()
                    << "::css::uno::Type const & the_ptype" << k
                    << " = ::cppu::getTypeFavourChar(static_cast< ";
                dumpTypeParameterName(out, member.type);
                out << " * >(0));\n" << indent()
                    << "::typelib_TypeClass the_pclass" << k
                    << " = (::typelib_TypeClass) the_ptype" << k
                    << ".getTypeClass();\n" << indent()
                    << "::rtl::OUString the_pname" << k << "(the_ptype" << k
                    << ".getTypeName());\n";
            }
        } else if (types.emplace(member.type, static_cast< sal_uInt32 >(types.size())).
                   second) {
            dumpCppuGetType(out, member.type, &name_);
            // For typedefs, use the resolved type name, as there will be no
            // information available about the typedef itself at runtime (the
            // above getCppuType call will make available information about the
            // resolved type); no extra #include for the resolved type is
            // needed, as the header for the typedef includes it already:
            out << indent() << "::rtl::OUString the_tname"
                << static_cast< sal_uInt32 >(types.size() - 1) << "( \""
                << resolveAllTypedefs(member.type) << "\" );\n";
        }
        out << indent() << "::rtl::OUString the_name" << n++ << "( \""
            << member.name << "\" );\n";
    }
    out << indent() << "::typelib_StructMember_Init the_members[] = {\n";
    inc();
    n = 0;
    for (std::vector< unoidl::PolymorphicStructTypeTemplateEntity::Member >::
         const_iterator i(entity_->getMembers().begin());
         i != entity_->getMembers().end();) {
        out << indent() << "{ { ";
        if (i->parameterized) {
            const auto iter = parameters.find(i->type);
            assert(iter != parameters.end());
            sal_uInt32 k = iter->second;
            out << "the_pclass" << k << ", the_pname" << k << ".pData";
        } else {
            const auto iter = types.find(i->type);
            assert(iter != types.end());
            out << getTypeClass(i->type, true) << ", the_tname"
                << iter->second << ".pData";
        }
        out << ", the_name" << n++ << ".pData }, "
            << (i->parameterized ? "true" : "false") << " }";
        ++i;
        out << (i == entity_->getMembers().end() ? " };" : ",") << "\n";
    }
    dec();
    out << indent() << "::typelib_TypeDescription * the_newType = 0;\n";
    out << indent()
        << ("::typelib_typedescription_newStruct(&the_newType, the_name.pData,"
            " 0, ")
        << entity_->getMembers().size() << ", the_members);\n" << indent()
        << "::typelib_typedescription_register(&the_newType);\n" << indent()
        << "::typelib_typedescription_release(the_newType);\n" << indent()
        << "return new ::css::uno::Type(" << getTypeClass(name_)
        << ", the_name); // leaked\n";
    dec();
    out << indent() << "}\n";
    dec();
    out << indent() << "};\n } }\n\n";
    dumpGetCppuTypePreamble(out);
    out << indent() << "return *detail::" << staticTypeClass;
    dumpTemplateParameters(out);
    out << "::get();\n";
    dumpGetCppuTypePostamble(out);
}
 
void PolyStructType::addLightGetCppuTypeIncludes(
    codemaker::cppumaker::Includes & includes) const
{
    includes.addType();
    includes.addCppuUnotypeHxx();
    includes.addSalTypesH();
    includes.addTypelibTypeclassH();
    includes.addTypelibTypedescriptionH();
    includes.addRtlStrbufHxx();
    includes.addRtlTextencH();
    includes.addRtlUstringHxx();
}
 
void PolyStructType::addNormalGetCppuTypeIncludes(
    codemaker::cppumaker::Includes & includes) const
{
    includes.addType();
    includes.addCppuUnotypeHxx();
    includes.addSalTypesH();
    includes.addTypelibTypeclassH();
    includes.addTypelibTypedescriptionH();
    includes.addRtlStrbufHxx();
    includes.addRtlTextencH();
    includes.addRtlUstringHxx();
}
 
void PolyStructType::addComprehensiveGetCppuTypeIncludes(
    codemaker::cppumaker::Includes & includes) const
{
    includes.addType();
    includes.addCppuUnotypeHxx();
    includes.addRtlInstanceHxx();
    includes.addRtlUstringH();
    includes.addRtlUstringHxx();
    includes.addSalTypesH();
    includes.addTypelibTypeclassH();
    includes.addTypelibTypedescriptionH();
    includes.addRtlStringH();
    includes.addRtlUstrbufHxx();
}
 
void PolyStructType::dumpTemplateHead(FileStream & out) const
{
    out << "template< ";
    for (std::vector< OUString >::const_iterator i(
             entity_->getTypeParameters().begin());
         i != entity_->getTypeParameters().end(); ++i) {
        if (i != entity_->getTypeParameters().begin()) {
            out << ", ";
        }
        out << "typename ";
        dumpTypeParameterName(out, *i);
    }
    out << " > ";
}
 
void PolyStructType::dumpTemplateParameters(FileStream & out) const
{
    out << "< ";
    for (std::vector< OUString >::const_iterator i(
             entity_->getTypeParameters().begin());
         i != entity_->getTypeParameters().end(); ++i) {
        if (i != entity_->getTypeParameters().begin()) {
            out << ", ";
        }
        dumpTypeParameterName(out, *i);
    }
    out << " >";
}
 
OUString typeToIdentifier(std::u16string_view name)
{
    sal_Int32 k;
    OUString n(b2u(codemaker::UnoType::decompose(u2b(name), &k)));
    OUStringBuffer b(4*k + n.getLength());
    for (sal_Int32 i = 0; i != k; ++i) {
        b.append("seq_");
    }
    b.append(n);
    b.replace(' ', '_');
    b.replace(',', '_');
    b.replace('.', '_');
    b.replace('<', '_');
    b.replace('>', '_');
    return b.makeStringAndClear();
}
 
class ExceptionType: public CppuType
{
public:
    ExceptionType(
        rtl::Reference< unoidl::ExceptionTypeEntity > const & entity,
        OUString const & name, rtl::Reference< TypeManager > const & typeMgr):
        CppuType(name, typeMgr), entity_(entity) {
        assert(entity.is());
    }
 
private:
    virtual void dumpHdlFile(
        FileStream & out, codemaker::cppumaker::Includes & includes) override;
 
    virtual void dumpHppFile(
        FileStream & out, codemaker::cppumaker::Includes & includes) override;
 
    virtual void addComprehensiveGetCppuTypeIncludes(
        codemaker::cppumaker::Includes & includes) const override;
 
    virtual void dumpLightGetCppuType(FileStream & out) override;
 
    virtual void dumpNormalGetCppuType(FileStream & out) override;
 
    virtual void dumpComprehensiveGetCppuType(FileStream & out) override;
 
    virtual sal_uInt32 checkInheritedMemberCount() const override {
        return getTotalMemberCount(entity_->getDirectBase());
    }
 
    virtual void dumpDeclaration(FileStream & out) override;
 
    bool dumpBaseMembers(
        FileStream & out, OUString const & base, bool withType,
        bool eligibleForDefaults);
 
    sal_uInt32 getTotalMemberCount(OUString const & base) const;
 
    rtl::Reference< unoidl::ExceptionTypeEntity > entity_;
};
 
void ExceptionType::dumpHdlFile(
        FileStream & out, codemaker::cppumaker::Includes & includes)
{
    if (name_ == "com.sun.star.uno.Exception")
    {
        includes.addCustom(u"#if defined(LIBO_INTERNAL_ONLY) && !defined(NDEBUG)"_ustr);
        includes.addCustom(u"#if __has_include(<version>)"_ustr);
        includes.addCustom(u"#include <version>"_ustr);
        includes.addCustom(u"#endif"_ustr);
        includes.addCustom(u"#if defined(__cpp_lib_source_location) && __cpp_lib_source_location >= 201907"_ustr);
        includes.addCustom(u"#include <source_location>"_ustr);
        includes.addCustom(u"#define LIBO_USE_SOURCE_LOCATION std"_ustr);
        includes.addCustom(u"#elif __has_include(<experimental/source_location>)"_ustr);
        includes.addCustom(u"#include <experimental/source_location>"_ustr);
        includes.addCustom(u"#define LIBO_USE_SOURCE_LOCATION std::experimental"_ustr);
        includes.addCustom(u"#endif"_ustr);
        includes.addCustom(u"#endif"_ustr);
        includes.addCustom(u"#if defined LIBO_USE_SOURCE_LOCATION"_ustr);
        includes.addCustom(u"#include <o3tl/runtimetooustring.hxx>"_ustr);
        includes.addCustom(u"#endif"_ustr);
    }
    dumpHFileContent(out, includes);
}
 
void ExceptionType::addComprehensiveGetCppuTypeIncludes(
    codemaker::cppumaker::Includes & includes) const
{
    includes.addCppuUnotypeHxx();
    includes.addRtlInstanceHxx(); // using rtl::StaticWithInit
}
 
void ExceptionType::dumpHppFile(
    FileStream & out, codemaker::cppumaker::Includes & includes)
{
    OUString headerDefine(dumpHeaderDefine(out, u"HPP"));
    out << "\n";
    addDefaultHxxIncludes(includes);
    includes.dump(out, &name_, true);
 
    // for the output operator below
    if (name_ == "com.sun.star.uno.Exception")
    {
        out << "#if defined LIBO_INTERNAL_ONLY\n";
        out << "#include <ostream>\n";
        out << "#include <typeinfo>\n";
        out << "#endif\n";
    }
 
    out << "\n";
 
    if (codemaker::cppumaker::dumpNamespaceOpen(out, name_, false)) {
        out << "\n";
    }
 
    // default constructor
    out << "\ninline " << id_ << "::" << id_ << "(\n";
    out << "#if defined LIBO_USE_SOURCE_LOCATION\n";
    out << "    LIBO_USE_SOURCE_LOCATION::source_location location\n";
    out << "#endif\n";
    out << "    )\n";
    inc();
    OUString base(entity_->getDirectBase());
    bool bFirst = true;
    if (!base.isEmpty()) {
        out << indent() << ": " << codemaker::cpp::scopedCppName(u2b(base))
            << "(\n";
        out << "#if defined LIBO_USE_SOURCE_LOCATION\n";
        out << "    location\n";
        out << "#endif\n";
        out << ")\n";
        bFirst = false;
    }
    for (const unoidl::ExceptionTypeEntity::Member& member : entity_->getDirectMembers()) {
        out << indent() << (bFirst ? ":" : ",") << " ";
        out << member.name;
        dumpInitializer(out, false, member.type);
        out << "\n";
        bFirst = false;
    }
    dec();
    out << "{";
    if (!m_cppuTypeDynamic) {
        out << "\n";
        inc();
        dumpCppuGetType(out, name_);
        dec();
    } else {
        out << " ";
    }
    if (name_ == "com.sun.star.uno.Exception")
    {
        out << "\n#if defined LIBO_USE_SOURCE_LOCATION\n";
        out << "    if (!Message.isEmpty())\n";
        out << "        Message += \" \";\n";
        out << "    Message += \"at \" + o3tl::runtimeToOUString(location.file_name()) + \":\" + OUString::number(location.line());\n";
        out << "#endif\n";
    }
    out << "}\n\n";
 
    // fields constructor
    if (!entity_->getDirectMembers().empty() || getInheritedMemberCount() > 0) {
        out << indent() << "inline " << id_ << "::" << id_ << "(";
        bFirst = !dumpBaseMembers(out, base, true, false);
        for (const unoidl::ExceptionTypeEntity::Member& member : entity_->getDirectMembers()) {
            if (!bFirst) {
                out << ", ";
            }
            dumpType(out, member.type, true, true);
            out << " " << member.name << "_";
            bFirst = false;
        }
        out << "\n#if defined LIBO_USE_SOURCE_LOCATION\n";
        out << "    " << (bFirst ? "" : ", ") << "LIBO_USE_SOURCE_LOCATION::source_location location\n";
        out << "#endif\n";
        out << ")\n";
        inc();
        bFirst = true;
        if (!base.isEmpty()) {
            out << indent() << ": " << codemaker::cpp::scopedCppName(u2b(base))
                << "(";
            dumpBaseMembers(out, base, false, false);
            out << "\n#if defined LIBO_USE_SOURCE_LOCATION\n";
            out << "    , location\n";
            out << "#endif\n";
            out << ")\n";
            bFirst = false;
        }
        for (const unoidl::ExceptionTypeEntity::Member& member : entity_->getDirectMembers()) {
            out << indent() << (bFirst ? ":" : ",") << " " << member.name << "("
                << member.name << "_)\n";
            bFirst = false;
        }
        dec();
        out << "{";
        if (!m_cppuTypeDynamic) {
            out << "\n";
            inc();
            dumpCppuGetType(out, name_);
            dec();
        } else {
            out << " ";
        }
        if (name_ == "com.sun.star.uno.Exception")
        {
            out << "\n#if defined LIBO_USE_SOURCE_LOCATION\n";
            out << "    if (!Message.isEmpty())\n";
            out << "        Message += \" \";\n";
            out << "    Message += \"at \" + o3tl::runtimeToOUString(location.file_name()) + \":\" + OUString::number(location.line());\n";
            out << "#endif\n";
        }
        out << "}\n\n";
    }
    out << "#if !defined LIBO_INTERNAL_ONLY\n" << indent() << id_ << "::" << id_
        << "(" << id_ << " const & the_other)";
    bFirst = true;
    if (!base.isEmpty()) {
        out << ": " << codemaker::cpp::scopedCppName(u2b(base))
            << "(the_other)";
        bFirst = false;
    }
    for (const unoidl::ExceptionTypeEntity::Member& member : entity_->getDirectMembers()) {
        out << (bFirst ? ":" : ",") << " " << member.name << "(the_other." << member.name
            << ")";
        bFirst = false;
    }
    out << indent() << " {}\n\n" << indent() << id_ << "::~" << id_
        << "() {}\n\n" << indent() << id_ << " & " << id_ << "::operator =("
        << id_ << " const & the_other) {\n";
    inc();
    out << indent()
        << ("//TODO: Just like its implicitly-defined counterpart, this"
            " function definition is not exception-safe\n");
    if (!base.isEmpty()) {
        out << indent() << codemaker::cpp::scopedCppName(u2b(base))
            << "::operator =(the_other);\n";
    }
    for (const unoidl::ExceptionTypeEntity::Member& member : entity_->getDirectMembers()) {
        out << indent() << member.name << " = the_other." << member.name << ";\n";
    }
    out << indent() << "return *this;\n";
    dec();
    out << indent() << "}\n#endif\n\n";
 
    // Provide an output operator for printing Exception information to SAL_WARN/SAL_INFO.
    if (name_ == "com.sun.star.uno.Exception")
    {
        out << "#if defined LIBO_INTERNAL_ONLY\n";
        out << "template< typename charT, typename traits >\n";
        out << "inline ::std::basic_ostream<charT, traits> & operator<<(\n";
        out << "    ::std::basic_ostream<charT, traits> & os, ::com::sun::star::uno::Exception const & exception)\n";
        out << "{\n";
        out << "    // the class name is useful because exception throwing code does not always pass in a useful message\n";
        out << "    os << typeid(exception).name();\n";
        out << "    if (!exception.Message.isEmpty())\n";
        out << "      os << \" msg: \" << exception.Message;\n";
        out << "    return os;\n";
        out << "}\n";
        out << "#endif\n";
        out << "\n";
    }
 
    if (codemaker::cppumaker::dumpNamespaceClose(out, name_, false)) {
        out << "\n";
    }
    out << "\n";
 
    dumpGetCppuType(out);
    out << "\n#endif // "<< headerDefine << "\n";
}
 
void ExceptionType::dumpLightGetCppuType(FileStream & out)
{
    dumpGetCppuTypePreamble(out);
    out << indent()
        << "static typelib_TypeDescriptionReference * the_type = 0;\n"
        << indent() << "if ( !the_type )\n" << indent() << "{\n";
    inc();
    out << indent() << "typelib_static_type_init( &the_type, "
        << getTypeClass(name_, true) << ", \"" << name_ << "\" );\n";
    dec();
    out << indent() << "}\n" << indent()
        << ("return * reinterpret_cast< ::css::uno::Type * >("
            " &the_type );\n");
    dumpGetCppuTypePostamble(out);
}
 
void ExceptionType::dumpNormalGetCppuType(FileStream & out)
{
    dumpGetCppuTypePreamble(out);
    out << indent()
        << "static typelib_TypeDescriptionReference * the_type = 0;\n"
        << indent() << "if ( !the_type )\n" << indent() << "{\n";
    inc();
    OUString base(entity_->getDirectBase());
    bool baseException = false;
    if (!base.isEmpty()) {
        if (base == "com.sun.star.uno.Exception") {
            baseException = true;
        } else {
            out << indent()
                << ("const ::css::uno::Type& rBaseType ="
                    " ::cppu::UnoType< ");
            dumpType(out, base, true, false, false, true);
            out << " >::get();\n\n";
        }
    }
    if (!entity_->getDirectMembers().empty()) {
        out << indent() << "typelib_TypeDescriptionReference * aMemberRefs["
            << entity_->getDirectMembers().size() << "];\n";
        std::set< OUString > seen;
        std::vector< unoidl::ExceptionTypeEntity::Member >::size_type n = 0;
        for (const unoidl::ExceptionTypeEntity::Member& member : entity_->getDirectMembers()) {
            OUString type(resolveAllTypedefs(member.type));
            OUString modType(typeToIdentifier(type));
            if (seen.insert(type).second) {
                out << indent()
                    << "const ::css::uno::Type& rMemberType_"
                    << modType << " = ::cppu::UnoType< ";
                dumpType(out, type, false, false, false, true);
                out << " >::get();\n";
            }
            out << indent() << "aMemberRefs[" << n++ << "] = rMemberType_"
                << modType << ".getTypeLibType();\n";
        }
        out << "\n";
    }
    out << indent() << "typelib_static_compound_type_init( &the_type, "
        << getTypeClass(name_, true) << ", \"" << name_ << "\", ";
    if (baseException) {
        out << ("* ::typelib_static_type_getByTypeClass("
                " typelib_TypeClass_EXCEPTION )");
    } else if (base.isEmpty()) {
        out << "0";
    } else {
        out << "rBaseType.getTypeLibType()";
    }
    out << ", " << entity_->getDirectMembers().size() << ",  "
        << (entity_->getDirectMembers().empty() ? "0" : "aMemberRefs")
        << " );\n";
    dec();
    out << indent() << "}\n" << indent()
        << ("return * reinterpret_cast< const ::css::uno::Type * >("
            " &the_type );\n");
    dumpGetCppuTypePostamble(out);
}
 
void ExceptionType::dumpComprehensiveGetCppuType(FileStream & out)
{
    codemaker::cppumaker::dumpNamespaceOpen(out, name_, false);
    out << " namespace detail {\n\n";
    OUString staticTypeClass("the" + id_ + "Type");
    out << indent() << "struct " << staticTypeClass
        << " : public rtl::StaticWithInit< ::css::uno::Type *, "
        << staticTypeClass << " >\n" << indent() << "{\n";
    inc();
    out << indent() << "::css::uno::Type * operator()() const\n"
        << indent() << "{\n";
    inc();
    out << indent() << "::rtl::OUString sTypeName( \"" << name_ << "\" );\n\n"
        << indent() << "// Start inline typedescription generation\n"
        << indent() << "typelib_TypeDescription * pTD = 0;\n";
    OUString base(entity_->getDirectBase());
    if (!base.isEmpty()) {
        out << indent()
            << ("const ::css::uno::Type& rSuperType ="
                " ::cppu::UnoType< ");
        dumpType(out, base, false, false, false, true);
        out << " >::get();\n";
    }
    std::set< OUString > seen;
    for (const unoidl::ExceptionTypeEntity::Member& member : entity_->getDirectMembers()) {
        if (seen.insert(member.type).second) {
            dumpCppuGetType(out, member.type);
        }
    }
    if (!entity_->getDirectMembers().empty()) {
        out << "\n" << indent() << "typelib_CompoundMember_Init aMembers["
            << entity_->getDirectMembers().size() << "];\n";
        std::vector< unoidl::ExceptionTypeEntity::Member >::size_type n = 0;
        for (const unoidl::ExceptionTypeEntity::Member& member : entity_->getDirectMembers()) {
            OUString type(resolveAllTypedefs(member.type));
            out << indent() << "::rtl::OUString sMemberType" << n << "( \""
                << type << "\" );\n" << indent()
                << "::rtl::OUString sMemberName" << n << "( \"" << member.name
                << "\" );\n" << indent() << "aMembers[" << n
                << "].eTypeClass = (typelib_TypeClass)" << getTypeClass(type)
                << ";\n" << indent() << "aMembers[" << n
                << "].pTypeName = sMemberType" << n << ".pData;\n" << indent()
                << "aMembers[" << n << "].pMemberName = sMemberName" << n
                << ".pData;\n";
            ++n;
        }
    }
    out << "\n" << indent() << "typelib_typedescription_new(\n";
    inc();
    out << indent() << "&pTD,\n" << indent() << "(typelib_TypeClass)"
        << getTypeClass(name_) << ", sTypeName.pData,\n" << indent()
        << (base.isEmpty() ? "0" : "rSuperType.getTypeLibType()") << ",\n"
        << indent() << entity_->getDirectMembers().size() << ",\n" << indent()
        << (entity_->getDirectMembers().empty() ? "0" : "aMembers")
        << " );\n\n";
    dec();
    out << indent()
        << ("typelib_typedescription_register( (typelib_TypeDescription**)&pTD"
            " );\n\n")
        << indent() << "typelib_typedescription_release( pTD );\n" << indent()
        << "// End inline typedescription generation\n\n" << indent()
        << "return new ::css::uno::Type( " << getTypeClass(name_)
        << ", sTypeName ); // leaked\n";
    dec();
    out << indent() << "}\n";
    dec();
    out << indent() << "};\n\n";
    codemaker::cppumaker::dumpNamespaceClose(out, name_, false);
    out << " }\n\n";
    dumpGetCppuTypePreamble(out);
    out << indent() << "return *detail::" << staticTypeClass << "::get();\n";
    dumpGetCppuTypePostamble(out);
}
 
void ExceptionType::dumpDeclaration(FileStream & out)
{
    out << "\nclass CPPU_GCC_DLLPUBLIC_EXPORT SAL_WARN_UNUSED " << id_;
    OUString base(entity_->getDirectBase());
    if (!base.isEmpty()) {
        out << " : public " << codemaker::cpp::scopedCppName(u2b(base));
    }
    out << "\n{\npublic:\n";
    inc();
 
    // default constructor
    out << indent() << "inline CPPU_GCC_DLLPRIVATE " << id_ << "(\n";
    out << "#if defined LIBO_USE_SOURCE_LOCATION\n";
    out << "    LIBO_USE_SOURCE_LOCATION::source_location location = LIBO_USE_SOURCE_LOCATION::source_location::current()\n";
    out << "#endif\n\n";
    out << "    );\n";
 
    // constructor that initializes data members
    if (!entity_->getDirectMembers().empty() || getInheritedMemberCount() > 0) {
        out << indent() << "inline CPPU_GCC_DLLPRIVATE " << id_ << "(";
        bool eligibleForDefaults = entity_->getDirectMembers().empty();
        bool bFirst = !dumpBaseMembers(out, base, true, eligibleForDefaults);
        for (const unoidl::ExceptionTypeEntity::Member& member : entity_->getDirectMembers()) {
            if (!bFirst) {
                out << ", ";
            }
            dumpType(out, member.type, true, true);
            out << " " << member.name << "_";
            bFirst = false;
        }
        out << "\n#if defined LIBO_USE_SOURCE_LOCATION\n";
        out << ", LIBO_USE_SOURCE_LOCATION::source_location location = LIBO_USE_SOURCE_LOCATION::source_location::current()\n";
        out << "#endif\n";
        out << "    );\n\n";
    }
    out << "#if !defined LIBO_INTERNAL_ONLY\n" << indent()
        << "inline CPPU_GCC_DLLPRIVATE " << id_ << "(" << id_
        << " const &);\n\n" << indent() << "inline CPPU_GCC_DLLPRIVATE ~"
        << id_ << "();\n\n" << indent() << "inline CPPU_GCC_DLLPRIVATE " << id_
        << " & operator =(" << id_ << " const &);\n#endif\n\n";
    for (std::vector< unoidl::ExceptionTypeEntity::Member >::const_iterator i(
             entity_->getDirectMembers().begin());
         i != entity_->getDirectMembers().end(); ++i) {
        out << indent();
        dumpType(out, i->type);
        out << " " << i->name;
        if (i == entity_->getDirectMembers().begin() && !base.isEmpty()
            && i->type != "hyper" && i->type != "unsigned hyper"
            && i->type != "double") {
            out << " CPPU_GCC3_ALIGN( "
                << codemaker::cpp::scopedCppName(u2b(base)) << " )";
        }
        out << ";\n";
    }
    dec();
    out << "};\n\n";
}
 
bool ExceptionType::dumpBaseMembers(
    FileStream & out, OUString const & base, bool withType, bool eligibleForDefaults)
{
    if (base.isEmpty())
        return false;
 
    bool hasMember = false;
    rtl::Reference< unoidl::Entity > ent;
    codemaker::UnoType::Sort sort = m_typeMgr->getSort(base, &ent);
    if (sort != codemaker::UnoType::Sort::Exception) {
        throw CannotDumpException(
            "exception type base " + base + " is not an exception type");
    }
    rtl::Reference< unoidl::ExceptionTypeEntity > ent2(
        dynamic_cast< unoidl::ExceptionTypeEntity * >(ent.get()));
    assert(ent2.is());
    if (!ent2.is()) {
        return false;
    }
    hasMember = dumpBaseMembers( out, ent2->getDirectBase(), withType,
                                 eligibleForDefaults && ent2->getDirectMembers().empty() );
    int memberCount = 0;
    for (const unoidl::ExceptionTypeEntity::Member& member : ent2->getDirectMembers()) {
        if (hasMember) {
            out << ", ";
        }
        if (withType) {
            dumpType(out, member.type, true, true);
            out << " ";
        }
        out << member.name << "_";
        // We want to provide a default parameter value for uno::Exception subtype
        // constructors, since most of the time we don't pass a Context object in to the exception
        // throw sites.
        if (eligibleForDefaults
            && base == "com.sun.star.uno.Exception"
            && memberCount == 1
            && member.name == "Context"
            && member.type == "com.sun.star.uno.XInterface") {
            out << " = ::css::uno::Reference< ::css::uno::XInterface >()";
        }
        hasMember = true;
        ++memberCount;
    }
    return hasMember;
}
 
sal_uInt32 ExceptionType::getTotalMemberCount(OUString const & base) const
{
    if (base.isEmpty()) {
        return 0;
    }
    rtl::Reference< unoidl::Entity > ent;
    codemaker::UnoType::Sort sort = m_typeMgr->getSort(base, &ent);
    if (sort != codemaker::UnoType::Sort::Exception) {
        throw CannotDumpException(
            "exception type base " + base + " is not an exception type");
    }
    unoidl::ExceptionTypeEntity& ent2(dynamic_cast<unoidl::ExceptionTypeEntity&>(*ent));
    return getTotalMemberCount(ent2.getDirectBase())
           + ent2.getDirectMembers().size(); //TODO: overflow
}
 
class EnumType: public CppuType
{
public:
    EnumType(
        rtl::Reference< unoidl::EnumTypeEntity > const & entity,
        OUString const & name, rtl::Reference< TypeManager > const & typeMgr):
        CppuType(name, typeMgr), entity_(entity) {
        assert(entity.is());
    }
 
private:
    virtual void dumpDeclaration(FileStream& o) override;
 
    virtual void addComprehensiveGetCppuTypeIncludes(
        codemaker::cppumaker::Includes & includes) const override;
 
    void dumpHppFile(FileStream& o, codemaker::cppumaker::Includes & includes) override;
 
    void        dumpNormalGetCppuType(FileStream& o) override;
    void        dumpComprehensiveGetCppuType(FileStream& o) override;
 
    rtl::Reference< unoidl::EnumTypeEntity > entity_;
};
 
void EnumType::addComprehensiveGetCppuTypeIncludes(
    codemaker::cppumaker::Includes & includes) const
{
    includes.addCppuUnotypeHxx();
    includes.addRtlInstanceHxx(); // using rtl::StaticWithInit
}
 
void EnumType::dumpDeclaration(FileStream& o)
{
    o << "\n#if defined LIBO_INTERNAL_ONLY\n";
    o << "\n#if defined __GNUC__\n"; // gcc does not like visibility annotation on enum
    o << "\nenum class " << id_ << "\n{\n";
    o << "\n#else\n";
    o << "\nenum class SAL_DLLPUBLIC_RTTI " << id_ << "\n{\n";
    o << "\n#endif\n";
    o << "\n#else\n";
    o << "\nenum SAL_DLLPUBLIC_RTTI " << id_ << "\n{\n";
    o << "\n#endif\n";
    inc();
 
    for (const unoidl::EnumTypeEntity::Member& member : entity_->getMembers()) {
        o << indent() << id_ << "_" << u2b(member.name) << " = " << member.value
          << ",\n";
    }
 
    o << indent() << id_ << "_MAKE_FIXED_SIZE = SAL_MAX_ENUM\n";
 
    dec();
    o << "};\n\n";
 
    // use constexpr to create a kind of type-alias so we don't have to modify existing code
    o << "#if defined LIBO_INTERNAL_ONLY\n";
    for (const unoidl::EnumTypeEntity::Member& member : entity_->getMembers()) {
        o << "constexpr auto " << id_ << "_" << u2b(member.name)
          << " = "
          << id_ << "::" << id_ << "_" << u2b(member.name)
          << ";\n";
    }
    o << "#endif\n";
}
 
void EnumType::dumpHppFile(
    FileStream& o, codemaker::cppumaker::Includes & includes)
{
    OUString headerDefine(dumpHeaderDefine(o, u"HPP"));
    o << "\n";
 
    addDefaultHxxIncludes(includes);
    includes.dump(o, &name_, true);
    o << "\n";
 
    dumpGetCppuType(o);
 
    o << "\n#endif // "<< headerDefine << "\n";
}
 
void EnumType::dumpNormalGetCppuType(FileStream& o)
{
    dumpGetCppuTypePreamble(o);
 
    o << indent()
      << "static typelib_TypeDescriptionReference * the_type = 0;\n";
 
    o << indent() << "if ( !the_type )\n" << indent() << "{\n";
    inc();
 
    o << indent() << "typelib_static_enum_type_init( &the_type,\n";
    inc(31);
    o << indent() << "\"" << name_ << "\",\n"
      << indent() << codemaker::cpp::scopedCppName(u2b(name_)) << "_"
      << u2b(entity_->getMembers()[0].name) << " );\n";
    dec(31);
    dec();
    o << indent() << "}\n";
    o << indent()
      << ("return * reinterpret_cast< ::css::uno::Type * >("
          " &the_type );\n");
    dumpGetCppuTypePostamble(o);
}
 
void EnumType::dumpComprehensiveGetCppuType(FileStream& o)
{
    if (!isPolymorphic())
        codemaker::cppumaker::dumpNamespaceOpen(o, name_, false);
    else
        o << "namespace cppu { ";
    o << " namespace detail {\n\n";
 
    OUString sStaticTypeClass("the" + id_ + "Type");
    o << indent() << "struct " << sStaticTypeClass << " : public rtl::StaticWithInit< ::css::uno::Type *, " << sStaticTypeClass << " >\n";
    o << indent() << "{\n";
    inc();
    o << indent() << "::css::uno::Type * operator()() const\n";
    o << indent() << "{\n";
 
    inc();
    o << indent() << "::rtl::OUString sTypeName( \"" << name_
      << "\" );\n\n";
 
    o << indent() << "// Start inline typedescription generation\n"
      << indent() << "typelib_TypeDescription * pTD = 0;\n\n";
 
    o << indent() << "rtl_uString* enumValueNames["
      << entity_->getMembers().size() << "];\n";
    std::vector< unoidl::EnumTypeEntity::Member >::size_type n = 0;
    for (const unoidl::EnumTypeEntity::Member& member : entity_->getMembers()) {
        o << indent() << "::rtl::OUString sEnumValue" << n << "( \""
          << u2b(member.name) << "\" );\n";
        o << indent() << "enumValueNames[" << n << "] = sEnumValue" << n
          << ".pData;\n";
        ++n;
    }
 
    o << "\n" << indent() << "sal_Int32 enumValues["
      << entity_->getMembers().size() << "];\n";
    n = 0;
    for (const unoidl::EnumTypeEntity::Member& member : entity_->getMembers()) {
        o << indent() << "enumValues[" << n++ << "] = " << member.value << ";\n";
    }
 
    o << "\n" << indent() << "typelib_typedescription_newEnum( &pTD,\n";
    inc();
    o << indent() << "sTypeName.pData,\n"
      << indent() << "(sal_Int32)"
      << codemaker::cpp::scopedCppName(u2b(name_), false) << "_"
      << u2b(entity_->getMembers()[0].name) << ",\n"
      << indent() << entity_->getMembers().size()
      << ", enumValueNames, enumValues );\n\n";
    dec();
 
    o << indent()
      << ("typelib_typedescription_register( (typelib_TypeDescription**)&pTD"
          " );\n");
    o << indent() << "typelib_typedescription_release( pTD );\n"
      << indent() << "// End inline typedescription generation\n\n";
 
    o << indent() << "return new ::css::uno::Type( "
      << getTypeClass(name_) << ", sTypeName ); // leaked\n";
 
    dec();
    o << indent() << "}\n";
    dec();
    o << indent() << "};\n\n";
 
    if (!isPolymorphic())
        codemaker::cppumaker::dumpNamespaceClose(o, name_, false);
    else
        o << " }";
    o << " }\n\n";
 
    dumpGetCppuTypePreamble(o);
    o  << indent() << "return *detail::" << sStaticTypeClass << "::get();\n";
    dumpGetCppuTypePostamble(o);
}
 
class Typedef: public CppuType
{
public:
    Typedef(
        rtl::Reference< unoidl::TypedefEntity > const & entity,
        OUString const & name, rtl::Reference< TypeManager > const & typeMgr):
        CppuType(name, typeMgr), entity_(entity) {
        assert(entity.is());
    }
 
private:
    virtual void dumpDeclaration(FileStream& o) override;
 
    void dumpHdlFile(FileStream& o, codemaker::cppumaker::Includes & includes) override;
 
    void dumpHppFile(FileStream& o, codemaker::cppumaker::Includes & includes) override;
 
    rtl::Reference< unoidl::TypedefEntity > entity_;
};
 
void Typedef::dumpHdlFile(
    FileStream& o, codemaker::cppumaker::Includes & includes)
{
    OUString headerDefine(dumpHeaderDefine(o, u"HDL"));
    o << "\n";
 
    addDefaultHIncludes(includes);
    includes.dump(o, nullptr, true);
    o << "\n";
 
    if (codemaker::cppumaker::dumpNamespaceOpen(o, name_, false)) {
        o << "\n";
    }
 
    dumpDeclaration(o);
 
    if (codemaker::cppumaker::dumpNamespaceClose(o, name_, false)) {
        o << "\n";
    }
 
    o << "#endif // "<< headerDefine << "\n";
}
 
void Typedef::dumpDeclaration(FileStream& o)
{
    o << "\ntypedef ";
    dumpType(o, entity_->getType());
    o << " " << id_ << ";\n\n";
}
 
void Typedef::dumpHppFile(
    FileStream& o, codemaker::cppumaker::Includes & includes)
{
    OUString headerDefine(dumpHeaderDefine(o, u"HPP"));
    o << "\n";
 
    addDefaultHxxIncludes(includes);
    includes.dump(o, &name_, true);
    o << "\n";
 
    o << "\n#endif // "<< headerDefine << "\n";
}
 
class ConstructiveType: public CppuType
{
public:
    ConstructiveType(
        OUString const & name, rtl::Reference< TypeManager > const & manager):
        CppuType(name, manager) {}
 
private:
    virtual void dumpHdlFile(FileStream &, codemaker::cppumaker::Includes &) override {
        assert(false);    // this cannot happen
    }
 
    virtual void dumpFiles(OUString const & uri, CppuOptions const & options) override {
        dumpFile(uri, name_, FileType::HPP, options);
    }
};
 
bool hasRestParameter(
    unoidl::SingleInterfaceBasedServiceEntity::Constructor const & constructor)
{
    return !constructor.parameters.empty()
           && constructor.parameters.back().rest;
}
 
void includeExceptions(
    codemaker::cppumaker::Includes & includes,
    codemaker::ExceptionTreeNode const * node)
{
    if (node->present) {
        includes.add(node->name);
    } else {
        for (std::unique_ptr<codemaker::ExceptionTreeNode> const & pChild : node->children) {
            includeExceptions(includes, pChild.get());
        }
    }
}
 
class ServiceType: public ConstructiveType
{
public:
    ServiceType(
        rtl::Reference< unoidl::SingleInterfaceBasedServiceEntity > const &
        entity,
        OUString const & name, rtl::Reference< TypeManager > const & manager):
        ConstructiveType(name, manager), entity_(entity) {
        assert(entity.is());
    }
 
private:
    virtual void dumpHppFile(
        FileStream & o, codemaker::cppumaker::Includes & includes) override;
 
    void dumpCatchClauses(
        FileStream & out, codemaker::ExceptionTreeNode const * node);
 
    rtl::Reference< unoidl::SingleInterfaceBasedServiceEntity > entity_;
};
 
void failsToSupply(
    FileStream & o, std::u16string_view service, OString const & type)
{
    o << "::rtl::OUString(\"component context fails to supply service \") + \""
      << service << "\" + \" of type \" + \"" << type << "\"";
}
 
void ServiceType::dumpHppFile(
    FileStream & o, codemaker::cppumaker::Includes & includes)
{
    if (!entity_->getConstructors().empty()) {
        //TODO: Decide whether the types added to includes should rather be
        // added to m_dependencies (and thus be generated during
        // dumpDependedTypes):
        includes.addCassert();
        includes.addReference();
        includes.addRtlUstringH();
        includes.addRtlUstringHxx();
        includes.add("com.sun.star.uno.DeploymentException"_ostr);
        includes.add("com.sun.star.uno.XComponentContext"_ostr);
        for (const unoidl::SingleInterfaceBasedServiceEntity::Constructor& cons : entity_->getConstructors()) {
            if (cons.defaultConstructor) {
                includes.add("com.sun.star.uno.Exception"_ostr);
                includes.add("com.sun.star.uno.RuntimeException"_ostr);
            } else {
                if (!hasRestParameter(cons)) {
                    includes.addAny();
                    includes.addSequence();
                    for (const unoidl::SingleInterfaceBasedServiceEntity::Constructor::Parameter& param :
                         cons.parameters) {
                        if (m_typeMgr->getSort(
                                b2u(codemaker::UnoType::decompose(
                                        u2b(param.type))))
                            == codemaker::UnoType::Sort::Char) {
                            includes.addCppuUnotypeHxx();
                            break;
                        }
                    }
                }
                codemaker::ExceptionTree tree;
                for (const OUString& ex : cons.exceptions) {
                    tree.add(u2b(ex), m_typeMgr);
                }
                if (!tree.getRoot().present) {
                    includes.add("com.sun.star.uno.Exception"_ostr);
                    includes.add("com.sun.star.uno.RuntimeException"_ostr);
                    includeExceptions(includes, &tree.getRoot());
                }
            }
        }
    }
    OString cppName(
        codemaker::cpp::translateUnoToCppIdentifier(
            u2b(id_), "service", isGlobal()));
    OUString headerDefine(dumpHeaderDefine(o, u"HPP"));
    o << "\n";
    includes.dump(o, nullptr, true);
    if (!entity_->getConstructors().empty()) {
        o << ("\n#if defined ANDROID || defined IOS //TODO\n"
              "#include <com/sun/star/lang/XInitialization.hpp>\n"
              "#include <osl/detail/component-defines.h>\n#endif\n\n"
              "#if defined LO_URE_CURRENT_ENV && defined LO_URE_CTOR_ENV_")
          << name_.replaceAll(".", "_dot_")
          << " && (LO_URE_CURRENT_ENV) == (LO_URE_CTOR_ENV_"
          << name_.replaceAll(".", "_dot_") << ") && defined LO_URE_CTOR_FUN_"
          << name_.replaceAll(".", "_dot_")
          << "\nextern \"C\" ::css::uno::XInterface * SAL_CALL LO_URE_CTOR_FUN_"
          << name_.replaceAll(".", "_dot_")
          << "(::css::uno::XComponentContext *, ::css::uno::Sequence< "
          "::css::uno::Any > const &);\n#endif\n";
    }
    o << "\n";
    if (codemaker::cppumaker::dumpNamespaceOpen(o, name_, false)) {
        o << "\n";
    }
    o << "\nclass " << cppName << " {\n";
    inc();
    if (!entity_->getConstructors().empty()) {
        OString baseName(u2b(entity_->getBase()));
        OString scopedBaseName(codemaker::cpp::scopedCppName(baseName));
        o << "public:\n";
        for (const unoidl::SingleInterfaceBasedServiceEntity::Constructor& cons :
             entity_->getConstructors()) {
            if (cons.defaultConstructor) {
                o << indent() << "static ::css::uno::Reference< "
                  << scopedBaseName << " > "
                  << codemaker::cpp::translateUnoToCppIdentifier(
                      "create"_ostr, "method", codemaker::cpp::IdentifierTranslationMode::NonGlobal,
                      &cppName)
                  << ("(::css::uno::Reference< ::css::uno::XComponentContext > const &"
                      " the_context) {\n");
                inc();
                o << indent() << "assert(the_context.is());\n" << indent()
                  << "::css::uno::Reference< " << scopedBaseName
                  << " > the_instance;\n" << indent() << "try {\n";
                inc();
                o << ("#if defined LO_URE_CURRENT_ENV && defined "
                      "LO_URE_CTOR_ENV_")
                  << name_.replaceAll(".", "_dot_")
                  << " && (LO_URE_CURRENT_ENV) == (LO_URE_CTOR_ENV_"
                  << name_.replaceAll(".", "_dot_")
                  << ") && defined LO_URE_CTOR_FUN_"
                  << name_.replaceAll(".", "_dot_") << "\n" << indent()
                  << "the_instance = ::css::uno::Reference< " << scopedBaseName
                  << (" >(::css::uno::Reference< ::css::uno::XInterface >("
                      "static_cast< ::css::uno::XInterface * >((*"
                      "LO_URE_CTOR_FUN_")
                  << name_.replaceAll(".", "_dot_")
                  << (")(the_context.get(), ::css::uno::Sequence<"
                      " ::css::uno::Any >())), ::SAL_NO_ACQUIRE),"
                      " ::css::uno::UNO_QUERY);\n#else\n")
                  << indent() << "the_instance = ::css::uno::Reference< "
                  << scopedBaseName
                  << (" >(the_context->getServiceManager()->"
                      "createInstanceWithContext("
                      " \"")
                  << name_
                  << "\", the_context), ::css::uno::UNO_QUERY);\n#endif\n";
                dec();
                o << indent()
                  << "} catch (const ::css::uno::RuntimeException &) {\n";
                inc();
                o << indent() << "throw;\n";
                dec();
                o << indent()
                  << "} catch (const ::css::uno::Exception & the_exception) {\n";
                inc();
                o << indent() << "throw ::css::uno::DeploymentException(";
                failsToSupply(o, name_, baseName);
                o << " + \": \" + the_exception.Message, the_context);\n";
                dec();
                o << indent() << "}\n" << indent()
                  << "if (!the_instance.is()) {\n";
                inc();
                o << indent() << "throw ::css::uno::DeploymentException(";
                failsToSupply(o, name_, baseName);
                o << ", the_context);\n";
                dec();
                o << indent() << "}\n" << indent() << "return the_instance;\n";
                dec();
                o << indent() << "}\n\n";
            } else {
                o << indent() << "static ::css::uno::Reference< "
                  << scopedBaseName << " > "
                  << codemaker::cpp::translateUnoToCppIdentifier(
                      u2b(cons.name), "method", codemaker::cpp::IdentifierTranslationMode::NonGlobal,
                      &cppName)
                  << ("(::css::uno::Reference< ::css::uno::XComponentContext > const &"
                      " the_context");
                bool rest = hasRestParameter(cons);
                for (const unoidl::SingleInterfaceBasedServiceEntity::Constructor::Parameter& param :
                     cons.parameters) {
                    o << ", ";
                    OUStringBuffer buf(2 + param.type.getLength());
                    if (param.rest) {
                        buf.append("[]");
                    }
                    buf.append(param.type);
                    OUString type(buf.makeStringAndClear());
                    bool byRef = passByReference(type);
                    dumpType(o, type, byRef, byRef);
                    o << " "
                      << codemaker::cpp::translateUnoToCppIdentifier(
                          u2b(param.name), "param", codemaker::cpp::IdentifierTranslationMode::NonGlobal);
                }
                o << ") {\n";
                inc();
                o << indent() << "assert(the_context.is());\n";
                if (!rest && !cons.parameters.empty()) {
                    o << indent()
                      << "::css::uno::Sequence< ::css::uno::Any > the_arguments("
                      << cons.parameters.size() << ");\n";
                    o << indent()
                      << "::css::uno::Any* the_arguments_array = the_arguments.getArray();\n";
 
                    std::vector<
                    unoidl::SingleInterfaceBasedServiceEntity::Constructor::
                    Parameter >::size_type n = 0;
                    for (const unoidl::SingleInterfaceBasedServiceEntity::Constructor::Parameter& j :
                         cons.parameters) {
                        o << indent() << "the_arguments_array[" << n++ << "] ";
                        OString param(
                            codemaker::cpp::translateUnoToCppIdentifier(
                                u2b(j.name), "param",
                                codemaker::cpp::IdentifierTranslationMode::NonGlobal));
                        sal_Int32 rank;
                        if (resolveOuterTypedefs(j.type) == "any") {
                            o << "= " << param;
                        } else if (m_typeMgr->getSort(
                                       b2u(codemaker::UnoType::decompose(
                                               u2b(j.type), &rank)))
                                   == codemaker::UnoType::Sort::Char) {
                            o << "= ::css::uno::Any(&" << param
                              << ", ::cppu::UnoType< ";
                            for (sal_Int32 k = 0; k < rank; ++k) {
                                o << "::cppu::UnoSequenceType< ";
                            }
                            o << "::cppu::UnoCharType";
                            for (sal_Int32 k = 0; k < rank; ++k) {
                                o << " >";
                            }
                            o << " >::get())";
                        } else {
                            o << "<<= " << param;
                        }
                        o << ";\n";
                    }
                }
                o << indent() << "::css::uno::Reference< "
                  << scopedBaseName << " > the_instance;\n";
                codemaker::ExceptionTree tree;
                for (const OUString& ex : cons.exceptions) {
                    tree.add(u2b(ex), m_typeMgr);
                }
                if (!tree.getRoot().present) {
                    o << indent() << "try {\n";
                    inc();
                }
                o << ("#if defined LO_URE_CURRENT_ENV && defined "
                      "LO_URE_CTOR_ENV_")
                  << name_.replaceAll(".", "_dot_")
                  << " && (LO_URE_CURRENT_ENV) == (LO_URE_CTOR_ENV_"
                  << name_.replaceAll(".", "_dot_")
                  << ") && defined LO_URE_CTOR_FUN_"
                  << name_.replaceAll(".", "_dot_") << "\n" << indent()
                  << "the_instance = ::css::uno::Reference< " << scopedBaseName
                  << (" >(::css::uno::Reference< ::css::uno::XInterface >("
                      "static_cast< ::css::uno::XInterface * >((*"
                      "LO_URE_CTOR_FUN_")
                  << name_.replaceAll(".", "_dot_")
                  << ")(the_context.get(), ";
                if (rest) {
                    o << codemaker::cpp::translateUnoToCppIdentifier(
                          u2b(cons.parameters.back().name), "param",
                          codemaker::cpp::IdentifierTranslationMode::NonGlobal);
                } else if (cons.parameters.empty()) {
                    o << "::css::uno::Sequence< ::css::uno::Any >()";
                } else {
                    o << "the_arguments";
                }
                o << ")), ::SAL_NO_ACQUIRE), ::css::uno::UNO_QUERY);\n" << indent()
                  << ("::css::uno::Reference< ::css::lang::XInitialization > "
                      "init(the_instance, ::css::uno::UNO_QUERY);\n")
                  << indent() << "if (init.is()) {\n"
                  << indent() << "    init->initialize(";
                if (cons.parameters.empty()) {
                    o << "::css::uno::Sequence< ::css::uno::Any >()";
                } else {
                    o << "the_arguments";
                }
                o << ");\n" << indent() << "}\n";
                o << "#else\n"
                  << indent() << "the_instance = ::css::uno::Reference< "
                  << scopedBaseName
                  << (" >(the_context->getServiceManager()->"
                      "createInstanceWithArgumentsAndContext("
                      " \"")
                  << name_ << "\", ";
                if (rest) {
                    o << codemaker::cpp::translateUnoToCppIdentifier(
                          u2b(cons.parameters.back().name), "param",
                          codemaker::cpp::IdentifierTranslationMode::NonGlobal);
                } else if (cons.parameters.empty()) {
                    o << "::css::uno::Sequence< ::css::uno::Any >()";
                } else {
                    o << "the_arguments";
                }
                o << ", the_context), ::css::uno::UNO_QUERY);\n#endif\n";
                if (!tree.getRoot().present) {
                    dec();
                    o << indent()
                      << "} catch (const ::css::uno::RuntimeException &) {\n";
                    inc();
                    o << indent() << "throw;\n";
                    dec();
                    dumpCatchClauses(o, &tree.getRoot());
                    o << indent()
                      << ("} catch (const ::css::uno::Exception &"
                          " the_exception) {\n");
                    inc();
                    o << indent() << "throw ::css::uno::DeploymentException(";
                    failsToSupply(o, name_, baseName);
                    o << " + \": \" + the_exception.Message, the_context);\n";
                    dec();
                    o << indent() << "}\n";
                }
                o << indent() << "if (!the_instance.is()) {\n";
                inc();
                o << indent() << "throw ::css::uno::DeploymentException(";
                failsToSupply(o, name_, baseName);
                o << ", the_context);\n";
                dec();
                o << indent() << "}\n" << indent() << "return the_instance;\n";
                dec();
                o << indent() << "}\n\n";
            }
        }
    }
    o << "private:\n";
    o << indent() << cppName << "(); // not implemented\n"
      << indent() << cppName << "(" << cppName << " &); // not implemented\n"
      << indent() << "~" << cppName << "(); // not implemented\n"
      << indent() << "void operator =(" << cppName << "); // not implemented\n";
    dec();
    o << "};\n\n";
    if (codemaker::cppumaker::dumpNamespaceClose(o, name_, false)) {
        o << "\n";
    }
    o << "\n#endif // "<< headerDefine << "\n";
}
 
void ServiceType::dumpCatchClauses(
    FileStream & out, codemaker::ExceptionTreeNode const * node)
{
    if (node->present) {
        out << indent() << "} catch (const ";
        dumpType(out, b2u(node->name));
        out << " &) {\n";
        inc();
        out << indent() << "throw;\n";
        dec();
    } else {
        for (std::unique_ptr<codemaker::ExceptionTreeNode> const & pChild : node->children) {
            dumpCatchClauses(out, pChild.get());
        }
    }
}
 
class SingletonType: public ConstructiveType
{
public:
    SingletonType(
        rtl::Reference< unoidl::InterfaceBasedSingletonEntity > const & entity,
        OUString const & name, rtl::Reference< TypeManager > const & manager):
        ConstructiveType(name, manager), entity_(entity) {
        assert(entity.is());
    }
 
private:
    virtual void dumpHppFile(
        FileStream & o, codemaker::cppumaker::Includes & includes) override;
 
    rtl::Reference< unoidl::InterfaceBasedSingletonEntity > entity_;
};
 
void SingletonType::dumpHppFile(
    FileStream & o, codemaker::cppumaker::Includes & includes)
{
    OString cppName(
        codemaker::cpp::translateUnoToCppIdentifier(
            u2b(id_), "singleton", isGlobal()));
    OString baseName(u2b(entity_->getBase()));
    OString scopedBaseName(codemaker::cpp::scopedCppName(baseName));
    OUString headerDefine(dumpHeaderDefine(o, u"HPP"));
    o << "\n";
    //TODO: Decide whether the types added to includes should rather be added to
    // m_dependencies (and thus be generated during dumpDependedTypes):
    includes.add("com.sun.star.uno.DeploymentException"_ostr);
    includes.add("com.sun.star.uno.XComponentContext"_ostr);
    includes.addCassert();
    includes.addAny();
    includes.addReference();
    includes.addRtlUstringH();
    includes.addRtlUstringHxx();
    includes.dump(o, nullptr, true);
    o << ("\n#if defined ANDROID || defined IOS //TODO\n"
          "#include <com/sun/star/lang/XInitialization.hpp>\n"
          "#include <osl/detail/component-defines.h>\n#endif\n\n"
          "#if defined LO_URE_CURRENT_ENV && defined LO_URE_CTOR_ENV_")
      << name_.replaceAll(".", "_dot_")
      << " && (LO_URE_CURRENT_ENV) == (LO_URE_CTOR_ENV_"
      << name_.replaceAll(".", "_dot_") << ") && defined LO_URE_CTOR_FUN_"
      << name_.replaceAll(".", "_dot_")
      << "\nextern \"C\" ::css::uno::XInterface * SAL_CALL LO_URE_CTOR_FUN_"
      << name_.replaceAll(".", "_dot_")
      << "(::css::uno::XComponentContext *, ::css::uno::Sequence< "
      "::css::uno::Any > const &);\n#endif\n";
    o << "\n";
    if (codemaker::cppumaker::dumpNamespaceOpen(o, name_, false)) {
        o << "\n";
    }
    o << "\nclass " << cppName << " {\npublic:\n";
    inc();
    o << indent() << "static ::css::uno::Reference< "
      << scopedBaseName << " > "
      << codemaker::cpp::translateUnoToCppIdentifier(
          "get"_ostr, "method", codemaker::cpp::IdentifierTranslationMode::NonGlobal, &cppName)
      << ("(::css::uno::Reference<"
          " ::css::uno::XComponentContext > const & the_context)"
          " {\n");
    inc();
    o << indent() << "assert(the_context.is());\n" << indent()
      << "::css::uno::Reference< " << scopedBaseName
      << (" > instance;\n#if defined LO_URE_CURRENT_ENV && defined "
          "LO_URE_CTOR_ENV_")
      << name_.replaceAll(".", "_dot_")
      << " && (LO_URE_CURRENT_ENV) == (LO_URE_CTOR_ENV_"
      << name_.replaceAll(".", "_dot_")
      << ") && defined LO_URE_CTOR_FUN_"
      << name_.replaceAll(".", "_dot_") << "\n" << indent()
      << "instance = ::css::uno::Reference< " << scopedBaseName
      << (" >(::css::uno::Reference< ::css::uno::XInterface >("
          "static_cast< ::css::uno::XInterface * >((*"
          "LO_URE_CTOR_FUN_")
      << name_.replaceAll(".", "_dot_")
      << (")(the_context.get(), ::css::uno::Sequence<"
          " ::css::uno::Any >())), ::SAL_NO_ACQUIRE),"
          " ::css::uno::UNO_QUERY);\n#else\n")
      << indent() << ("the_context->getValueByName("
                      "::rtl::OUString( \"/singletons/")
      << name_ << "\" )) >>= instance;\n#endif\n"
      << indent() << "if (!instance.is()) {\n";
    inc();
    o << indent()
      << ("throw ::css::uno::DeploymentException("
          "::rtl::OUString( \"component context"
          " fails to supply singleton ")
      << name_ << " of type " << baseName << "\" ), the_context);\n";
    dec();
    o << indent() << "}\n" << indent() << "return instance;\n";
    dec();
    o << indent() << "}\n\n";
    o << "private:\n";
    o << indent() << cppName << "(); // not implemented\n"
      << indent() << cppName << "(" << cppName << " &); // not implemented\n"
      << indent() << "~" << cppName << "(); // not implemented\n"
      << indent() << "void operator =(" << cppName << "); // not implemented\n";
    dec();
    o << "};\n\n";
    if (codemaker::cppumaker::dumpNamespaceClose(o, name_, false)) {
        o << "\n";
    }
    o << "\n#endif // "<< headerDefine << "\n";
}
 
}
 
void produce(
    OUString const & name, rtl::Reference< TypeManager > const & manager,
    codemaker::GeneratedTypeSet & generated, CppuOptions const & options)
{
    if (generated.contains(u2b(name))) {
        return;
    }
    generated.add(u2b(name));
    if (!manager->foundAtPrimaryProvider(name)) {
        return;
    }
    rtl::Reference< unoidl::Entity > ent;
    rtl::Reference< unoidl::MapCursor > cur;
    switch (manager->getSort(name, &ent, &cur)) {
    case codemaker::UnoType::Sort::Module: {
        OUString prefix;
        if (!name.isEmpty()) {
            prefix = name + ".";
        }
        for (;;) {
            OUString mem;
            if (!cur->getNext(&mem).is()) {
                break;
            }
            produce(prefix + mem, manager, generated, options);
        }
        break;
    }
    case codemaker::UnoType::Sort::Enum: {
        EnumType t(
            dynamic_cast< unoidl::EnumTypeEntity * >(ent.get()), name,
            manager);
        t.dump(options);
        t.dumpDependedTypes(generated, options);
        break;
    }
    case codemaker::UnoType::Sort::PlainStruct: {
        PlainStructType t(
            dynamic_cast< unoidl::PlainStructTypeEntity * >(ent.get()),
            name, manager);
        t.dump(options);
        t.dumpDependedTypes(generated, options);
        break;
    }
    case codemaker::UnoType::Sort::PolymorphicStructTemplate: {
        PolyStructType t(
            dynamic_cast< unoidl::PolymorphicStructTypeTemplateEntity * >(
                ent.get()),
            name, manager);
        t.dump(options);
        t.dumpDependedTypes(generated, options);
        break;
    }
    case codemaker::UnoType::Sort::Exception: {
        ExceptionType t(
            dynamic_cast< unoidl::ExceptionTypeEntity * >(ent.get()), name,
            manager);
        t.dump(options);
        t.dumpDependedTypes(generated, options);
        break;
    }
    case codemaker::UnoType::Sort::Interface: {
        InterfaceType t(
            dynamic_cast< unoidl::InterfaceTypeEntity * >(ent.get()), name,
            manager);
        t.dump(options);
        t.dumpDependedTypes(generated, options);
        break;
    }
    case codemaker::UnoType::Sort::Typedef: {
        Typedef t(
            dynamic_cast< unoidl::TypedefEntity * >(ent.get()), name,
            manager);
        t.dump(options);
        t.dumpDependedTypes(generated, options);
        break;
    }
    case codemaker::UnoType::Sort::ConstantGroup: {
        ConstantGroup t(
            dynamic_cast< unoidl::ConstantGroupEntity * >(ent.get()), name,
            manager);
        if (t.hasConstants()) {
            t.dump(options);
        }
        break;
    }
    case codemaker::UnoType::Sort::SingleInterfaceBasedService: {
        ServiceType t(
            dynamic_cast< unoidl::SingleInterfaceBasedServiceEntity * >(
                ent.get()),
            name, manager);
        t.dump(options);
        t.dumpDependedTypes(generated, options);
        break;
    }
    case codemaker::UnoType::Sort::InterfaceBasedSingleton: {
        SingletonType t(
            dynamic_cast< unoidl::InterfaceBasedSingletonEntity * >(
                ent.get()),
            name, manager);
        t.dump(options);
        t.dumpDependedTypes(generated, options);
        break;
    }
    case codemaker::UnoType::Sort::AccumulationBasedService:
    case codemaker::UnoType::Sort::ServiceBasedSingleton:
        break;
    default:
        throw CannotDumpException(
            "unexpected entity \"" + name + "\" in call to produce");
    }
}
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V530 The return value of function 'dumpHeaderDefine' is required to be utilized.

V530 The return value of function 'append' is required to be utilized.

V530 The return value of function 'replace' is required to be utilized.

V530 The return value of function 'replace' is required to be utilized.

V530 The return value of function 'replace' is required to be utilized.

V530 The return value of function 'replace' is required to be utilized.

V530 The return value of function 'replace' is required to be utilized.