diff options
Diffstat (limited to 'unodevtools/source/skeletonmaker/skeletoncommon.cxx')
-rw-r--r-- | unodevtools/source/skeletonmaker/skeletoncommon.cxx | 589 |
1 files changed, 589 insertions, 0 deletions
diff --git a/unodevtools/source/skeletonmaker/skeletoncommon.cxx b/unodevtools/source/skeletonmaker/skeletoncommon.cxx new file mode 100644 index 000000000..664bc9088 --- /dev/null +++ b/unodevtools/source/skeletonmaker/skeletoncommon.cxx @@ -0,0 +1,589 @@ +/* -*- 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 <codemaker/commoncpp.hxx> +#include <codemaker/generatedtypeset.hxx> +#include <codemaker/global.hxx> +#include <unoidl/unoidl.hxx> + +#include "skeletoncommon.hxx" + +#include <algorithm> +#include <cassert> +#include <iostream> +#include <string_view> + +using namespace ::codemaker::cpp; + +namespace skeletonmaker { + +void printLicenseHeader(std::ostream& o) +{ + o << "/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */\n" + "/*\n" + " * This file is part of the LibreOffice project.\n" + " *\n" + " * This Source Code Form is subject to the terms of the Mozilla Public\n" + " * License, v. 2.0. If a copy of the MPL was not distributed with this\n" + " * file, You can obtain one at http://mozilla.org/MPL/2.0/.\n" + " */\n\n"; +} + +bool getOutputStream(ProgramOptions const & options, + OString const & extension, + std::ostream** ppOutputStream, + OString & targetSourceFileName, + OString & tmpSourceFileName) +{ + bool bStandardout = false; + if ( options.outputpath == "stdout" ) + { + bStandardout = true; + *ppOutputStream = &std::cout; + return bStandardout; + } + + targetSourceFileName = createFileNameFromType( + options.outputpath, options.implname.replace('.','/'), extension); + + OString tmpDir = getTempDir(targetSourceFileName); + FileStream file; + file.createTempFile(tmpDir); + + if( !file.isValid() ) + { + throw CannotDumpException( + "cannot open " + b2u(targetSourceFileName) + " for writing"); + } + tmpSourceFileName = file.getName(); + file.close(); + *ppOutputStream = new std::ofstream(tmpSourceFileName.getStr(), + std::ios_base::binary); + + return bStandardout; +} + +static bool containsAttribute(AttributeInfo& attributes, OUString const & attrname) +{ + return std::any_of(attributes.begin(), attributes.end(), + [&attrname](const unoidl::AccumulationBasedServiceEntity::Property& rAttr) { + return rAttr.name == attrname; }); +} + +// collect attributes including inherited attributes +static void checkAttributes(rtl::Reference< TypeManager > const & manager, + OUString const & name, + AttributeInfo& attributes, + std::set< OUString >& propinterfaces) +{ + if ( name == "com.sun.star.beans.XPropertySet" || + name == "com.sun.star.beans.XFastPropertySet" || + name == "com.sun.star.beans.XPropertyAccess" ) + { + propinterfaces.insert(name); + } + rtl::Reference< unoidl::Entity > ent; + switch (manager->getSort(name, &ent)) { + case codemaker::UnoType::Sort::Interface: + { + rtl::Reference< unoidl::InterfaceTypeEntity > ent2( + dynamic_cast< unoidl::InterfaceTypeEntity * >(ent.get())); + assert(ent2.is()); + for (const auto& rBase : ent2->getDirectMandatoryBases()) + { + checkAttributes(manager, rBase.name, attributes, propinterfaces); + } + for (const auto& rAttr : ent2->getDirectAttributes()) + { + if (!containsAttribute(attributes, rAttr.name)) { + attributes.emplace_back( + rAttr.name, rAttr.type, + (unoidl::AccumulationBasedServiceEntity::Property:: + Attributes( + ((rAttr.bound + ? unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_BOUND + : 0) + | (rAttr.readOnly + ? unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_READ_ONLY + : 0)))), + std::vector< OUString >()); + } + } + break; + } + case codemaker::UnoType::Sort::AccumulationBasedService: + { + rtl::Reference< unoidl::AccumulationBasedServiceEntity > ent2( + dynamic_cast< unoidl::AccumulationBasedServiceEntity * >( + ent.get())); + assert(ent2.is()); + for (const auto& rService : ent2->getDirectMandatoryBaseServices()) + { + checkAttributes(manager, rService.name, attributes, propinterfaces); + } + for (const auto& rIface : ent2->getDirectMandatoryBaseInterfaces()) + { + checkAttributes(manager, rIface.name, attributes, propinterfaces); + } + for (const auto& rProp : ent2->getDirectProperties()) + { + if (!containsAttribute(attributes, rProp.name)) { + attributes.push_back(rProp); + } + } + break; + } + default: + throw CannotDumpException( + "unexpected entity \"" + name + + "\" in call to skeletonmaker::checkAttributes"); + } +} + +void checkType(rtl::Reference< TypeManager > const & manager, + OUString const & name, + std::set< OUString >& interfaceTypes, + std::set< OUString >& serviceTypes, + AttributeInfo& properties) +{ + rtl::Reference< unoidl::Entity > ent; + switch (manager->getSort(name, &ent)) { + case codemaker::UnoType::Sort::Interface: + // com.sun.star.lang.XComponent should be also not in the list + // but it will be used for checking the impl helper and will be + // removed later if necessary. + if ( name == "com.sun.star.lang.XTypeProvider" || + name == "com.sun.star.uno.XWeak" ) + return; + interfaceTypes.insert(name); + break; + case codemaker::UnoType::Sort::SingleInterfaceBasedService: + if (serviceTypes.insert(name).second) { + rtl::Reference< unoidl::SingleInterfaceBasedServiceEntity > ent2( + dynamic_cast< unoidl::SingleInterfaceBasedServiceEntity * >( + ent.get())); + assert(ent2.is()); + if (interfaceTypes.insert(ent2->getBase()).second) { + // check if constructors are specified, if yes automatically + // support of XInitialization. We will take care of the default + // constructor because in this case XInitialization is not + // called. + if (ent2->getConstructors().size() > 1 || + (ent2->getConstructors().size() == 1 && + !ent2->getConstructors()[0].defaultConstructor)) + { + interfaceTypes.insert(OUString("com.sun.star.lang.XInitialization")); + } + } + } + break; + case codemaker::UnoType::Sort::AccumulationBasedService: + if ( serviceTypes.insert(name).second ) { + rtl::Reference< unoidl::AccumulationBasedServiceEntity > ent2( + dynamic_cast< unoidl::AccumulationBasedServiceEntity * >( + ent.get())); + assert(ent2.is()); + for (const auto& rService : ent2->getDirectMandatoryBaseServices()) + { + checkType( + manager, rService.name, interfaceTypes, serviceTypes, properties); + } + for (const auto& rIface : ent2->getDirectMandatoryBaseInterfaces()) + { + checkType( + manager, rIface.name, interfaceTypes, serviceTypes, properties); + } + for (const auto& rProp : ent2->getDirectProperties()) + { + properties.push_back(rProp); + } + } + break; + default: + throw CannotDumpException( + "unexpected entity \"" + name + + "\" in call to skeletonmaker::checkType"); + } +} + +void checkDefaultInterfaces( + std::set< OUString >& interfaces, + const std::set< OUString >& services, + std::u16string_view propertyhelper) +{ + if ( services.empty() ) { + interfaces.erase("com.sun.star.lang.XServiceInfo"); + } else { + interfaces.insert("com.sun.star.lang.XServiceInfo"); + } + + if ( propertyhelper == u"_" ) { + interfaces.erase("com.sun.star.beans.XPropertySet"); + interfaces.erase("com.sun.star.beans.XFastPropertySet"); + interfaces.erase("com.sun.star.beans.XPropertyAccess"); + } +} + +static bool checkServiceProperties(rtl::Reference< TypeManager > const & manager, + OUString const & name) +{ + rtl::Reference< unoidl::Entity > ent; + if (manager->getSort(name, &ent) + == codemaker::UnoType::Sort::AccumulationBasedService) + { + rtl::Reference< unoidl::AccumulationBasedServiceEntity > ent2( + dynamic_cast< unoidl::AccumulationBasedServiceEntity * >( + ent.get())); + assert(ent2.is()); + if (!ent2->getDirectProperties().empty()) { + return true; + } + return std::any_of(ent2->getDirectMandatoryBaseServices().begin(), + ent2->getDirectMandatoryBaseServices().end(), + [&manager](const unoidl::AnnotatedReference& rService) { + return checkServiceProperties(manager, rService.name); }); + } + return false; +} + + +OUString checkPropertyHelper( + ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + const std::set< OUString >& services, + const std::set< OUString >& interfaces, + AttributeInfo& attributes, + std::set< OUString >& propinterfaces) +{ + std::set< OUString >::const_iterator iter; + std::set< OUString >::const_iterator end; + + if ( !services.empty() ) { + iter = services.begin(); + end = services.end(); + } else { + iter = interfaces.begin(); + end = interfaces.end(); + } + + bool oldStyleWithProperties = false; + while ( iter != end ) { + rtl::Reference< unoidl::Entity > ent; + codemaker::UnoType::Sort sort = manager->getSort(*iter, &ent); + if ( !services.empty() ) { + if (options.supportpropertysetmixin + && (sort + == codemaker::UnoType::Sort::SingleInterfaceBasedService)) + { + rtl::Reference< unoidl::SingleInterfaceBasedServiceEntity > + ent2( + dynamic_cast< + unoidl::SingleInterfaceBasedServiceEntity * >( + ent.get())); + assert(ent2.is()); + checkAttributes( + manager, ent2->getBase(), attributes, propinterfaces); + if (!(attributes.empty() || propinterfaces.empty())) { + return ent2->getBase(); + } + } else { + oldStyleWithProperties = checkServiceProperties(manager, *iter); + } + } else { + checkAttributes(manager, *iter, attributes, propinterfaces); + if (!(attributes.empty() || propinterfaces.empty())) { + return *iter; + } + } + ++iter; + } + + return oldStyleWithProperties ? OUString("_") : OUString(); +} + +static bool checkXComponentSupport( + rtl::Reference< TypeManager > const & manager, OUString const & name) +{ + assert(manager.is()); + if (name == "com.sun.star.lang.XComponent") { + return true; + } + rtl::Reference< unoidl::Entity > ent; + codemaker::UnoType::Sort sort = manager->getSort(name, &ent); + if (sort != codemaker::UnoType::Sort::Interface) { + throw CannotDumpException( + "unexpected entity \"" + name + + "\" in call to skeletonmaker::checkXComponentSupport"); + } + rtl::Reference< unoidl::InterfaceTypeEntity > ent2( + dynamic_cast< unoidl::InterfaceTypeEntity * >(ent.get())); + assert(ent2.is()); + return std::any_of(ent2->getDirectMandatoryBases().begin(), ent2->getDirectMandatoryBases().end(), + [&manager](const unoidl::AnnotatedReference& rBase) { return checkXComponentSupport(manager, rBase.name); }); +} + + +// if XComponent is directly specified, return true and remove it from the +// supported interfaces list +bool checkXComponentSupport(rtl::Reference< TypeManager > const & manager, + std::set< OUString >& interfaces) +{ + if ( interfaces.empty() ) + return false; + + for ( const auto& rIface : interfaces ) { + if ( rIface == "com.sun.star.lang.XComponent" ) { + interfaces.erase("com.sun.star.lang.XComponent"); + return true; + } + if ( checkXComponentSupport(manager, rIface) ) + return true; + } + + return false; +} + +unoidl::AccumulationBasedServiceEntity::Property::Attributes +checkAdditionalPropertyFlags( + unoidl::InterfaceTypeEntity::Attribute const & attribute) +{ + int flags = 0; + bool getterSupportsUnknown = false; + for (const auto& rException : attribute.getExceptions) + { + if (rException == "com.sun.star.beans.UnknownPropertyException") { + getterSupportsUnknown = true; + } + } + for (const auto& rException : attribute.setExceptions) + { + if (rException == "com.sun.star.beans.PropertyVetoException") { + flags |= unoidl::AccumulationBasedServiceEntity::Property:: + ATTRIBUTE_CONSTRAINED; + } else if (getterSupportsUnknown + && rException == "com.sun.star.beans.UnknownPropertyException") + { + flags |= unoidl::AccumulationBasedServiceEntity::Property:: + ATTRIBUTE_OPTIONAL; + } + } + return unoidl::AccumulationBasedServiceEntity::Property::Attributes(flags); +} + +// This function checks if the specified types for parameters and return +// types are allowed add-in types, for more info see the com.sun.star.sheet.AddIn +// service description +static bool checkAddinType(rtl::Reference< TypeManager > const & manager, + std::u16string_view type, bool & bLastAny, + bool & bHasXPropertySet, bool bIsReturn) +{ + assert(manager.is()); + sal_Int32 rank; + codemaker::UnoType::Sort sort = manager->decompose( + type, true, nullptr, &rank, nullptr, nullptr); + + if ( sort == codemaker::UnoType::Sort::Long || + sort == codemaker::UnoType::Sort::Double || + sort == codemaker::UnoType::Sort::String ) + { + if ( rank == 0 || rank ==2 ) + return true; + } + if ( sort == codemaker::UnoType::Sort::Any ) + { + if ( rank <= 2 ) { + if ( rank ==1 ) { + if ( bIsReturn ) + return false; + bLastAny = true; + } + + return true; + } + } + if ( sort == codemaker::UnoType::Sort::Interface ) + { + if ( bIsReturn && type == u"com.sun.star.sheet.XVolatileResult" ) + return true; + if ( !bIsReturn && type == u"com.sun.star.table.XCellRange" ) + return true; + if ( !bIsReturn && type == u"com.sun.star.beans.XPropertySet" ) + { + if ( bHasXPropertySet ) { + return false; + } else { + bHasXPropertySet = true; + return true; + } + } + } + return false; +} + +static void checkAddInTypes( + rtl::Reference< TypeManager > const & manager, std::u16string_view name, + rtl::Reference< unoidl::InterfaceTypeEntity > const & entity) +{ + assert(entity.is()); + bool bLastAny = false; + bool bHasXPropertySet = false; + for (const auto& rMethod : entity->getDirectMethods()) + { + if ( !checkAddinType( + manager, rMethod.returnType, bLastAny, bHasXPropertySet, true) ) + { + throw CannotDumpException( + OUString::Concat("the return type of the calc add-in function '") + name + + ":" + rMethod.name + + "' is invalid. Please check your IDL definition."); + } + + bHasXPropertySet = false; + for (const auto& rParam : rMethod.parameters) + { + bLastAny = false; + if ( !checkAddinType(manager, rParam.type, + bLastAny, bHasXPropertySet, false) || + bLastAny ) + { + throw CannotDumpException( + "the type of the " + rParam.name + + " parameter of the calc add-in function '" + name + + ":" + rMethod.name + "' is invalid." + + (bLastAny + ? OUString( + " The type 'sequence<any>' is allowed as last" + " parameter only.") + : OUString()) + + (bHasXPropertySet + ? OUString( + " The type 'XPropertySet' is allowed only once.") + : OUString()) + + " Please check your IDL definition."); + } + } + } +} + +static void generateFunctionParameterMap(std::ostream& o, + ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + OUString const & name, + ::codemaker::GeneratedTypeSet & generated, + bool& bFirst) +{ + if ( name == "com.sun.star.uno.XInterface" || + name == "com.sun.star.lang.XLocalizable" || + name == "com.sun.star.lang.XServiceInfo" || + // the next three checks becomes obsolete when configuration is used + name == "com.sun.star.sheet.XAddIn" || + name == "com.sun.star.sheet.XCompatibilityNames" || + name == "com.sun.star.lang.XServiceName" ) + { + return; + } + + rtl::Reference< unoidl::Entity > ent; + codemaker::UnoType::Sort sort = manager->getSort(name, &ent); + if (sort != codemaker::UnoType::Sort::Interface) { + throw CannotDumpException( + "unexpected entity \"" + name + + "\" in call to skeletonmaker::generateFunctionParameterMap"); + } + rtl::Reference< unoidl::InterfaceTypeEntity > ent2( + dynamic_cast< unoidl::InterfaceTypeEntity * >(ent.get())); + assert(ent2.is()); + + // check if the specified add-in functions supports valid types + checkAddInTypes(manager, name, ent2); + + for (const auto& rBase : ent2->getDirectMandatoryBases()) + { + generateFunctionParameterMap( + o, options, manager, rBase.name, generated, bFirst); + } + + if ( generated.contains(u2b(name)) ) + return; + else + generated.add(u2b(name)); + + for (const auto& rMethod : ent2->getDirectMethods()) + { + if ( bFirst ) { + if (options.language == 2) { + o << " ParamMap fpm;\n"; + } + else { + o << " java.util.Hashtable< Integer, String > fpm = " + "new java.util.Hashtable< Integer, String >();\n"; + } + bFirst = false; + } else + if ( options.language == 2 ) { + o << " fpm = ParamMap();\n"; + } + else { + o << " fpm = new java.util.Hashtable< " + "Integer, String >();\n"; + } + + std::vector< unoidl::InterfaceTypeEntity::Method::Parameter >::size_type + n = 0; + for (const auto& rParam : rMethod.parameters) + { + if ( options.language == 2 ) { + o << " fpm[" << n + << "] = OUString(\"" + << rParam.name + << "\");\n"; + } + else { + o << " fpm.put(" << n << ", \"" + << rParam.name + << "\");\n"; + } + ++n; + } + + if ( options.language == 2 ) { + o << " m_functionMap[OUString(\"" + << rMethod.name << "\")] = fpm;\n\n"; + } + else { + o << " m_functionMap.put(\"" << rMethod.name << "\", fpm);\n\n"; + } + } +} + +void generateFunctionParameterMap(std::ostream& o, + ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + const std::set< OUString >& interfaces) +{ + ::codemaker::GeneratedTypeSet generated; + bool bFirst = true; + for ( const auto& rIface : interfaces ) { + generateFunctionParameterMap(o, options, manager, rIface, generated, bFirst); + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |