Bump version to 24.04.3.4
[LibreOffice.git] / unoidl / source / unoidl-check.cxx
blobfdeb74441fc1de9e26f3b1db22a92327794675a2
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/.
8 */
10 #include <sal/config.h>
12 #include <algorithm>
13 #include <cassert>
14 #include <cstdlib>
15 #include <iostream>
16 #include <string_view>
17 #include <utility>
18 #include <vector>
20 #include <osl/file.hxx>
21 #include <osl/process.h>
22 #include <rtl/character.hxx>
23 #include <rtl/process.h>
24 #include <rtl/ref.hxx>
25 #include <rtl/ustring.hxx>
26 #include <sal/main.h>
27 #include <sal/types.h>
28 #include <unoidl/unoidl.hxx>
30 namespace unoidl {
32 static bool operator ==(ConstantValue const & lhs, ConstantValue const & rhs) {
33 if (lhs.type == rhs.type) {
34 switch (lhs.type) {
35 case ConstantValue::TYPE_BOOLEAN:
36 return lhs.booleanValue == rhs.booleanValue;
37 case ConstantValue::TYPE_BYTE:
38 return lhs.byteValue == rhs.byteValue;
39 case ConstantValue::TYPE_SHORT:
40 return lhs.shortValue == rhs.shortValue;
41 case ConstantValue::TYPE_UNSIGNED_SHORT:
42 return lhs.unsignedShortValue == rhs.unsignedShortValue;
43 case ConstantValue::TYPE_LONG:
44 return lhs.longValue == rhs.longValue;
45 case ConstantValue::TYPE_UNSIGNED_LONG:
46 return lhs.unsignedLongValue == rhs.unsignedLongValue;
47 case ConstantValue::TYPE_HYPER:
48 return lhs.hyperValue == rhs.hyperValue;
49 case ConstantValue::TYPE_UNSIGNED_HYPER:
50 return lhs.unsignedHyperValue == rhs.unsignedHyperValue;
51 case ConstantValue::TYPE_FLOAT:
52 return lhs.floatValue == rhs.floatValue;
53 case ConstantValue::TYPE_DOUBLE:
54 return lhs.doubleValue == rhs.doubleValue;
57 return false;
60 static bool operator !=(ConstantValue const & lhs, ConstantValue const & rhs) {
61 return !(lhs == rhs);
64 static bool operator ==(
65 SingleInterfaceBasedServiceEntity::Constructor::Parameter const & lhs,
66 SingleInterfaceBasedServiceEntity::Constructor::Parameter const & rhs)
68 return lhs.name == rhs.name && lhs.type == rhs.type && lhs.rest == rhs.rest;
73 namespace {
75 void badUsage() {
76 std::cerr
77 << "Usage:" << std::endl << std::endl
78 << (" unoidl-check [--ignore-unpublished] [<extra registries A>]"
79 " <registry A> --")
80 << std::endl << " [<extra registries B>] <registry B>" << std::endl
81 << std::endl
82 << ("where each <registry> is either a new- or legacy-format .rdb file,"
83 " a single .idl")
84 << std::endl
85 << ("file, or a root directory of an .idl file tree. Check that each"
86 " entity from")
87 << std::endl
88 << "<registry A> is also present in <registry B> in a compatible form."
89 << std::endl;
90 std::exit(EXIT_FAILURE);
93 bool getArgument(
94 sal_uInt32 argument, bool * ignoreUnpublished, bool * delimiter,
95 OUString * uri)
97 assert(ignoreUnpublished != nullptr);
98 assert(uri != nullptr);
99 OUString arg;
100 rtl_getAppCommandArg(argument, &arg.pData);
101 if (argument == 0 && arg == "--ignore-unpublished") {
102 *ignoreUnpublished = true;
103 return false;
105 if (arg == "--") {
106 if (delimiter == nullptr) {
107 badUsage();
109 *delimiter = true;
110 return false;
112 OUString url;
113 osl::FileBase::RC e1 = osl::FileBase::getFileURLFromSystemPath(arg, url);
114 if (e1 != osl::FileBase::E_None) {
115 std::cerr
116 << "Cannot convert \"" << arg << "\" to file URL, error code "
117 << +e1 << std::endl;
118 std::exit(EXIT_FAILURE);
120 OUString cwd;
121 oslProcessError e2 = osl_getProcessWorkingDir(&cwd.pData);
122 if (e2 != osl_Process_E_None) {
123 std::cerr
124 << "Cannot obtain working directory, error code " << +e2
125 << std::endl;
126 std::exit(EXIT_FAILURE);
128 e1 = osl::FileBase::getAbsoluteFileURL(cwd, url, *uri);
129 if (e1 != osl::FileBase::E_None) {
130 std::cerr
131 << "Cannot make \"" << url
132 << "\" into an absolute file URL, error code " << +e1 << std::endl;
133 std::exit(EXIT_FAILURE);
135 return true;
138 OUString showDirection(
139 unoidl::InterfaceTypeEntity::Method::Parameter::Direction direction)
141 switch (direction) {
142 case unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN:
143 return "[in]";
144 case unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_OUT:
145 return "[out]";
146 case unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN_OUT:
147 return "[inout]";
148 default:
149 assert(false && "this cannot happen"); for (;;) { std::abort(); }
153 struct EqualsAnnotation {
154 explicit EqualsAnnotation(OUString name): name_(std::move(name)) {}
156 bool operator ()(unoidl::AnnotatedReference const & ref)
157 { return ref.name == name_; }
159 private:
160 OUString name_;
163 void checkMap(
164 rtl::Reference<unoidl::Provider> const & providerB, std::u16string_view prefix,
165 rtl::Reference<unoidl::MapCursor> const & cursor, bool ignoreUnpublished)
167 assert(providerB.is());
168 assert(cursor.is());
169 for (;;) {
170 OUString id;
171 rtl::Reference<unoidl::Entity> entA(cursor->getNext(&id));
172 if (!entA.is()) {
173 break;
175 OUString name(prefix + id);
176 if (entA->getSort() == unoidl::Entity::SORT_MODULE) {
177 checkMap(
178 providerB, Concat2View(name + "."),
179 (static_cast<unoidl::ModuleEntity *>(entA.get())
180 ->createCursor()),
181 ignoreUnpublished);
182 } else {
183 bool pubA = dynamic_cast<unoidl::PublishableEntity&>(*entA).isPublished();
184 if (!pubA && ignoreUnpublished) {
185 continue;
187 rtl::Reference<unoidl::Entity> entB(providerB->findEntity(name));
188 if (!entB.is()) {
189 std::cerr
190 << "A entity " << name << " is not present in B"
191 << std::endl;
192 std::exit(EXIT_FAILURE);
194 if (entA->getSort() != entB->getSort()) {
195 std::cerr
196 << "A entity " << name << " is of different sort in B"
197 << std::endl;
198 std::exit(EXIT_FAILURE);
200 if (pubA && (!dynamic_cast<unoidl::PublishableEntity&>(*entB).isPublished()))
202 std::cerr
203 << "A published entity " << name << " is not published in B"
204 << std::endl;
205 std::exit(EXIT_FAILURE);
207 switch (entA->getSort()) {
208 case unoidl::Entity::SORT_ENUM_TYPE:
210 rtl::Reference<unoidl::EnumTypeEntity> ent2A(
211 static_cast<unoidl::EnumTypeEntity *>(entA.get()));
212 rtl::Reference<unoidl::EnumTypeEntity> ent2B(
213 static_cast<unoidl::EnumTypeEntity *>(entB.get()));
214 if (ent2A->getMembers().size()
215 != ent2B->getMembers().size())
217 std::cerr
218 << "enum type " << name
219 << " number of members changed from "
220 << ent2A->getMembers().size() << " to "
221 << ent2B->getMembers().size() << std::endl;
222 std::exit(EXIT_FAILURE);
224 for (auto
225 i(ent2A->getMembers().begin()),
226 j(ent2B->getMembers().begin());
227 i != ent2A->getMembers().end(); ++i, ++j)
229 if (i->name != j->name || i->value != j->value) {
230 std::cerr
231 << "enum type " << name << " member #"
232 << i - ent2A->getMembers().begin() + 1
233 << " changed from " << i->name << " = "
234 << i->value << " to " << j->name << " = "
235 << j->value << std::endl;
236 std::exit(EXIT_FAILURE);
239 break;
241 case unoidl::Entity::SORT_PLAIN_STRUCT_TYPE:
243 rtl::Reference<unoidl::PlainStructTypeEntity> ent2A(
244 static_cast<unoidl::PlainStructTypeEntity *>(
245 entA.get()));
246 rtl::Reference<unoidl::PlainStructTypeEntity> ent2B(
247 static_cast<unoidl::PlainStructTypeEntity *>(
248 entB.get()));
249 if (ent2A->getDirectBase() != ent2B->getDirectBase()) {
250 std::cerr
251 << "plain struct type " << name
252 << " direct base changed from "
253 << (ent2A->getDirectBase().isEmpty()
254 ? OUString("none") : ent2A->getDirectBase())
255 << " to "
256 << (ent2B->getDirectBase().isEmpty()
257 ? OUString("none") : ent2B->getDirectBase())
258 << std::endl;
259 std::exit(EXIT_FAILURE);
261 if (ent2A->getDirectMembers().size()
262 != ent2B->getDirectMembers().size())
264 std::cerr
265 << "plain struct type " << name
266 << " number of direct members changed from "
267 << ent2A->getDirectMembers().size() << " to "
268 << ent2B->getDirectMembers().size() << std::endl;
269 std::exit(EXIT_FAILURE);
271 for (auto
272 i(ent2A->getDirectMembers().begin()),
273 j(ent2B->getDirectMembers().begin());
274 i != ent2A->getDirectMembers().end(); ++i, ++j)
276 if (i->name != j->name || i->type != j->type) {
277 std::cerr
278 << "plain struct type " << name
279 << " direct member #"
280 << i - ent2A->getDirectMembers().begin() + 1
281 << " changed from " << i->type << " " << i->name
282 << " to " << j->type << " " << j->name
283 << std::endl;
284 std::exit(EXIT_FAILURE);
287 break;
289 case unoidl::Entity::SORT_POLYMORPHIC_STRUCT_TYPE_TEMPLATE:
291 rtl::Reference<unoidl::PolymorphicStructTypeTemplateEntity>
292 ent2A(
293 static_cast<unoidl::PolymorphicStructTypeTemplateEntity *>(
294 entA.get()));
295 rtl::Reference<unoidl::PolymorphicStructTypeTemplateEntity>
296 ent2B(
297 static_cast<unoidl::PolymorphicStructTypeTemplateEntity *>(
298 entB.get()));
299 if (ent2A->getTypeParameters().size()
300 != ent2B->getTypeParameters().size())
302 std::cerr
303 << "polymorphic struct type template " << name
304 << " number of type parameters changed from "
305 << ent2A->getTypeParameters().size() << " to "
306 << ent2B->getTypeParameters().size() << std::endl;
307 std::exit(EXIT_FAILURE);
309 for (auto
310 i(ent2A->getTypeParameters().begin()),
311 j(ent2B->getTypeParameters().begin());
312 i != ent2A->getTypeParameters().end(); ++i, ++j)
314 if (*i != *j) {
315 std::cerr
316 << "polymorphic struct type template " << name
317 << " type parameter #"
318 << i - ent2A->getTypeParameters().begin() + 1
319 << " changed from " << *i << " to " << *j
320 << std::endl;
321 std::exit(EXIT_FAILURE);
324 if (ent2A->getMembers().size()
325 != ent2B->getMembers().size())
327 std::cerr
328 << "polymorphic struct type template " << name
329 << " number of members changed from "
330 << ent2A->getMembers().size() << " to "
331 << ent2B->getMembers().size() << std::endl;
332 std::exit(EXIT_FAILURE);
334 for (auto
335 i(ent2A->getMembers().begin()),
336 j(ent2B->getMembers().begin());
337 i != ent2A->getMembers().end(); ++i, ++j)
339 if (i->name != j->name || i->type != j->type
340 || i->parameterized != j->parameterized)
342 std::cerr
343 << "polymorphic struct type template " << name
344 << " member #"
345 << i - ent2A->getMembers().begin() + 1
346 << " changed from "
347 << (i->parameterized
348 ? OUString("parameterized ") : OUString())
349 << i->type << " " << i->name
350 << " to "
351 << (j->parameterized
352 ? OUString("parameterized ") : OUString())
353 << j->type << " " << j->name
354 << std::endl;
355 std::exit(EXIT_FAILURE);
358 break;
360 case unoidl::Entity::SORT_EXCEPTION_TYPE:
362 rtl::Reference<unoidl::ExceptionTypeEntity> ent2A(
363 static_cast<unoidl::ExceptionTypeEntity *>(entA.get()));
364 rtl::Reference<unoidl::ExceptionTypeEntity> ent2B(
365 static_cast<unoidl::ExceptionTypeEntity *>(entB.get()));
366 if (ent2A->getDirectBase() != ent2B->getDirectBase()) {
367 std::cerr
368 << "exception type " << name
369 << " direct base changed from "
370 << (ent2A->getDirectBase().isEmpty()
371 ? OUString("none") : ent2A->getDirectBase())
372 << " to "
373 << (ent2B->getDirectBase().isEmpty()
374 ? OUString("none") : ent2B->getDirectBase())
375 << std::endl;
376 std::exit(EXIT_FAILURE);
378 if (ent2A->getDirectMembers().size()
379 != ent2B->getDirectMembers().size())
381 std::cerr
382 << "exception type " << name
383 << " number of direct members changed from "
384 << ent2A->getDirectMembers().size() << " to "
385 << ent2B->getDirectMembers().size() << std::endl;
386 std::exit(EXIT_FAILURE);
388 for (auto
389 i(ent2A->getDirectMembers().begin()),
390 j(ent2B->getDirectMembers().begin());
391 i != ent2A->getDirectMembers().end(); ++i, ++j)
393 if (i->name != j->name || i->type != j->type) {
394 std::cerr
395 << "exception type " << name
396 << " direct member #"
397 << i - ent2A->getDirectMembers().begin() + 1
398 << " changed from " << i->type << " " << i->name
399 << " to " << j->type << " " << j->name
400 << std::endl;
401 std::exit(EXIT_FAILURE);
404 break;
406 case unoidl::Entity::SORT_INTERFACE_TYPE:
408 rtl::Reference<unoidl::InterfaceTypeEntity> ent2A(
409 static_cast<unoidl::InterfaceTypeEntity *>(entA.get()));
410 rtl::Reference<unoidl::InterfaceTypeEntity> ent2B(
411 static_cast<unoidl::InterfaceTypeEntity *>(entB.get()));
412 if (ent2A->getDirectMandatoryBases().size()
413 != ent2B->getDirectMandatoryBases().size())
415 std::cerr
416 << "interface type " << name
417 << " number of direct mandatory bases changed from "
418 << ent2A->getDirectMandatoryBases().size() << " to "
419 << ent2B->getDirectMandatoryBases().size()
420 << std::endl;
421 std::exit(EXIT_FAILURE);
423 for (auto
424 i(ent2A->getDirectMandatoryBases().begin()),
425 j(ent2B->getDirectMandatoryBases().begin());
426 i != ent2A->getDirectMandatoryBases().end(); ++i, ++j)
428 if (i->name != j->name) {
429 std::cerr
430 << "interface type " << name
431 << " direct mandatory base #"
432 << (i - ent2A->getDirectMandatoryBases().begin()
433 + 1)
434 << " changed from " << i->name << " to "
435 << j->name << std::endl;
436 std::exit(EXIT_FAILURE);
439 if (ent2A->getDirectOptionalBases().size()
440 != ent2B->getDirectOptionalBases().size())
442 std::cerr
443 << "interface type " << name
444 << " number of direct optional bases changed from "
445 << ent2A->getDirectOptionalBases().size() << " to "
446 << ent2B->getDirectOptionalBases().size()
447 << std::endl;
448 std::exit(EXIT_FAILURE);
450 for (auto
451 i(ent2A->getDirectOptionalBases().begin()),
452 j(ent2B->getDirectOptionalBases().begin());
453 i != ent2A->getDirectOptionalBases().end(); ++i, ++j)
455 if (i->name != j->name) {
456 std::cerr
457 << "interface type " << name
458 << " direct optional base #"
459 << (i - ent2A->getDirectOptionalBases().begin()
460 + 1)
461 << " changed from " << i->name << " to "
462 << j->name << std::endl;
463 std::exit(EXIT_FAILURE);
466 if (ent2A->getDirectAttributes().size()
467 != ent2B->getDirectAttributes().size())
469 std::cerr
470 << "interface type " << name
471 << " number of direct attributes changed from "
472 << ent2A->getDirectAttributes().size() << " to "
473 << ent2B->getDirectAttributes().size() << std::endl;
474 std::exit(EXIT_FAILURE);
476 for (auto
477 i(ent2A->getDirectAttributes().begin()),
478 j(ent2B->getDirectAttributes().begin());
479 i != ent2A->getDirectAttributes().end(); ++i, ++j)
481 if (i->name != j->name || i->type != j->type
482 || i->bound != j->bound
483 || i->readOnly != j->readOnly
484 || i->getExceptions != j->getExceptions
485 || i->setExceptions != j->setExceptions)
487 std::cerr
488 << "interface type " << name
489 << " direct attribute #"
490 << i - ent2A->getDirectAttributes().begin() + 1
491 << " changed from "
492 << (i->bound ? OUString("bound ") : OUString())
493 << (i->readOnly
494 ? OUString("read-only ") : OUString())
495 << i->type << " " << i->name //TODO: exceptions
496 << " to "
497 << (j->bound ? OUString("bound ") : OUString())
498 << (j->readOnly
499 ? OUString("read-only ") : OUString())
500 << j->type << " " << j->name //TODO: exceptions
501 << std::endl;
502 std::exit(EXIT_FAILURE);
505 if (ent2A->getDirectMethods().size()
506 != ent2B->getDirectMethods().size())
508 std::cerr
509 << "interface type " << name
510 << " number of direct methods changed from "
511 << ent2A->getDirectMethods().size() << " to "
512 << ent2B->getDirectMethods().size() << std::endl;
513 std::exit(EXIT_FAILURE);
515 for (auto
516 i(ent2A->getDirectMethods().begin()),
517 j(ent2B->getDirectMethods().begin());
518 i != ent2A->getDirectMethods().end(); ++i, ++j)
520 if (i->name != j->name || i->returnType != j->returnType
521 || i->exceptions != j->exceptions)
523 std::cerr
524 << "interface type " << name
525 << " direct method #"
526 << i - ent2A->getDirectMethods().begin() + 1
527 << " changed from "
528 << i->returnType << " " << i->name //TODO: exceptions
529 << " to " << j->returnType << " " << j->name //TODO: exceptions
530 << std::endl;
531 std::exit(EXIT_FAILURE);
533 if (i->parameters.size() != j->parameters.size()) {
534 std::cerr
535 << "interface type " << name
536 << " direct method " << i->name
537 << " number of parameters changed from "
538 << i->parameters.size() << " to "
539 << j->parameters.size() << std::endl;
540 std::exit(EXIT_FAILURE);
542 for (auto
543 k(i->parameters.begin()),
544 l(j->parameters.begin());
545 k != i->parameters.end(); ++k, ++l)
547 if (k->type != l->type || k->direction != l->direction)
549 std::cerr
550 << "interface type " << name
551 << " direct method " << i->name
552 << " parameter #"
553 << k - i->parameters.begin() + 1
554 << " changed from "
555 << showDirection(k->direction) << " "
556 << k->type << " to "
557 << showDirection(l->direction) << " "
558 << l->type << std::endl;
559 std::exit(EXIT_FAILURE);
561 if (k->name != l->name) {
562 std::cerr
563 << "interface type " << name
564 << " direct method " << i->name
565 << " parameter #"
566 << k - i->parameters.begin() + 1
567 << " changed name from " << k->name
568 << " to " << l->name << std::endl;
569 std::exit(EXIT_FAILURE);
573 break;
575 case unoidl::Entity::SORT_TYPEDEF:
577 rtl::Reference<unoidl::TypedefEntity> ent2A(
578 static_cast<unoidl::TypedefEntity *>(entA.get()));
579 rtl::Reference<unoidl::TypedefEntity> ent2B(
580 static_cast<unoidl::TypedefEntity *>(entB.get()));
581 if (ent2A->getType() != ent2B->getType()) {
582 std::cerr
583 << "typedef " << name << " type changed from "
584 << ent2A->getType() << " to " << ent2B->getType()
585 << std::endl;
586 std::exit(EXIT_FAILURE);
588 break;
590 case unoidl::Entity::SORT_CONSTANT_GROUP:
592 rtl::Reference<unoidl::ConstantGroupEntity> ent2A(
593 static_cast<unoidl::ConstantGroupEntity *>(entA.get()));
594 rtl::Reference<unoidl::ConstantGroupEntity> ent2B(
595 static_cast<unoidl::ConstantGroupEntity *>(entB.get()));
596 for (auto & i: ent2A->getMembers()) {
597 bool found = false;
598 for (auto & j: ent2B->getMembers()) {
599 if (i.name == j.name) {
600 if (i.value != j.value) {
601 std::cerr
602 << "constant group " << name
603 << " member " << i.name
604 << " changed value" << std::endl;
605 std::exit(EXIT_FAILURE);
607 found = true;
608 break;
611 if (!found) {
612 std::cerr
613 << "A constant group " << name << " member "
614 << i.name << " is not present in B"
615 << std::endl;
616 std::exit(EXIT_FAILURE);
619 break;
621 case unoidl::Entity::SORT_SINGLE_INTERFACE_BASED_SERVICE:
623 rtl::Reference<unoidl::SingleInterfaceBasedServiceEntity>
624 ent2A(
625 static_cast<unoidl::SingleInterfaceBasedServiceEntity *>(
626 entA.get()));
627 rtl::Reference<unoidl::SingleInterfaceBasedServiceEntity>
628 ent2B(
629 static_cast<unoidl::SingleInterfaceBasedServiceEntity *>(
630 entB.get()));
631 if (ent2A->getBase() != ent2B->getBase()) {
632 std::cerr
633 << "single-interface--based service " << name
634 << " base changed from " << ent2A->getBase()
635 << " to " << ent2B->getBase()
636 << std::endl;
637 std::exit(EXIT_FAILURE);
639 if (ent2A->getConstructors().size()
640 != ent2B->getConstructors().size())
642 std::cerr
643 << "single-interface--based service " << name
644 << " number of constructors changed from "
645 << ent2A->getConstructors().size() << " to "
646 << ent2B->getConstructors().size() << std::endl;
647 std::exit(EXIT_FAILURE);
649 for (auto
650 i(ent2A->getConstructors().begin()),
651 j(ent2B->getConstructors().begin());
652 i != ent2A->getConstructors().end(); ++i, ++j)
654 if (i->name != j->name || i->parameters != j->parameters
655 || i->exceptions != j->exceptions
656 || i->defaultConstructor != j->defaultConstructor)
658 std::cerr
659 << "single-interface--based service " << name
660 << " constructor #"
661 << i - ent2A->getConstructors().begin() + 1
662 << " changed from "
663 << (i->defaultConstructor
664 ? OUString("default ") : i->name) //TODO: parameters, exceptions
665 << " to "
666 << (j->defaultConstructor
667 ? OUString("default ") : j->name) //TODO: parameters, exceptions
668 << std::endl;
669 std::exit(EXIT_FAILURE);
672 break;
674 case unoidl::Entity::SORT_ACCUMULATION_BASED_SERVICE:
676 rtl::Reference<unoidl::AccumulationBasedServiceEntity>
677 ent2A(
678 static_cast<unoidl::AccumulationBasedServiceEntity *>(
679 entA.get()));
680 rtl::Reference<unoidl::AccumulationBasedServiceEntity>
681 ent2B(
682 static_cast<unoidl::AccumulationBasedServiceEntity *>(
683 entB.get()));
684 if (ent2A->getDirectMandatoryBaseServices().size()
685 != ent2B->getDirectMandatoryBaseServices().size())
687 std::cerr
688 << "accumulation-based service " << name
689 << (" number of direct mandatory base services"
690 " changed from ")
691 << ent2A->getDirectMandatoryBaseServices().size()
692 << " to "
693 << ent2B->getDirectMandatoryBaseServices().size()
694 << std::endl;
695 std::exit(EXIT_FAILURE);
697 for (auto
698 i(ent2A->getDirectMandatoryBaseServices().begin()),
699 j(ent2B->getDirectMandatoryBaseServices().begin());
700 i != ent2A->getDirectMandatoryBaseServices().end();
701 ++i, ++j)
703 if (i->name != j->name) {
704 std::cerr
705 << "accumulation-based service " << name
706 << " direct mandatory base service #"
707 << (i
708 - (ent2A->getDirectMandatoryBaseServices()
709 .begin())
710 + 1)
711 << " changed from " << i->name << " to "
712 << j->name << std::endl;
713 std::exit(EXIT_FAILURE);
716 if (ent2A->getDirectOptionalBaseServices().size()
717 > ent2B->getDirectOptionalBaseServices().size())
719 std::cerr
720 << "accumulation-based service " << name
721 << (" number of direct optional base services"
722 " shrank from ")
723 << ent2A->getDirectOptionalBaseServices().size()
724 << " to "
725 << ent2B->getDirectOptionalBaseServices().size()
726 << std::endl;
727 std::exit(EXIT_FAILURE);
729 for (auto & i: ent2A->getDirectOptionalBaseServices()) {
730 if (std::none_of(
731 ent2B->getDirectOptionalBaseServices().begin(),
732 ent2B->getDirectOptionalBaseServices().end(),
733 EqualsAnnotation(i.name)))
735 std::cerr
736 << "accumulation-based service " << name
737 << " direct optional base service " << i.name
738 << " was removed" << std::endl;
739 std::exit(EXIT_FAILURE);
742 if (ent2A->getDirectMandatoryBaseInterfaces().size()
743 != ent2B->getDirectMandatoryBaseInterfaces().size())
745 std::cerr
746 << "accumulation-based service " << name
747 << (" number of direct mandatory base interfaces"
748 " changed from ")
749 << ent2A->getDirectMandatoryBaseInterfaces().size()
750 << " to "
751 << ent2B->getDirectMandatoryBaseInterfaces().size()
752 << std::endl;
753 std::exit(EXIT_FAILURE);
755 for (auto
756 i(ent2A->getDirectMandatoryBaseInterfaces()
757 .begin()),
758 j(ent2B->getDirectMandatoryBaseInterfaces()
759 .begin());
760 i != ent2A->getDirectMandatoryBaseInterfaces().end();
761 ++i, ++j)
763 if (i->name != j->name) {
764 std::cerr
765 << "accumulation-based service " << name
766 << " direct mandatory base interface #"
767 << (i
768 - (ent2A->getDirectMandatoryBaseInterfaces()
769 .begin())
770 + 1)
771 << " changed from " << i->name << " to "
772 << j->name << std::endl;
773 std::exit(EXIT_FAILURE);
776 if (ent2A->getDirectOptionalBaseInterfaces().size()
777 > ent2B->getDirectOptionalBaseInterfaces().size())
779 std::cerr
780 << "accumulation-based service " << name
781 << (" number of direct optional base interfaces"
782 " shrank from ")
783 << ent2A->getDirectOptionalBaseInterfaces().size()
784 << " to "
785 << ent2B->getDirectOptionalBaseInterfaces().size()
786 << std::endl;
787 std::exit(EXIT_FAILURE);
789 for (auto & i: ent2A->getDirectOptionalBaseInterfaces()) {
790 if (std::none_of(
791 (ent2B->getDirectOptionalBaseInterfaces()
792 .begin()),
793 ent2B->getDirectOptionalBaseInterfaces().end(),
794 EqualsAnnotation(i.name)))
796 std::cerr
797 << "accumulation-based service " << name
798 << " direct optional base interface " << i.name
799 << " was removed" << std::endl;
800 std::exit(EXIT_FAILURE);
803 if (ent2A->getDirectProperties().size()
804 > ent2B->getDirectProperties().size())
806 std::cerr
807 << "accumulation-based service " << name
808 << " number of direct properties changed from "
809 << ent2A->getDirectProperties().size() << " to "
810 << ent2B->getDirectProperties().size() << std::endl;
811 std::exit(EXIT_FAILURE);
813 for (auto
814 i(ent2A->getDirectProperties().begin()),
815 j(ent2B->getDirectProperties().begin());
816 i != ent2A->getDirectProperties().end(); ++i, ++j)
818 if (i->name != j->name || i->type != j->type
819 || i->attributes != j->attributes)
821 std::cerr
822 << "accumulation-based service " << name
823 << " direct property #"
824 << i - ent2A->getDirectProperties().begin() + 1
825 << " changed from "
826 << i->type << " " << i->name //TODO: attributes
827 << " to "
828 << j->type << " " << j->name //TODO: attributes
829 << std::endl;
830 std::exit(EXIT_FAILURE);
833 for (auto
834 i(ent2B->getDirectProperties().begin()
835 + ent2A->getDirectProperties().size());
836 i != ent2B->getDirectProperties().end(); ++i)
838 if ((i->attributes & unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_OPTIONAL) == 0)
840 std::cerr
841 << "B accumulation-based service " << name
842 << " additional direct property " << i->name
843 << " is not optional" << std::endl;
844 std::exit(EXIT_FAILURE);
847 break;
849 case unoidl::Entity::SORT_INTERFACE_BASED_SINGLETON:
851 rtl::Reference<unoidl::InterfaceBasedSingletonEntity> ent2A(
852 static_cast<unoidl::InterfaceBasedSingletonEntity *>(
853 entA.get()));
854 rtl::Reference<unoidl::InterfaceBasedSingletonEntity> ent2B(
855 static_cast<unoidl::InterfaceBasedSingletonEntity *>(
856 entB.get()));
857 if (ent2A->getBase() != ent2B->getBase()) {
858 std::cerr
859 << "interface-based singleton " << name
860 << " base changed from " << ent2A->getBase()
861 << " to " << ent2B->getBase() << std::endl;
862 std::exit(EXIT_FAILURE);
864 break;
866 case unoidl::Entity::SORT_SERVICE_BASED_SINGLETON:
868 rtl::Reference<unoidl::ServiceBasedSingletonEntity> ent2A(
869 static_cast<unoidl::ServiceBasedSingletonEntity *>(
870 entA.get()));
871 rtl::Reference<unoidl::ServiceBasedSingletonEntity> ent2B(
872 static_cast<unoidl::ServiceBasedSingletonEntity *>(
873 entB.get()));
874 if (ent2A->getBase() != ent2B->getBase()) {
875 std::cerr
876 << "service-based singleton " << name
877 << " base changed from " << ent2A->getBase()
878 << " to " << ent2B->getBase() << std::endl;
879 std::exit(EXIT_FAILURE);
881 break;
883 case unoidl::Entity::SORT_MODULE:
884 assert(false && "this cannot happen");
890 bool valid(std::u16string_view identifier) {
891 for (size_t i = 0;; ++i) {
892 i = identifier.find('_', i);
893 if (i == std::u16string_view::npos) {
894 return true;
896 if (!rtl::isAsciiUpperCase(identifier[0]) || identifier[i - 1] == '_') {
897 return false;
902 void checkIds(
903 rtl::Reference<unoidl::Provider> const & providerA, std::u16string_view prefix,
904 rtl::Reference<unoidl::MapCursor> const & cursor)
906 assert(cursor.is());
907 for (;;) {
908 OUString id;
909 rtl::Reference<unoidl::Entity> entB(cursor->getNext(&id));
910 if (!entB.is()) {
911 break;
913 OUString name(prefix + id);
914 rtl::Reference<unoidl::Entity> entA(providerA->findEntity(name));
915 if (!(entA.is() || valid(id))) {
916 std::cerr
917 << "entity name " << name << " uses an invalid identifier"
918 << std::endl;
919 std::exit(EXIT_FAILURE);
921 switch (entB->getSort()) {
922 case unoidl::Entity::SORT_MODULE:
923 checkIds(
924 providerA, Concat2View(name + "."),
925 (static_cast<unoidl::ModuleEntity *>(entB.get())
926 ->createCursor()));
927 break;
928 case unoidl::Entity::SORT_ENUM_TYPE:
929 if (!entA.is()) {
930 rtl::Reference<unoidl::EnumTypeEntity> ent2B(
931 static_cast<unoidl::EnumTypeEntity *>(entB.get()));
932 for (auto & i: ent2B->getMembers()) {
933 if (!valid(i.name)) {
934 std::cerr
935 << "enum type " << name << " member " << i.name
936 << " uses an invalid identifier" << std::endl;
937 std::exit(EXIT_FAILURE);
941 break;
942 case unoidl::Entity::SORT_PLAIN_STRUCT_TYPE:
943 if (!entA.is()) {
944 rtl::Reference<unoidl::PlainStructTypeEntity> ent2B(
945 static_cast<unoidl::PlainStructTypeEntity *>(
946 entB.get()));
947 for (auto & i: ent2B->getDirectMembers()) {
948 if (!valid(i.name)) {
949 std::cerr
950 << "plain struct type " << name << " direct member "
951 << i.name << " uses an invalid identifier"
952 << std::endl;
953 std::exit(EXIT_FAILURE);
957 break;
958 case unoidl::Entity::SORT_POLYMORPHIC_STRUCT_TYPE_TEMPLATE:
959 if (!entA.is()) {
960 rtl::Reference<unoidl::PolymorphicStructTypeTemplateEntity>
961 ent2B(
962 static_cast<
963 unoidl::PolymorphicStructTypeTemplateEntity *>(
964 entB.get()));
965 for (auto & i: ent2B->getTypeParameters()) {
966 if (!valid(i)) {
967 std::cerr
968 << "polymorphic struct type template " << name
969 << " type parameter " << i
970 << " uses an invalid identifier" << std::endl;
971 std::exit(EXIT_FAILURE);
974 for (auto & i: ent2B->getMembers()) {
975 if (!valid(i.name)) {
976 std::cerr
977 << "polymorphic struct type template " << name
978 << " member " << i.name
979 << " uses an invalid identifier" << std::endl;
980 std::exit(EXIT_FAILURE);
984 break;
985 case unoidl::Entity::SORT_EXCEPTION_TYPE:
986 if (!entA.is()) {
987 rtl::Reference<unoidl::ExceptionTypeEntity> ent2B(
988 static_cast<unoidl::ExceptionTypeEntity *>(entB.get()));
989 for (auto & i: ent2B->getDirectMembers()) {
990 if (!valid(i.name)) {
991 std::cerr
992 << "exception type " << name << " direct member "
993 << i.name << " uses an invalid identifier"
994 << std::endl;
995 std::exit(EXIT_FAILURE);
999 break;
1000 case unoidl::Entity::SORT_INTERFACE_TYPE:
1001 if (!entA.is()) {
1002 rtl::Reference<unoidl::InterfaceTypeEntity> ent2B(
1003 static_cast<unoidl::InterfaceTypeEntity *>(entB.get()));
1004 for (auto & i: ent2B->getDirectAttributes()) {
1005 if (!valid(i.name)) {
1006 std::cerr
1007 << "interface type " << name << " direct attribute "
1008 << i.name << " uses an invalid identifier"
1009 << std::endl;
1010 std::exit(EXIT_FAILURE);
1013 for (auto & i: ent2B->getDirectMethods()) {
1014 if (!valid(i.name)) {
1015 std::cerr
1016 << "interface type " << name << " direct method "
1017 << i.name << " uses an invalid identifier"
1018 << std::endl;
1019 std::exit(EXIT_FAILURE);
1021 for (auto & j: i.parameters) {
1022 if (!valid(j.name)) {
1023 std::cerr
1024 << "interface type " << name
1025 << " direct method " << i.name << " parameter "
1026 << j.name << " uses an invalid identifier"
1027 << std::endl;
1028 std::exit(EXIT_FAILURE);
1033 break;
1034 case unoidl::Entity::SORT_TYPEDEF:
1035 case unoidl::Entity::SORT_INTERFACE_BASED_SINGLETON:
1036 case unoidl::Entity::SORT_SERVICE_BASED_SINGLETON:
1037 break;
1038 case unoidl::Entity::SORT_CONSTANT_GROUP:
1040 rtl::Reference<unoidl::ConstantGroupEntity> ent2B(
1041 static_cast<unoidl::ConstantGroupEntity *>(entB.get()));
1042 for (auto & i: ent2B->getMembers()) {
1043 bool found = false;
1044 if (entA.is()) {
1045 rtl::Reference<unoidl::ConstantGroupEntity> ent2A(
1046 static_cast<unoidl::ConstantGroupEntity *>(
1047 entA.get()));
1048 for (auto & j: ent2A->getMembers()) {
1049 if (i.name == j.name) {
1050 found = true;
1051 break;
1055 if (!(found || valid(i.name))) {
1056 std::cerr
1057 << "Constant group " << name << " member "
1058 << i.name << " uses an invalid identifier"
1059 << std::endl;
1060 std::exit(EXIT_FAILURE);
1063 break;
1065 case unoidl::Entity::SORT_SINGLE_INTERFACE_BASED_SERVICE:
1066 if (!entA.is()) {
1067 rtl::Reference<unoidl::SingleInterfaceBasedServiceEntity>
1068 ent2B(
1069 static_cast<unoidl::SingleInterfaceBasedServiceEntity *>(
1070 entB.get()));
1071 for (auto & i: ent2B->getConstructors()) {
1072 if (!valid(i.name)) {
1073 std::cerr
1074 << "single-interface--based service " << name
1075 << " constructor " << i.name
1076 << " uses an invalid identifier" << std::endl;
1077 std::exit(EXIT_FAILURE);
1079 for (auto & j: i.parameters) {
1080 if (!valid(j.name)) {
1081 std::cerr
1082 << "single-interface--based service " << name
1083 << " constructor " << i.name << " parameter "
1084 << j.name << " uses an invalid identifier"
1085 << std::endl;
1086 std::exit(EXIT_FAILURE);
1091 break;
1092 case unoidl::Entity::SORT_ACCUMULATION_BASED_SERVICE:
1094 rtl::Reference<unoidl::AccumulationBasedServiceEntity> ent2B(
1095 static_cast<unoidl::AccumulationBasedServiceEntity *>(
1096 entB.get()));
1097 std::vector<unoidl::AccumulationBasedServiceEntity::Property>::size_type
1098 n(entA.is()
1099 ? (static_cast<unoidl::AccumulationBasedServiceEntity *>(
1100 entA.get())
1101 ->getDirectProperties().size())
1102 : 0);
1103 assert(n <= ent2B->getDirectProperties().size());
1104 for (auto i(ent2B->getDirectProperties().begin() +n);
1105 i != ent2B->getDirectProperties().end(); ++i)
1107 if (!valid(i->name)) {
1108 std::cerr
1109 << "accumulation-based service " << name
1110 << " direct property " << i->name
1111 << " uses an invalid identifier" << std::endl;
1112 std::exit(EXIT_FAILURE);
1115 break;
1123 SAL_IMPLEMENT_MAIN() {
1124 try {
1125 sal_uInt32 args = rtl_getAppCommandArgCount();
1126 rtl::Reference<unoidl::Manager> mgr[2];
1127 mgr[0] = new unoidl::Manager;
1128 mgr[1] = new unoidl::Manager;
1129 rtl::Reference<unoidl::Provider> prov[2];
1130 int side = 0;
1131 bool ignoreUnpublished = false;
1132 for (sal_uInt32 i = 0; i != args; ++i) {
1133 bool delimiter = false;
1134 OUString uri;
1135 if (getArgument(
1136 i, &ignoreUnpublished, side == 0 ? &delimiter : nullptr,
1137 &uri))
1139 try {
1140 prov[side] = mgr[side]->addProvider(uri);
1141 } catch (unoidl::NoSuchFileException &) {
1142 std::cerr
1143 << "Input <" << uri << "> does not exist" << std::endl;
1144 std::exit(EXIT_FAILURE);
1146 } else if (delimiter) {
1147 side = 1;
1150 if (side == 0 || !(prov[0].is() && prov[1].is())) {
1151 badUsage();
1153 checkMap(prov[1], u"", prov[0]->createRootCursor(), ignoreUnpublished);
1154 checkIds(prov[0], u"", prov[1]->createRootCursor());
1155 return EXIT_SUCCESS;
1156 } catch (unoidl::FileFormatException & e1) {
1157 std::cerr
1158 << "Bad input <" << e1.getUri() << ">: " << e1.getDetail()
1159 << std::endl;
1160 std::exit(EXIT_FAILURE);
1161 } catch (std::exception & e1) {
1162 std::cerr << "Failure: " << e1.what() << std::endl;
1163 std::exit(EXIT_FAILURE);
1167 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */