Bump version to 24.04.3.4
[LibreOffice.git] / unodevtools / source / skeletonmaker / skeletoncommon.cxx
blob664bc90888aabc1e3d781867e6eefaab75786bd0
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <codemaker/commoncpp.hxx>
21 #include <codemaker/generatedtypeset.hxx>
22 #include <codemaker/global.hxx>
23 #include <unoidl/unoidl.hxx>
25 #include "skeletoncommon.hxx"
27 #include <algorithm>
28 #include <cassert>
29 #include <iostream>
30 #include <string_view>
32 using namespace ::codemaker::cpp;
34 namespace skeletonmaker {
36 void printLicenseHeader(std::ostream& o)
38 o << "/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */\n"
39 "/*\n"
40 " * This file is part of the LibreOffice project.\n"
41 " *\n"
42 " * This Source Code Form is subject to the terms of the Mozilla Public\n"
43 " * License, v. 2.0. If a copy of the MPL was not distributed with this\n"
44 " * file, You can obtain one at http://mozilla.org/MPL/2.0/.\n"
45 " */\n\n";
48 bool getOutputStream(ProgramOptions const & options,
49 OString const & extension,
50 std::ostream** ppOutputStream,
51 OString & targetSourceFileName,
52 OString & tmpSourceFileName)
54 bool bStandardout = false;
55 if ( options.outputpath == "stdout" )
57 bStandardout = true;
58 *ppOutputStream = &std::cout;
59 return bStandardout;
62 targetSourceFileName = createFileNameFromType(
63 options.outputpath, options.implname.replace('.','/'), extension);
65 OString tmpDir = getTempDir(targetSourceFileName);
66 FileStream file;
67 file.createTempFile(tmpDir);
69 if( !file.isValid() )
71 throw CannotDumpException(
72 "cannot open " + b2u(targetSourceFileName) + " for writing");
74 tmpSourceFileName = file.getName();
75 file.close();
76 *ppOutputStream = new std::ofstream(tmpSourceFileName.getStr(),
77 std::ios_base::binary);
79 return bStandardout;
82 static bool containsAttribute(AttributeInfo& attributes, OUString const & attrname)
84 return std::any_of(attributes.begin(), attributes.end(),
85 [&attrname](const unoidl::AccumulationBasedServiceEntity::Property& rAttr) {
86 return rAttr.name == attrname; });
89 // collect attributes including inherited attributes
90 static void checkAttributes(rtl::Reference< TypeManager > const & manager,
91 OUString const & name,
92 AttributeInfo& attributes,
93 std::set< OUString >& propinterfaces)
95 if ( name == "com.sun.star.beans.XPropertySet" ||
96 name == "com.sun.star.beans.XFastPropertySet" ||
97 name == "com.sun.star.beans.XPropertyAccess" )
99 propinterfaces.insert(name);
101 rtl::Reference< unoidl::Entity > ent;
102 switch (manager->getSort(name, &ent)) {
103 case codemaker::UnoType::Sort::Interface:
105 rtl::Reference< unoidl::InterfaceTypeEntity > ent2(
106 dynamic_cast< unoidl::InterfaceTypeEntity * >(ent.get()));
107 assert(ent2.is());
108 for (const auto& rBase : ent2->getDirectMandatoryBases())
110 checkAttributes(manager, rBase.name, attributes, propinterfaces);
112 for (const auto& rAttr : ent2->getDirectAttributes())
114 if (!containsAttribute(attributes, rAttr.name)) {
115 attributes.emplace_back(
116 rAttr.name, rAttr.type,
117 (unoidl::AccumulationBasedServiceEntity::Property::
118 Attributes(
119 ((rAttr.bound
120 ? unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_BOUND
121 : 0)
122 | (rAttr.readOnly
123 ? unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_READ_ONLY
124 : 0)))),
125 std::vector< OUString >());
128 break;
130 case codemaker::UnoType::Sort::AccumulationBasedService:
132 rtl::Reference< unoidl::AccumulationBasedServiceEntity > ent2(
133 dynamic_cast< unoidl::AccumulationBasedServiceEntity * >(
134 ent.get()));
135 assert(ent2.is());
136 for (const auto& rService : ent2->getDirectMandatoryBaseServices())
138 checkAttributes(manager, rService.name, attributes, propinterfaces);
140 for (const auto& rIface : ent2->getDirectMandatoryBaseInterfaces())
142 checkAttributes(manager, rIface.name, attributes, propinterfaces);
144 for (const auto& rProp : ent2->getDirectProperties())
146 if (!containsAttribute(attributes, rProp.name)) {
147 attributes.push_back(rProp);
150 break;
152 default:
153 throw CannotDumpException(
154 "unexpected entity \"" + name
155 + "\" in call to skeletonmaker::checkAttributes");
159 void checkType(rtl::Reference< TypeManager > const & manager,
160 OUString const & name,
161 std::set< OUString >& interfaceTypes,
162 std::set< OUString >& serviceTypes,
163 AttributeInfo& properties)
165 rtl::Reference< unoidl::Entity > ent;
166 switch (manager->getSort(name, &ent)) {
167 case codemaker::UnoType::Sort::Interface:
168 // com.sun.star.lang.XComponent should be also not in the list
169 // but it will be used for checking the impl helper and will be
170 // removed later if necessary.
171 if ( name == "com.sun.star.lang.XTypeProvider" ||
172 name == "com.sun.star.uno.XWeak" )
173 return;
174 interfaceTypes.insert(name);
175 break;
176 case codemaker::UnoType::Sort::SingleInterfaceBasedService:
177 if (serviceTypes.insert(name).second) {
178 rtl::Reference< unoidl::SingleInterfaceBasedServiceEntity > ent2(
179 dynamic_cast< unoidl::SingleInterfaceBasedServiceEntity * >(
180 ent.get()));
181 assert(ent2.is());
182 if (interfaceTypes.insert(ent2->getBase()).second) {
183 // check if constructors are specified, if yes automatically
184 // support of XInitialization. We will take care of the default
185 // constructor because in this case XInitialization is not
186 // called.
187 if (ent2->getConstructors().size() > 1 ||
188 (ent2->getConstructors().size() == 1 &&
189 !ent2->getConstructors()[0].defaultConstructor))
191 interfaceTypes.insert(OUString("com.sun.star.lang.XInitialization"));
195 break;
196 case codemaker::UnoType::Sort::AccumulationBasedService:
197 if ( serviceTypes.insert(name).second ) {
198 rtl::Reference< unoidl::AccumulationBasedServiceEntity > ent2(
199 dynamic_cast< unoidl::AccumulationBasedServiceEntity * >(
200 ent.get()));
201 assert(ent2.is());
202 for (const auto& rService : ent2->getDirectMandatoryBaseServices())
204 checkType(
205 manager, rService.name, interfaceTypes, serviceTypes, properties);
207 for (const auto& rIface : ent2->getDirectMandatoryBaseInterfaces())
209 checkType(
210 manager, rIface.name, interfaceTypes, serviceTypes, properties);
212 for (const auto& rProp : ent2->getDirectProperties())
214 properties.push_back(rProp);
217 break;
218 default:
219 throw CannotDumpException(
220 "unexpected entity \"" + name
221 + "\" in call to skeletonmaker::checkType");
225 void checkDefaultInterfaces(
226 std::set< OUString >& interfaces,
227 const std::set< OUString >& services,
228 std::u16string_view propertyhelper)
230 if ( services.empty() ) {
231 interfaces.erase("com.sun.star.lang.XServiceInfo");
232 } else {
233 interfaces.insert("com.sun.star.lang.XServiceInfo");
236 if ( propertyhelper == u"_" ) {
237 interfaces.erase("com.sun.star.beans.XPropertySet");
238 interfaces.erase("com.sun.star.beans.XFastPropertySet");
239 interfaces.erase("com.sun.star.beans.XPropertyAccess");
243 static bool checkServiceProperties(rtl::Reference< TypeManager > const & manager,
244 OUString const & name)
246 rtl::Reference< unoidl::Entity > ent;
247 if (manager->getSort(name, &ent)
248 == codemaker::UnoType::Sort::AccumulationBasedService)
250 rtl::Reference< unoidl::AccumulationBasedServiceEntity > ent2(
251 dynamic_cast< unoidl::AccumulationBasedServiceEntity * >(
252 ent.get()));
253 assert(ent2.is());
254 if (!ent2->getDirectProperties().empty()) {
255 return true;
257 return std::any_of(ent2->getDirectMandatoryBaseServices().begin(),
258 ent2->getDirectMandatoryBaseServices().end(),
259 [&manager](const unoidl::AnnotatedReference& rService) {
260 return checkServiceProperties(manager, rService.name); });
262 return false;
266 OUString checkPropertyHelper(
267 ProgramOptions const & options,
268 rtl::Reference< TypeManager > const & manager,
269 const std::set< OUString >& services,
270 const std::set< OUString >& interfaces,
271 AttributeInfo& attributes,
272 std::set< OUString >& propinterfaces)
274 std::set< OUString >::const_iterator iter;
275 std::set< OUString >::const_iterator end;
277 if ( !services.empty() ) {
278 iter = services.begin();
279 end = services.end();
280 } else {
281 iter = interfaces.begin();
282 end = interfaces.end();
285 bool oldStyleWithProperties = false;
286 while ( iter != end ) {
287 rtl::Reference< unoidl::Entity > ent;
288 codemaker::UnoType::Sort sort = manager->getSort(*iter, &ent);
289 if ( !services.empty() ) {
290 if (options.supportpropertysetmixin
291 && (sort
292 == codemaker::UnoType::Sort::SingleInterfaceBasedService))
294 rtl::Reference< unoidl::SingleInterfaceBasedServiceEntity >
295 ent2(
296 dynamic_cast<
297 unoidl::SingleInterfaceBasedServiceEntity * >(
298 ent.get()));
299 assert(ent2.is());
300 checkAttributes(
301 manager, ent2->getBase(), attributes, propinterfaces);
302 if (!(attributes.empty() || propinterfaces.empty())) {
303 return ent2->getBase();
305 } else {
306 oldStyleWithProperties = checkServiceProperties(manager, *iter);
308 } else {
309 checkAttributes(manager, *iter, attributes, propinterfaces);
310 if (!(attributes.empty() || propinterfaces.empty())) {
311 return *iter;
314 ++iter;
317 return oldStyleWithProperties ? OUString("_") : OUString();
320 static bool checkXComponentSupport(
321 rtl::Reference< TypeManager > const & manager, OUString const & name)
323 assert(manager.is());
324 if (name == "com.sun.star.lang.XComponent") {
325 return true;
327 rtl::Reference< unoidl::Entity > ent;
328 codemaker::UnoType::Sort sort = manager->getSort(name, &ent);
329 if (sort != codemaker::UnoType::Sort::Interface) {
330 throw CannotDumpException(
331 "unexpected entity \"" + name
332 + "\" in call to skeletonmaker::checkXComponentSupport");
334 rtl::Reference< unoidl::InterfaceTypeEntity > ent2(
335 dynamic_cast< unoidl::InterfaceTypeEntity * >(ent.get()));
336 assert(ent2.is());
337 return std::any_of(ent2->getDirectMandatoryBases().begin(), ent2->getDirectMandatoryBases().end(),
338 [&manager](const unoidl::AnnotatedReference& rBase) { return checkXComponentSupport(manager, rBase.name); });
342 // if XComponent is directly specified, return true and remove it from the
343 // supported interfaces list
344 bool checkXComponentSupport(rtl::Reference< TypeManager > const & manager,
345 std::set< OUString >& interfaces)
347 if ( interfaces.empty() )
348 return false;
350 for ( const auto& rIface : interfaces ) {
351 if ( rIface == "com.sun.star.lang.XComponent" ) {
352 interfaces.erase("com.sun.star.lang.XComponent");
353 return true;
355 if ( checkXComponentSupport(manager, rIface) )
356 return true;
359 return false;
362 unoidl::AccumulationBasedServiceEntity::Property::Attributes
363 checkAdditionalPropertyFlags(
364 unoidl::InterfaceTypeEntity::Attribute const & attribute)
366 int flags = 0;
367 bool getterSupportsUnknown = false;
368 for (const auto& rException : attribute.getExceptions)
370 if (rException == "com.sun.star.beans.UnknownPropertyException") {
371 getterSupportsUnknown = true;
374 for (const auto& rException : attribute.setExceptions)
376 if (rException == "com.sun.star.beans.PropertyVetoException") {
377 flags |= unoidl::AccumulationBasedServiceEntity::Property::
378 ATTRIBUTE_CONSTRAINED;
379 } else if (getterSupportsUnknown
380 && rException == "com.sun.star.beans.UnknownPropertyException")
382 flags |= unoidl::AccumulationBasedServiceEntity::Property::
383 ATTRIBUTE_OPTIONAL;
386 return unoidl::AccumulationBasedServiceEntity::Property::Attributes(flags);
389 // This function checks if the specified types for parameters and return
390 // types are allowed add-in types, for more info see the com.sun.star.sheet.AddIn
391 // service description
392 static bool checkAddinType(rtl::Reference< TypeManager > const & manager,
393 std::u16string_view type, bool & bLastAny,
394 bool & bHasXPropertySet, bool bIsReturn)
396 assert(manager.is());
397 sal_Int32 rank;
398 codemaker::UnoType::Sort sort = manager->decompose(
399 type, true, nullptr, &rank, nullptr, nullptr);
401 if ( sort == codemaker::UnoType::Sort::Long ||
402 sort == codemaker::UnoType::Sort::Double ||
403 sort == codemaker::UnoType::Sort::String )
405 if ( rank == 0 || rank ==2 )
406 return true;
408 if ( sort == codemaker::UnoType::Sort::Any )
410 if ( rank <= 2 ) {
411 if ( rank ==1 ) {
412 if ( bIsReturn )
413 return false;
414 bLastAny = true;
417 return true;
420 if ( sort == codemaker::UnoType::Sort::Interface )
422 if ( bIsReturn && type == u"com.sun.star.sheet.XVolatileResult" )
423 return true;
424 if ( !bIsReturn && type == u"com.sun.star.table.XCellRange" )
425 return true;
426 if ( !bIsReturn && type == u"com.sun.star.beans.XPropertySet" )
428 if ( bHasXPropertySet ) {
429 return false;
430 } else {
431 bHasXPropertySet = true;
432 return true;
436 return false;
439 static void checkAddInTypes(
440 rtl::Reference< TypeManager > const & manager, std::u16string_view name,
441 rtl::Reference< unoidl::InterfaceTypeEntity > const & entity)
443 assert(entity.is());
444 bool bLastAny = false;
445 bool bHasXPropertySet = false;
446 for (const auto& rMethod : entity->getDirectMethods())
448 if ( !checkAddinType(
449 manager, rMethod.returnType, bLastAny, bHasXPropertySet, true) )
451 throw CannotDumpException(
452 OUString::Concat("the return type of the calc add-in function '") + name
453 + ":" + rMethod.name
454 + "' is invalid. Please check your IDL definition.");
457 bHasXPropertySet = false;
458 for (const auto& rParam : rMethod.parameters)
460 bLastAny = false;
461 if ( !checkAddinType(manager, rParam.type,
462 bLastAny, bHasXPropertySet, false) ||
463 bLastAny )
465 throw CannotDumpException(
466 "the type of the " + rParam.name
467 + " parameter of the calc add-in function '" + name
468 + ":" + rMethod.name + "' is invalid."
469 + (bLastAny
470 ? OUString(
471 " The type 'sequence<any>' is allowed as last"
472 " parameter only.")
473 : OUString())
474 + (bHasXPropertySet
475 ? OUString(
476 " The type 'XPropertySet' is allowed only once.")
477 : OUString())
478 + " Please check your IDL definition.");
484 static void generateFunctionParameterMap(std::ostream& o,
485 ProgramOptions const & options,
486 rtl::Reference< TypeManager > const & manager,
487 OUString const & name,
488 ::codemaker::GeneratedTypeSet & generated,
489 bool& bFirst)
491 if ( name == "com.sun.star.uno.XInterface" ||
492 name == "com.sun.star.lang.XLocalizable" ||
493 name == "com.sun.star.lang.XServiceInfo" ||
494 // the next three checks becomes obsolete when configuration is used
495 name == "com.sun.star.sheet.XAddIn" ||
496 name == "com.sun.star.sheet.XCompatibilityNames" ||
497 name == "com.sun.star.lang.XServiceName" )
499 return;
502 rtl::Reference< unoidl::Entity > ent;
503 codemaker::UnoType::Sort sort = manager->getSort(name, &ent);
504 if (sort != codemaker::UnoType::Sort::Interface) {
505 throw CannotDumpException(
506 "unexpected entity \"" + name
507 + "\" in call to skeletonmaker::generateFunctionParameterMap");
509 rtl::Reference< unoidl::InterfaceTypeEntity > ent2(
510 dynamic_cast< unoidl::InterfaceTypeEntity * >(ent.get()));
511 assert(ent2.is());
513 // check if the specified add-in functions supports valid types
514 checkAddInTypes(manager, name, ent2);
516 for (const auto& rBase : ent2->getDirectMandatoryBases())
518 generateFunctionParameterMap(
519 o, options, manager, rBase.name, generated, bFirst);
522 if ( generated.contains(u2b(name)) )
523 return;
524 else
525 generated.add(u2b(name));
527 for (const auto& rMethod : ent2->getDirectMethods())
529 if ( bFirst ) {
530 if (options.language == 2) {
531 o << " ParamMap fpm;\n";
533 else {
534 o << " java.util.Hashtable< Integer, String > fpm = "
535 "new java.util.Hashtable< Integer, String >();\n";
537 bFirst = false;
538 } else
539 if ( options.language == 2 ) {
540 o << " fpm = ParamMap();\n";
542 else {
543 o << " fpm = new java.util.Hashtable< "
544 "Integer, String >();\n";
547 std::vector< unoidl::InterfaceTypeEntity::Method::Parameter >::size_type
548 n = 0;
549 for (const auto& rParam : rMethod.parameters)
551 if ( options.language == 2 ) {
552 o << " fpm[" << n
553 << "] = OUString(\""
554 << rParam.name
555 << "\");\n";
557 else {
558 o << " fpm.put(" << n << ", \""
559 << rParam.name
560 << "\");\n";
562 ++n;
565 if ( options.language == 2 ) {
566 o << " m_functionMap[OUString(\""
567 << rMethod.name << "\")] = fpm;\n\n";
569 else {
570 o << " m_functionMap.put(\"" << rMethod.name << "\", fpm);\n\n";
575 void generateFunctionParameterMap(std::ostream& o,
576 ProgramOptions const & options,
577 rtl::Reference< TypeManager > const & manager,
578 const std::set< OUString >& interfaces)
580 ::codemaker::GeneratedTypeSet generated;
581 bool bFirst = true;
582 for ( const auto& rIface : interfaces ) {
583 generateFunctionParameterMap(o, options, manager, rIface, generated, bFirst);
589 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */