nss: upgrade to release 3.73
[LibreOffice.git] / unodevtools / source / skeletonmaker / skeletoncommon.cxx
blob37041a8be951a678bf9d2dfca8712f12f616aa90
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 <osl/thread.hxx>
22 #include <codemaker/commonjava.hxx>
23 #include <codemaker/commoncpp.hxx>
24 #include <codemaker/generatedtypeset.hxx>
25 #include <codemaker/global.hxx>
26 #include <unoidl/unoidl.hxx>
28 #include "skeletoncommon.hxx"
30 #include <algorithm>
31 #include <cassert>
32 #include <iostream>
34 using namespace ::codemaker::cpp;
36 namespace skeletonmaker {
38 void printLicenseHeader(std::ostream& o, OString const & filename)
40 sal_Int32 index;
41 #ifdef SAL_UNX
42 index = filename.lastIndexOf('/');
43 #else
44 index = filename.lastIndexOf('\\');
45 #endif
46 OString shortfilename(filename);
47 if ( index != -1 )
48 shortfilename = filename.copy(index+1);
50 o << "/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */\n"
51 "/*\n"
52 " * This file is part of the LibreOffice project.\n"
53 " *\n"
54 " * This Source Code Form is subject to the terms of the Mozilla Public\n"
55 " * License, v. 2.0. If a copy of the MPL was not distributed with this\n"
56 " * file, You can obtain one at http://mozilla.org/MPL/2.0/.\n"
57 " */\n\n";
60 bool getOutputStream(ProgramOptions const & options,
61 OString const & extension,
62 std::ostream** ppOutputStream,
63 OString & targetSourceFileName,
64 OString & tmpSourceFileName)
66 bool bStandardout = false;
67 if ( options.outputpath == "stdout" )
69 bStandardout = true;
70 *ppOutputStream = &std::cout;
71 return bStandardout;
74 targetSourceFileName = createFileNameFromType(
75 options.outputpath, options.implname.replace('.','/'), extension);
77 OString tmpDir = getTempDir(targetSourceFileName);
78 FileStream file;
79 file.createTempFile(tmpDir);
81 if( !file.isValid() )
83 throw CannotDumpException(
84 "cannot open " + b2u(targetSourceFileName) + " for writing");
86 tmpSourceFileName = file.getName();
87 file.close();
88 *ppOutputStream = new std::ofstream(tmpSourceFileName.getStr(),
89 std::ios_base::binary);
91 return bStandardout;
94 static bool containsAttribute(AttributeInfo& attributes, OUString const & attrname)
96 return std::any_of(attributes.begin(), attributes.end(),
97 [&attrname](const unoidl::AccumulationBasedServiceEntity::Property& rAttr) {
98 return rAttr.name == attrname; });
101 // collect attributes including inherited attributes
102 static void checkAttributes(rtl::Reference< TypeManager > const & manager,
103 OUString const & name,
104 AttributeInfo& attributes,
105 std::set< OUString >& propinterfaces)
107 if ( name == "com.sun.star.beans.XPropertySet" ||
108 name == "com.sun.star.beans.XFastPropertySet" ||
109 name == "com.sun.star.beans.XPropertyAccess" )
111 propinterfaces.insert(name);
113 rtl::Reference< unoidl::Entity > ent;
114 switch (manager->getSort(name, &ent)) {
115 case codemaker::UnoType::Sort::Interface:
117 rtl::Reference< unoidl::InterfaceTypeEntity > ent2(
118 dynamic_cast< unoidl::InterfaceTypeEntity * >(ent.get()));
119 assert(ent2.is());
120 for (const auto& rBase : ent2->getDirectMandatoryBases())
122 checkAttributes(manager, rBase.name, attributes, propinterfaces);
124 for (const auto& rAttr : ent2->getDirectAttributes())
126 if (!containsAttribute(attributes, rAttr.name)) {
127 attributes.emplace_back(
128 rAttr.name, rAttr.type,
129 (unoidl::AccumulationBasedServiceEntity::Property::
130 Attributes(
131 ((rAttr.bound
132 ? unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_BOUND
133 : 0)
134 | (rAttr.readOnly
135 ? unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_READ_ONLY
136 : 0)))),
137 std::vector< OUString >());
140 break;
142 case codemaker::UnoType::Sort::AccumulationBasedService:
144 rtl::Reference< unoidl::AccumulationBasedServiceEntity > ent2(
145 dynamic_cast< unoidl::AccumulationBasedServiceEntity * >(
146 ent.get()));
147 assert(ent2.is());
148 for (const auto& rService : ent2->getDirectMandatoryBaseServices())
150 checkAttributes(manager, rService.name, attributes, propinterfaces);
152 for (const auto& rIface : ent2->getDirectMandatoryBaseInterfaces())
154 checkAttributes(manager, rIface.name, attributes, propinterfaces);
156 for (const auto& rProp : ent2->getDirectProperties())
158 if (!containsAttribute(attributes, rProp.name)) {
159 attributes.push_back(rProp);
162 break;
164 default:
165 throw CannotDumpException(
166 "unexpected entity \"" + name
167 + "\" in call to skeletonmaker::checkAttributes");
171 void checkType(rtl::Reference< TypeManager > const & manager,
172 OUString const & name,
173 std::set< OUString >& interfaceTypes,
174 std::set< OUString >& serviceTypes,
175 AttributeInfo& properties)
177 rtl::Reference< unoidl::Entity > ent;
178 switch (manager->getSort(name, &ent)) {
179 case codemaker::UnoType::Sort::Interface:
180 // com.sun.star.lang.XComponent should be also not in the list
181 // but it will be used for checking the impl helper and will be
182 // removed later if necessary.
183 if ( name == "com.sun.star.lang.XTypeProvider" ||
184 name == "com.sun.star.uno.XWeak" )
185 return;
186 interfaceTypes.insert(name);
187 break;
188 case codemaker::UnoType::Sort::SingleInterfaceBasedService:
189 if (serviceTypes.insert(name).second) {
190 rtl::Reference< unoidl::SingleInterfaceBasedServiceEntity > ent2(
191 dynamic_cast< unoidl::SingleInterfaceBasedServiceEntity * >(
192 ent.get()));
193 assert(ent2.is());
194 if (interfaceTypes.insert(ent2->getBase()).second) {
195 // check if constructors are specified, if yes automatically
196 // support of XInitialization. We will take care of the default
197 // constructor because in this case XInitialization is not
198 // called.
199 if (ent2->getConstructors().size() > 1 ||
200 (ent2->getConstructors().size() == 1 &&
201 !ent2->getConstructors()[0].defaultConstructor))
203 interfaceTypes.insert(OUString("com.sun.star.lang.XInitialization"));
207 break;
208 case codemaker::UnoType::Sort::AccumulationBasedService:
209 if ( serviceTypes.insert(name).second ) {
210 rtl::Reference< unoidl::AccumulationBasedServiceEntity > ent2(
211 dynamic_cast< unoidl::AccumulationBasedServiceEntity * >(
212 ent.get()));
213 assert(ent2.is());
214 for (const auto& rService : ent2->getDirectMandatoryBaseServices())
216 checkType(
217 manager, rService.name, interfaceTypes, serviceTypes, properties);
219 for (const auto& rIface : ent2->getDirectMandatoryBaseInterfaces())
221 checkType(
222 manager, rIface.name, interfaceTypes, serviceTypes, properties);
224 for (const auto& rProp : ent2->getDirectProperties())
226 properties.push_back(rProp);
229 break;
230 default:
231 throw CannotDumpException(
232 "unexpected entity \"" + name
233 + "\" in call to skeletonmaker::checkType");
237 void checkDefaultInterfaces(
238 std::set< OUString >& interfaces,
239 const std::set< OUString >& services,
240 const OUString & propertyhelper)
242 if ( services.empty() ) {
243 interfaces.erase("com.sun.star.lang.XServiceInfo");
244 } else {
245 interfaces.insert("com.sun.star.lang.XServiceInfo");
248 if ( propertyhelper == "_" ) {
249 interfaces.erase("com.sun.star.beans.XPropertySet");
250 interfaces.erase("com.sun.star.beans.XFastPropertySet");
251 interfaces.erase("com.sun.star.beans.XPropertyAccess");
255 static bool checkServiceProperties(rtl::Reference< TypeManager > const & manager,
256 OUString const & name)
258 rtl::Reference< unoidl::Entity > ent;
259 if (manager->getSort(name, &ent)
260 == codemaker::UnoType::Sort::AccumulationBasedService)
262 rtl::Reference< unoidl::AccumulationBasedServiceEntity > ent2(
263 dynamic_cast< unoidl::AccumulationBasedServiceEntity * >(
264 ent.get()));
265 assert(ent2.is());
266 if (!ent2->getDirectProperties().empty()) {
267 return true;
269 return std::any_of(ent2->getDirectMandatoryBaseServices().begin(),
270 ent2->getDirectMandatoryBaseServices().end(),
271 [&manager](const unoidl::AnnotatedReference& rService) {
272 return checkServiceProperties(manager, rService.name); });
274 return false;
278 OUString checkPropertyHelper(
279 ProgramOptions const & options,
280 rtl::Reference< TypeManager > const & manager,
281 const std::set< OUString >& services,
282 const std::set< OUString >& interfaces,
283 AttributeInfo& attributes,
284 std::set< OUString >& propinterfaces)
286 std::set< OUString >::const_iterator iter;
287 std::set< OUString >::const_iterator end;
289 if ( !services.empty() ) {
290 iter = services.begin();
291 end = services.end();
292 } else {
293 iter = interfaces.begin();
294 end = interfaces.end();
297 bool oldStyleWithProperties = false;
298 while ( iter != end ) {
299 rtl::Reference< unoidl::Entity > ent;
300 codemaker::UnoType::Sort sort = manager->getSort(*iter, &ent);
301 if ( !services.empty() ) {
302 if (options.supportpropertysetmixin
303 && (sort
304 == codemaker::UnoType::Sort::SingleInterfaceBasedService))
306 rtl::Reference< unoidl::SingleInterfaceBasedServiceEntity >
307 ent2(
308 dynamic_cast<
309 unoidl::SingleInterfaceBasedServiceEntity * >(
310 ent.get()));
311 assert(ent2.is());
312 checkAttributes(
313 manager, ent2->getBase(), attributes, propinterfaces);
314 if (!(attributes.empty() || propinterfaces.empty())) {
315 return ent2->getBase();
317 } else {
318 oldStyleWithProperties = checkServiceProperties(manager, *iter);
320 } else {
321 checkAttributes(manager, *iter, attributes, propinterfaces);
322 if (!(attributes.empty() || propinterfaces.empty())) {
323 return *iter;
326 ++iter;
329 return oldStyleWithProperties ? OUString("_") : OUString();
332 static bool checkXComponentSupport(
333 rtl::Reference< TypeManager > const & manager, OUString const & name)
335 assert(manager.is());
336 if (name == "com.sun.star.lang.XComponent") {
337 return true;
339 rtl::Reference< unoidl::Entity > ent;
340 codemaker::UnoType::Sort sort = manager->getSort(name, &ent);
341 if (sort != codemaker::UnoType::Sort::Interface) {
342 throw CannotDumpException(
343 "unexpected entity \"" + name
344 + "\" in call to skeletonmaker::checkXComponentSupport");
346 rtl::Reference< unoidl::InterfaceTypeEntity > ent2(
347 dynamic_cast< unoidl::InterfaceTypeEntity * >(ent.get()));
348 assert(ent2.is());
349 return std::any_of(ent2->getDirectMandatoryBases().begin(), ent2->getDirectMandatoryBases().end(),
350 [&manager](const unoidl::AnnotatedReference& rBase) { return checkXComponentSupport(manager, rBase.name); });
354 // if XComponent is directly specified, return true and remove it from the
355 // supported interfaces list
356 bool checkXComponentSupport(rtl::Reference< TypeManager > const & manager,
357 std::set< OUString >& interfaces)
359 if ( interfaces.empty() )
360 return false;
362 for ( const auto& rIface : interfaces ) {
363 if ( rIface == "com.sun.star.lang.XComponent" ) {
364 interfaces.erase("com.sun.star.lang.XComponent");
365 return true;
367 if ( checkXComponentSupport(manager, rIface) )
368 return true;
371 return false;
374 unoidl::AccumulationBasedServiceEntity::Property::Attributes
375 checkAdditionalPropertyFlags(
376 unoidl::InterfaceTypeEntity::Attribute const & attribute)
378 int flags = 0;
379 bool getterSupportsUnknown = false;
380 for (const auto& rException : attribute.getExceptions)
382 if (rException == "com.sun.star.beans.UnknownPropertyException") {
383 getterSupportsUnknown = true;
386 for (const auto& rException : attribute.setExceptions)
388 if (rException == "com.sun.star.beans.PropertyVetoException") {
389 flags |= unoidl::AccumulationBasedServiceEntity::Property::
390 ATTRIBUTE_CONSTRAINED;
391 } else if (getterSupportsUnknown
392 && rException == "com.sun.star.beans.UnknownPropertyException")
394 flags |= unoidl::AccumulationBasedServiceEntity::Property::
395 ATTRIBUTE_OPTIONAL;
398 return unoidl::AccumulationBasedServiceEntity::Property::Attributes(flags);
401 // This function checks if the specified types for parameters and return
402 // types are allowed add-in types, for more info see the com.sun.star.sheet.AddIn
403 // service description
404 static bool checkAddinType(rtl::Reference< TypeManager > const & manager,
405 OUString const & type, bool & bLastAny,
406 bool & bHasXPropertySet, bool bIsReturn)
408 assert(manager.is());
409 sal_Int32 rank;
410 codemaker::UnoType::Sort sort = manager->decompose(
411 type, true, nullptr, &rank, nullptr, nullptr);
413 if ( sort == codemaker::UnoType::Sort::Long ||
414 sort == codemaker::UnoType::Sort::Double ||
415 sort == codemaker::UnoType::Sort::String )
417 if ( rank == 0 || rank ==2 )
418 return true;
420 if ( sort == codemaker::UnoType::Sort::Any )
422 if ( rank <= 2 ) {
423 if ( rank ==1 ) {
424 if ( bIsReturn )
425 return false;
426 bLastAny = true;
429 return true;
432 if ( sort == codemaker::UnoType::Sort::Interface )
434 if ( bIsReturn && type == "com.sun.star.sheet.XVolatileResult" )
435 return true;
436 if ( !bIsReturn && type == "com.sun.star.table.XCellRange" )
437 return true;
438 if ( !bIsReturn && type == "com.sun.star.beans.XPropertySet" )
440 if ( bHasXPropertySet ) {
441 return false;
442 } else {
443 bHasXPropertySet = true;
444 return true;
448 return false;
451 static void checkAddInTypes(
452 rtl::Reference< TypeManager > const & manager, OUString const & name,
453 rtl::Reference< unoidl::InterfaceTypeEntity > const & entity)
455 assert(entity.is());
456 bool bLastAny = false;
457 bool bHasXPropertySet = false;
458 for (const auto& rMethod : entity->getDirectMethods())
460 if ( !checkAddinType(
461 manager, rMethod.returnType, bLastAny, bHasXPropertySet, true) )
463 throw CannotDumpException(
464 "the return type of the calc add-in function '" + name
465 + ":" + rMethod.name
466 + "' is invalid. Please check your IDL definition.");
469 bHasXPropertySet = false;
470 for (const auto& rParam : rMethod.parameters)
472 bLastAny = false;
473 if ( !checkAddinType(manager, rParam.type,
474 bLastAny, bHasXPropertySet, false) ||
475 bLastAny )
477 throw CannotDumpException(
478 "the type of the " + rParam.name
479 + " parameter of the calc add-in function '" + name
480 + ":" + rMethod.name + "' is invalid."
481 + (bLastAny
482 ? OUString(
483 " The type 'sequence<any>' is allowed as last"
484 " parameter only.")
485 : OUString())
486 + (bHasXPropertySet
487 ? OUString(
488 " The type 'XPropertySet' is allowed only once.")
489 : OUString())
490 + " Please check your IDL definition.");
496 static void generateFunctionParameterMap(std::ostream& o,
497 ProgramOptions const & options,
498 rtl::Reference< TypeManager > const & manager,
499 OUString const & name,
500 ::codemaker::GeneratedTypeSet & generated,
501 bool& bFirst)
503 if ( name == "com.sun.star.uno.XInterface" ||
504 name == "com.sun.star.lang.XLocalizable" ||
505 name == "com.sun.star.lang.XServiceInfo" ||
506 // the next three checks becomes obsolete when configuration is used
507 name == "com.sun.star.sheet.XAddIn" ||
508 name == "com.sun.star.sheet.XCompatibilityNames" ||
509 name == "com.sun.star.lang.XServiceName" )
511 return;
514 rtl::Reference< unoidl::Entity > ent;
515 codemaker::UnoType::Sort sort = manager->getSort(name, &ent);
516 if (sort != codemaker::UnoType::Sort::Interface) {
517 throw CannotDumpException(
518 "unexpected entity \"" + name
519 + "\" in call to skeletonmaker::generateFunctionParameterMap");
521 rtl::Reference< unoidl::InterfaceTypeEntity > ent2(
522 dynamic_cast< unoidl::InterfaceTypeEntity * >(ent.get()));
523 assert(ent2.is());
525 // check if the specified add-in functions supports valid types
526 checkAddInTypes(manager, name, ent2);
528 for (const auto& rBase : ent2->getDirectMandatoryBases())
530 generateFunctionParameterMap(
531 o, options, manager, rBase.name, generated, bFirst);
534 if ( generated.contains(u2b(name)) )
535 return;
536 else
537 generated.add(u2b(name));
539 for (const auto& rMethod : ent2->getDirectMethods())
541 if ( bFirst ) {
542 if (options.language == 2) {
543 o << " ParamMap fpm;\n";
545 else {
546 o << " java.util.Hashtable< Integer, String > fpm = "
547 "new java.util.Hashtable< Integer, String >();\n";
549 bFirst = false;
550 } else
551 if ( options.language == 2 ) {
552 o << " fpm = ParamMap();\n";
554 else {
555 o << " fpm = new java.util.Hashtable< "
556 "Integer, String >();\n";
559 std::vector< unoidl::InterfaceTypeEntity::Method::Parameter >::size_type
560 n = 0;
561 for (const auto& rParam : rMethod.parameters)
563 if ( options.language == 2 ) {
564 o << " fpm[" << n
565 << "] = OUString(\""
566 << rParam.name
567 << "\");\n";
569 else {
570 o << " fpm.put(" << n << ", \""
571 << rParam.name
572 << "\");\n";
574 ++n;
577 if ( options.language == 2 ) {
578 o << " m_functionMap[OUString(\""
579 << rMethod.name << "\")] = fpm;\n\n";
581 else {
582 o << " m_functionMap.put(\"" << rMethod.name << "\", fpm);\n\n";
587 void generateFunctionParameterMap(std::ostream& o,
588 ProgramOptions const & options,
589 rtl::Reference< TypeManager > const & manager,
590 const std::set< OUString >& interfaces)
592 ::codemaker::GeneratedTypeSet generated;
593 bool bFirst = true;
594 for ( const auto& rIface : interfaces ) {
595 generateFunctionParameterMap(o, options, manager, rIface, generated, bFirst);
601 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */