1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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"
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"
40 " * This file is part of the LibreOffice project.\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"
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" )
58 *ppOutputStream
= &std::cout
;
62 targetSourceFileName
= createFileNameFromType(
63 options
.outputpath
, options
.implname
.replace('.','/'), extension
);
65 OString tmpDir
= getTempDir(targetSourceFileName
);
67 file
.createTempFile(tmpDir
);
71 throw CannotDumpException(
72 "cannot open " + b2u(targetSourceFileName
) + " for writing");
74 tmpSourceFileName
= file
.getName();
76 *ppOutputStream
= new std::ofstream(tmpSourceFileName
.getStr(),
77 std::ios_base::binary
);
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()));
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::
120 ? unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_BOUND
123 ? unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_READ_ONLY
125 std::vector
< OUString
>());
130 case codemaker::UnoType::Sort::AccumulationBasedService
:
132 rtl::Reference
< unoidl::AccumulationBasedServiceEntity
> ent2(
133 dynamic_cast< unoidl::AccumulationBasedServiceEntity
* >(
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
);
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" )
174 interfaceTypes
.insert(name
);
176 case codemaker::UnoType::Sort::SingleInterfaceBasedService
:
177 if (serviceTypes
.insert(name
).second
) {
178 rtl::Reference
< unoidl::SingleInterfaceBasedServiceEntity
> ent2(
179 dynamic_cast< unoidl::SingleInterfaceBasedServiceEntity
* >(
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
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"));
196 case codemaker::UnoType::Sort::AccumulationBasedService
:
197 if ( serviceTypes
.insert(name
).second
) {
198 rtl::Reference
< unoidl::AccumulationBasedServiceEntity
> ent2(
199 dynamic_cast< unoidl::AccumulationBasedServiceEntity
* >(
202 for (const auto& rService
: ent2
->getDirectMandatoryBaseServices())
205 manager
, rService
.name
, interfaceTypes
, serviceTypes
, properties
);
207 for (const auto& rIface
: ent2
->getDirectMandatoryBaseInterfaces())
210 manager
, rIface
.name
, interfaceTypes
, serviceTypes
, properties
);
212 for (const auto& rProp
: ent2
->getDirectProperties())
214 properties
.push_back(rProp
);
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");
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
* >(
254 if (!ent2
->getDirectProperties().empty()) {
257 return std::any_of(ent2
->getDirectMandatoryBaseServices().begin(),
258 ent2
->getDirectMandatoryBaseServices().end(),
259 [&manager
](const unoidl::AnnotatedReference
& rService
) {
260 return checkServiceProperties(manager
, rService
.name
); });
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();
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
292 == codemaker::UnoType::Sort::SingleInterfaceBasedService
))
294 rtl::Reference
< unoidl::SingleInterfaceBasedServiceEntity
>
297 unoidl::SingleInterfaceBasedServiceEntity
* >(
301 manager
, ent2
->getBase(), attributes
, propinterfaces
);
302 if (!(attributes
.empty() || propinterfaces
.empty())) {
303 return ent2
->getBase();
306 oldStyleWithProperties
= checkServiceProperties(manager
, *iter
);
309 checkAttributes(manager
, *iter
, attributes
, propinterfaces
);
310 if (!(attributes
.empty() || propinterfaces
.empty())) {
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") {
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()));
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() )
350 for ( const auto& rIface
: interfaces
) {
351 if ( rIface
== "com.sun.star.lang.XComponent" ) {
352 interfaces
.erase("com.sun.star.lang.XComponent");
355 if ( checkXComponentSupport(manager
, rIface
) )
362 unoidl::AccumulationBasedServiceEntity::Property::Attributes
363 checkAdditionalPropertyFlags(
364 unoidl::InterfaceTypeEntity::Attribute
const & attribute
)
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::
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());
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 )
408 if ( sort
== codemaker::UnoType::Sort::Any
)
420 if ( sort
== codemaker::UnoType::Sort::Interface
)
422 if ( bIsReturn
&& type
== u
"com.sun.star.sheet.XVolatileResult" )
424 if ( !bIsReturn
&& type
== u
"com.sun.star.table.XCellRange" )
426 if ( !bIsReturn
&& type
== u
"com.sun.star.beans.XPropertySet" )
428 if ( bHasXPropertySet
) {
431 bHasXPropertySet
= true;
439 static void checkAddInTypes(
440 rtl::Reference
< TypeManager
> const & manager
, std::u16string_view name
,
441 rtl::Reference
< unoidl::InterfaceTypeEntity
> const & entity
)
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
454 + "' is invalid. Please check your IDL definition.");
457 bHasXPropertySet
= false;
458 for (const auto& rParam
: rMethod
.parameters
)
461 if ( !checkAddinType(manager
, rParam
.type
,
462 bLastAny
, bHasXPropertySet
, false) ||
465 throw CannotDumpException(
466 "the type of the " + rParam
.name
467 + " parameter of the calc add-in function '" + name
468 + ":" + rMethod
.name
+ "' is invalid."
471 " The type 'sequence<any>' is allowed as last"
476 " The type 'XPropertySet' is allowed only once.")
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
,
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" )
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()));
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
)) )
525 generated
.add(u2b(name
));
527 for (const auto& rMethod
: ent2
->getDirectMethods())
530 if (options
.language
== 2) {
531 o
<< " ParamMap fpm;\n";
534 o
<< " java.util.Hashtable< Integer, String > fpm = "
535 "new java.util.Hashtable< Integer, String >();\n";
539 if ( options
.language
== 2 ) {
540 o
<< " fpm = ParamMap();\n";
543 o
<< " fpm = new java.util.Hashtable< "
544 "Integer, String >();\n";
547 std::vector
< unoidl::InterfaceTypeEntity::Method::Parameter
>::size_type
549 for (const auto& rParam
: rMethod
.parameters
)
551 if ( options
.language
== 2 ) {
558 o
<< " fpm.put(" << n
<< ", \""
565 if ( options
.language
== 2 ) {
566 o
<< " m_functionMap[OUString(\""
567 << rMethod
.name
<< "\")] = fpm;\n\n";
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
;
582 for ( const auto& rIface
: interfaces
) {
583 generateFunctionParameterMap(o
, options
, manager
, rIface
, generated
, bFirst
);
589 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */