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 <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"
34 using namespace ::codemaker::cpp
;
36 namespace skeletonmaker
{
38 void printLicenseHeader(std::ostream
& o
, OString
const & filename
)
42 index
= filename
.lastIndexOf('/');
44 index
= filename
.lastIndexOf('\\');
46 OString
shortfilename(filename
);
48 shortfilename
= filename
.copy(index
+1);
50 o
<< "/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */\n"
52 " * This file is part of the LibreOffice project.\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"
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" )
70 *ppOutputStream
= &std::cout
;
74 targetSourceFileName
= createFileNameFromType(
75 options
.outputpath
, options
.implname
.replace('.','/'), extension
);
77 OString tmpDir
= getTempDir(targetSourceFileName
);
79 file
.createTempFile(tmpDir
);
83 throw CannotDumpException(
84 "cannot open " + b2u(targetSourceFileName
) + " for writing");
86 tmpSourceFileName
= file
.getName();
88 *ppOutputStream
= new std::ofstream(tmpSourceFileName
.getStr(),
89 std::ios_base::binary
);
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()));
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::
132 ? unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_BOUND
135 ? unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_READ_ONLY
137 std::vector
< OUString
>());
142 case codemaker::UnoType::Sort::AccumulationBasedService
:
144 rtl::Reference
< unoidl::AccumulationBasedServiceEntity
> ent2(
145 dynamic_cast< unoidl::AccumulationBasedServiceEntity
* >(
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
);
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" )
186 interfaceTypes
.insert(name
);
188 case codemaker::UnoType::Sort::SingleInterfaceBasedService
:
189 if (serviceTypes
.insert(name
).second
) {
190 rtl::Reference
< unoidl::SingleInterfaceBasedServiceEntity
> ent2(
191 dynamic_cast< unoidl::SingleInterfaceBasedServiceEntity
* >(
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
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"));
208 case codemaker::UnoType::Sort::AccumulationBasedService
:
209 if ( serviceTypes
.insert(name
).second
) {
210 rtl::Reference
< unoidl::AccumulationBasedServiceEntity
> ent2(
211 dynamic_cast< unoidl::AccumulationBasedServiceEntity
* >(
214 for (const auto& rService
: ent2
->getDirectMandatoryBaseServices())
217 manager
, rService
.name
, interfaceTypes
, serviceTypes
, properties
);
219 for (const auto& rIface
: ent2
->getDirectMandatoryBaseInterfaces())
222 manager
, rIface
.name
, interfaceTypes
, serviceTypes
, properties
);
224 for (const auto& rProp
: ent2
->getDirectProperties())
226 properties
.push_back(rProp
);
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");
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
* >(
266 if (!ent2
->getDirectProperties().empty()) {
269 return std::any_of(ent2
->getDirectMandatoryBaseServices().begin(),
270 ent2
->getDirectMandatoryBaseServices().end(),
271 [&manager
](const unoidl::AnnotatedReference
& rService
) {
272 return checkServiceProperties(manager
, rService
.name
); });
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();
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
304 == codemaker::UnoType::Sort::SingleInterfaceBasedService
))
306 rtl::Reference
< unoidl::SingleInterfaceBasedServiceEntity
>
309 unoidl::SingleInterfaceBasedServiceEntity
* >(
313 manager
, ent2
->getBase(), attributes
, propinterfaces
);
314 if (!(attributes
.empty() || propinterfaces
.empty())) {
315 return ent2
->getBase();
318 oldStyleWithProperties
= checkServiceProperties(manager
, *iter
);
321 checkAttributes(manager
, *iter
, attributes
, propinterfaces
);
322 if (!(attributes
.empty() || propinterfaces
.empty())) {
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") {
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()));
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() )
362 for ( const auto& rIface
: interfaces
) {
363 if ( rIface
== "com.sun.star.lang.XComponent" ) {
364 interfaces
.erase("com.sun.star.lang.XComponent");
367 if ( checkXComponentSupport(manager
, rIface
) )
374 unoidl::AccumulationBasedServiceEntity::Property::Attributes
375 checkAdditionalPropertyFlags(
376 unoidl::InterfaceTypeEntity::Attribute
const & attribute
)
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::
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());
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 )
420 if ( sort
== codemaker::UnoType::Sort::Any
)
432 if ( sort
== codemaker::UnoType::Sort::Interface
)
434 if ( bIsReturn
&& type
== "com.sun.star.sheet.XVolatileResult" )
436 if ( !bIsReturn
&& type
== "com.sun.star.table.XCellRange" )
438 if ( !bIsReturn
&& type
== "com.sun.star.beans.XPropertySet" )
440 if ( bHasXPropertySet
) {
443 bHasXPropertySet
= true;
451 static void checkAddInTypes(
452 rtl::Reference
< TypeManager
> const & manager
, OUString
const & name
,
453 rtl::Reference
< unoidl::InterfaceTypeEntity
> const & entity
)
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
466 + "' is invalid. Please check your IDL definition.");
469 bHasXPropertySet
= false;
470 for (const auto& rParam
: rMethod
.parameters
)
473 if ( !checkAddinType(manager
, rParam
.type
,
474 bLastAny
, bHasXPropertySet
, false) ||
477 throw CannotDumpException(
478 "the type of the " + rParam
.name
479 + " parameter of the calc add-in function '" + name
480 + ":" + rMethod
.name
+ "' is invalid."
483 " The type 'sequence<any>' is allowed as last"
488 " The type 'XPropertySet' is allowed only once.")
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
,
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" )
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()));
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
)) )
537 generated
.add(u2b(name
));
539 for (const auto& rMethod
: ent2
->getDirectMethods())
542 if (options
.language
== 2) {
543 o
<< " ParamMap fpm;\n";
546 o
<< " java.util.Hashtable< Integer, String > fpm = "
547 "new java.util.Hashtable< Integer, String >();\n";
551 if ( options
.language
== 2 ) {
552 o
<< " fpm = ParamMap();\n";
555 o
<< " fpm = new java.util.Hashtable< "
556 "Integer, String >();\n";
559 std::vector
< unoidl::InterfaceTypeEntity::Method::Parameter
>::size_type
561 for (const auto& rParam
: rMethod
.parameters
)
563 if ( options
.language
== 2 ) {
570 o
<< " fpm.put(" << n
<< ", \""
577 if ( options
.language
== 2 ) {
578 o
<< " m_functionMap[OUString(\""
579 << rMethod
.name
<< "\")] = fpm;\n\n";
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
;
594 for ( const auto& rIface
: interfaces
) {
595 generateFunctionParameterMap(o
, options
, manager
, rIface
, generated
, bFirst
);
601 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */