bump product version to 7.2.5.1
[LibreOffice.git] / unoidl / source / unoidl-check.cxx
bloba3cade0b0334ddaab2d329e6c9466889f2914f6d
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 <vector>
19 #include <osl/file.hxx>
20 #include <osl/process.h>
21 #include <rtl/character.hxx>
22 #include <rtl/process.h>
23 #include <rtl/ref.hxx>
24 #include <rtl/ustring.hxx>
25 #include <sal/main.h>
26 #include <sal/types.h>
27 #include <unoidl/unoidl.hxx>
29 namespace unoidl {
31 static bool operator ==(ConstantValue const & lhs, ConstantValue const & rhs) {
32 if (lhs.type == rhs.type) {
33 switch (lhs.type) {
34 case ConstantValue::TYPE_BOOLEAN:
35 return lhs.booleanValue == rhs.booleanValue;
36 case ConstantValue::TYPE_BYTE:
37 return lhs.byteValue == rhs.byteValue;
38 case ConstantValue::TYPE_SHORT:
39 return lhs.shortValue == rhs.shortValue;
40 case ConstantValue::TYPE_UNSIGNED_SHORT:
41 return lhs.unsignedShortValue == rhs.unsignedShortValue;
42 case ConstantValue::TYPE_LONG:
43 return lhs.longValue == rhs.longValue;
44 case ConstantValue::TYPE_UNSIGNED_LONG:
45 return lhs.unsignedLongValue == rhs.unsignedLongValue;
46 case ConstantValue::TYPE_HYPER:
47 return lhs.hyperValue == rhs.hyperValue;
48 case ConstantValue::TYPE_UNSIGNED_HYPER:
49 return lhs.unsignedHyperValue == rhs.unsignedHyperValue;
50 case ConstantValue::TYPE_FLOAT:
51 return lhs.floatValue == rhs.floatValue;
52 case ConstantValue::TYPE_DOUBLE:
53 return lhs.doubleValue == rhs.doubleValue;
56 return false;
59 static bool operator !=(ConstantValue const & lhs, ConstantValue const & rhs) {
60 return !(lhs == rhs);
63 static bool operator ==(
64 SingleInterfaceBasedServiceEntity::Constructor::Parameter const & lhs,
65 SingleInterfaceBasedServiceEntity::Constructor::Parameter const & rhs)
67 return lhs.name == rhs.name && lhs.type == rhs.type && lhs.rest == rhs.rest;
72 namespace {
74 void badUsage() {
75 std::cerr
76 << "Usage:" << std::endl << std::endl
77 << (" unoidl-check [--ignore-unpublished] [<extra registries A>]"
78 " <registry A> --")
79 << std::endl << " [<extra registries B>] <registry B>" << std::endl
80 << std::endl
81 << ("where each <registry> is either a new- or legacy-format .rdb file,"
82 " a single .idl")
83 << std::endl
84 << ("file, or a root directory of an .idl file tree. Check that each"
85 " entity from")
86 << std::endl
87 << "<registry A> is also present in <registry B> in a compatible form."
88 << std::endl;
89 std::exit(EXIT_FAILURE);
92 bool getArgument(
93 sal_uInt32 argument, bool * ignoreUnpublished, bool * delimiter,
94 OUString * uri)
96 assert(ignoreUnpublished != nullptr);
97 assert(uri != nullptr);
98 OUString arg;
99 rtl_getAppCommandArg(argument, &arg.pData);
100 if (argument == 0 && arg == "--ignore-unpublished") {
101 *ignoreUnpublished = true;
102 return false;
104 if (arg == "--") {
105 if (delimiter == nullptr) {
106 badUsage();
108 *delimiter = true;
109 return false;
111 OUString url;
112 osl::FileBase::RC e1 = osl::FileBase::getFileURLFromSystemPath(arg, url);
113 if (e1 != osl::FileBase::E_None) {
114 std::cerr
115 << "Cannot convert \"" << arg << "\" to file URL, error code "
116 << +e1 << std::endl;
117 std::exit(EXIT_FAILURE);
119 OUString cwd;
120 oslProcessError e2 = osl_getProcessWorkingDir(&cwd.pData);
121 if (e2 != osl_Process_E_None) {
122 std::cerr
123 << "Cannot obtain working directory, error code " << +e2
124 << std::endl;
125 std::exit(EXIT_FAILURE);
127 e1 = osl::FileBase::getAbsoluteFileURL(cwd, url, *uri);
128 if (e1 != osl::FileBase::E_None) {
129 std::cerr
130 << "Cannot make \"" << url
131 << "\" into an absolute file URL, error code " << +e1 << std::endl;
132 std::exit(EXIT_FAILURE);
134 return true;
137 OUString showDirection(
138 unoidl::InterfaceTypeEntity::Method::Parameter::Direction direction)
140 switch (direction) {
141 case unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN:
142 return "[in]";
143 case unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_OUT:
144 return "[out]";
145 case unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN_OUT:
146 return "[inout]";
147 default:
148 assert(false && "this cannot happen"); for (;;) { std::abort(); }
152 struct EqualsAnnotation {
153 explicit EqualsAnnotation(OUString const & name): name_(name) {}
155 bool operator ()(unoidl::AnnotatedReference const & ref)
156 { return ref.name == name_; }
158 private:
159 OUString name_;
162 void checkMap(
163 rtl::Reference<unoidl::Provider> const & providerB, std::u16string_view prefix,
164 rtl::Reference<unoidl::MapCursor> const & cursor, bool ignoreUnpublished)
166 assert(providerB.is());
167 assert(cursor.is());
168 for (;;) {
169 OUString id;
170 rtl::Reference<unoidl::Entity> entA(cursor->getNext(&id));
171 if (!entA.is()) {
172 break;
174 OUString name(prefix + id);
175 if (entA->getSort() == unoidl::Entity::SORT_MODULE) {
176 checkMap(
177 providerB, OUString(name + "."),
178 (static_cast<unoidl::ModuleEntity *>(entA.get())
179 ->createCursor()),
180 ignoreUnpublished);
181 } else {
182 bool pubA = dynamic_cast<unoidl::PublishableEntity&>(*entA).isPublished();
183 if (!pubA && ignoreUnpublished) {
184 continue;
186 rtl::Reference<unoidl::Entity> entB(providerB->findEntity(name));
187 if (!entB.is()) {
188 std::cerr
189 << "A entity " << name << " is not present in B"
190 << std::endl;
191 std::exit(EXIT_FAILURE);
193 if (entA->getSort() != entB->getSort()) {
194 std::cerr
195 << "A entity " << name << " is of different sort in B"
196 << std::endl;
197 std::exit(EXIT_FAILURE);
199 if (pubA && (!dynamic_cast<unoidl::PublishableEntity&>(*entB).isPublished()))
201 std::cerr
202 << "A published entity " << name << " is not published in B"
203 << std::endl;
204 std::exit(EXIT_FAILURE);
206 switch (entA->getSort()) {
207 case unoidl::Entity::SORT_ENUM_TYPE:
209 rtl::Reference<unoidl::EnumTypeEntity> ent2A(
210 static_cast<unoidl::EnumTypeEntity *>(entA.get()));
211 rtl::Reference<unoidl::EnumTypeEntity> ent2B(
212 static_cast<unoidl::EnumTypeEntity *>(entB.get()));
213 if (ent2A->getMembers().size()
214 != ent2B->getMembers().size())
216 std::cerr
217 << "enum type " << name
218 << " number of members changed from "
219 << ent2A->getMembers().size() << " to "
220 << ent2B->getMembers().size() << std::endl;
221 std::exit(EXIT_FAILURE);
223 for (auto
224 i(ent2A->getMembers().begin()),
225 j(ent2B->getMembers().begin());
226 i != ent2A->getMembers().end(); ++i, ++j)
228 if (i->name != j->name || i->value != j->value) {
229 std::cerr
230 << "enum type " << name << " member #"
231 << i - ent2A->getMembers().begin() + 1
232 << " changed from " << i->name << " = "
233 << i->value << " to " << j->name << " = "
234 << j->value << std::endl;
235 std::exit(EXIT_FAILURE);
238 break;
240 case unoidl::Entity::SORT_PLAIN_STRUCT_TYPE:
242 rtl::Reference<unoidl::PlainStructTypeEntity> ent2A(
243 static_cast<unoidl::PlainStructTypeEntity *>(
244 entA.get()));
245 rtl::Reference<unoidl::PlainStructTypeEntity> ent2B(
246 static_cast<unoidl::PlainStructTypeEntity *>(
247 entB.get()));
248 if (ent2A->getDirectBase() != ent2B->getDirectBase()) {
249 std::cerr
250 << "plain struct type " << name
251 << " direct base changed from "
252 << (ent2A->getDirectBase().isEmpty()
253 ? OUString("none") : ent2A->getDirectBase())
254 << " to "
255 << (ent2B->getDirectBase().isEmpty()
256 ? OUString("none") : ent2B->getDirectBase())
257 << std::endl;
258 std::exit(EXIT_FAILURE);
260 if (ent2A->getDirectMembers().size()
261 != ent2B->getDirectMembers().size())
263 std::cerr
264 << "plain struct type " << name
265 << " number of direct members changed from "
266 << ent2A->getDirectMembers().size() << " to "
267 << ent2B->getDirectMembers().size() << std::endl;
268 std::exit(EXIT_FAILURE);
270 for (auto
271 i(ent2A->getDirectMembers().begin()),
272 j(ent2B->getDirectMembers().begin());
273 i != ent2A->getDirectMembers().end(); ++i, ++j)
275 if (i->name != j->name || i->type != j->type) {
276 std::cerr
277 << "plain struct type " << name
278 << " direct member #"
279 << i - ent2A->getDirectMembers().begin() + 1
280 << " changed from " << i->type << " " << i->name
281 << " to " << j->type << " " << j->name
282 << std::endl;
283 std::exit(EXIT_FAILURE);
286 break;
288 case unoidl::Entity::SORT_POLYMORPHIC_STRUCT_TYPE_TEMPLATE:
290 rtl::Reference<unoidl::PolymorphicStructTypeTemplateEntity>
291 ent2A(
292 static_cast<unoidl::PolymorphicStructTypeTemplateEntity *>(
293 entA.get()));
294 rtl::Reference<unoidl::PolymorphicStructTypeTemplateEntity>
295 ent2B(
296 static_cast<unoidl::PolymorphicStructTypeTemplateEntity *>(
297 entB.get()));
298 if (ent2A->getTypeParameters().size()
299 != ent2B->getTypeParameters().size())
301 std::cerr
302 << "polymorphic struct type template " << name
303 << " number of type parameters changed from "
304 << ent2A->getTypeParameters().size() << " to "
305 << ent2B->getTypeParameters().size() << std::endl;
306 std::exit(EXIT_FAILURE);
308 for (auto
309 i(ent2A->getTypeParameters().begin()),
310 j(ent2B->getTypeParameters().begin());
311 i != ent2A->getTypeParameters().end(); ++i, ++j)
313 if (*i != *j) {
314 std::cerr
315 << "polymorphic struct type template " << name
316 << " type parameter #"
317 << i - ent2A->getTypeParameters().begin() + 1
318 << " changed from " << *i << " to " << *j
319 << std::endl;
320 std::exit(EXIT_FAILURE);
323 if (ent2A->getMembers().size()
324 != ent2B->getMembers().size())
326 std::cerr
327 << "polymorphic struct type template " << name
328 << " number of members changed from "
329 << ent2A->getMembers().size() << " to "
330 << ent2B->getMembers().size() << std::endl;
331 std::exit(EXIT_FAILURE);
333 for (auto
334 i(ent2A->getMembers().begin()),
335 j(ent2B->getMembers().begin());
336 i != ent2A->getMembers().end(); ++i, ++j)
338 if (i->name != j->name || i->type != j->type
339 || i->parameterized != j->parameterized)
341 std::cerr
342 << "polymorphic struct type template " << name
343 << " member #"
344 << i - ent2A->getMembers().begin() + 1
345 << " changed from "
346 << (i->parameterized
347 ? OUString("parameterized ") : OUString())
348 << i->type << " " << i->name
349 << " to "
350 << (j->parameterized
351 ? OUString("parameterized ") : OUString())
352 << j->type << " " << j->name
353 << std::endl;
354 std::exit(EXIT_FAILURE);
357 break;
359 case unoidl::Entity::SORT_EXCEPTION_TYPE:
361 rtl::Reference<unoidl::ExceptionTypeEntity> ent2A(
362 static_cast<unoidl::ExceptionTypeEntity *>(entA.get()));
363 rtl::Reference<unoidl::ExceptionTypeEntity> ent2B(
364 static_cast<unoidl::ExceptionTypeEntity *>(entB.get()));
365 if (ent2A->getDirectBase() != ent2B->getDirectBase()) {
366 std::cerr
367 << "exception type " << name
368 << " direct base changed from "
369 << (ent2A->getDirectBase().isEmpty()
370 ? OUString("none") : ent2A->getDirectBase())
371 << " to "
372 << (ent2B->getDirectBase().isEmpty()
373 ? OUString("none") : ent2B->getDirectBase())
374 << std::endl;
375 std::exit(EXIT_FAILURE);
377 if (ent2A->getDirectMembers().size()
378 != ent2B->getDirectMembers().size())
380 std::cerr
381 << "exception type " << name
382 << " number of direct members changed from "
383 << ent2A->getDirectMembers().size() << " to "
384 << ent2B->getDirectMembers().size() << std::endl;
385 std::exit(EXIT_FAILURE);
387 for (auto
388 i(ent2A->getDirectMembers().begin()),
389 j(ent2B->getDirectMembers().begin());
390 i != ent2A->getDirectMembers().end(); ++i, ++j)
392 if (i->name != j->name || i->type != j->type) {
393 std::cerr
394 << "exception type " << name
395 << " direct member #"
396 << i - ent2A->getDirectMembers().begin() + 1
397 << " changed from " << i->type << " " << i->name
398 << " to " << j->type << " " << j->name
399 << std::endl;
400 std::exit(EXIT_FAILURE);
403 break;
405 case unoidl::Entity::SORT_INTERFACE_TYPE:
407 rtl::Reference<unoidl::InterfaceTypeEntity> ent2A(
408 static_cast<unoidl::InterfaceTypeEntity *>(entA.get()));
409 rtl::Reference<unoidl::InterfaceTypeEntity> ent2B(
410 static_cast<unoidl::InterfaceTypeEntity *>(entB.get()));
411 if (ent2A->getDirectMandatoryBases().size()
412 != ent2B->getDirectMandatoryBases().size())
414 std::cerr
415 << "interface type " << name
416 << " number of direct mandatory bases changed from "
417 << ent2A->getDirectMandatoryBases().size() << " to "
418 << ent2B->getDirectMandatoryBases().size()
419 << std::endl;
420 std::exit(EXIT_FAILURE);
422 for (auto
423 i(ent2A->getDirectMandatoryBases().begin()),
424 j(ent2B->getDirectMandatoryBases().begin());
425 i != ent2A->getDirectMandatoryBases().end(); ++i, ++j)
427 if (i->name != j->name) {
428 std::cerr
429 << "interface type " << name
430 << " direct mandatory base #"
431 << (i - ent2A->getDirectMandatoryBases().begin()
432 + 1)
433 << " changed from " << i->name << " to "
434 << j->name << std::endl;
435 std::exit(EXIT_FAILURE);
438 if (ent2A->getDirectOptionalBases().size()
439 != ent2B->getDirectOptionalBases().size())
441 std::cerr
442 << "interface type " << name
443 << " number of direct optional bases changed from "
444 << ent2A->getDirectOptionalBases().size() << " to "
445 << ent2B->getDirectOptionalBases().size()
446 << std::endl;
447 std::exit(EXIT_FAILURE);
449 for (auto
450 i(ent2A->getDirectOptionalBases().begin()),
451 j(ent2B->getDirectOptionalBases().begin());
452 i != ent2A->getDirectOptionalBases().end(); ++i, ++j)
454 if (i->name != j->name) {
455 std::cerr
456 << "interface type " << name
457 << " direct optional base #"
458 << (i - ent2A->getDirectOptionalBases().begin()
459 + 1)
460 << " changed from " << i->name << " to "
461 << j->name << std::endl;
462 std::exit(EXIT_FAILURE);
465 if (ent2A->getDirectAttributes().size()
466 != ent2B->getDirectAttributes().size())
468 std::cerr
469 << "interface type " << name
470 << " number of direct attributes changed from "
471 << ent2A->getDirectAttributes().size() << " to "
472 << ent2B->getDirectAttributes().size() << std::endl;
473 std::exit(EXIT_FAILURE);
475 for (auto
476 i(ent2A->getDirectAttributes().begin()),
477 j(ent2B->getDirectAttributes().begin());
478 i != ent2A->getDirectAttributes().end(); ++i, ++j)
480 if (i->name != j->name || i->type != j->type
481 || i->bound != j->bound
482 || i->readOnly != j->readOnly
483 || i->getExceptions != j->getExceptions
484 || i->setExceptions != j->setExceptions)
486 std::cerr
487 << "interface type " << name
488 << " direct attribute #"
489 << i - ent2A->getDirectAttributes().begin() + 1
490 << " changed from "
491 << (i->bound ? OUString("bound ") : OUString())
492 << (i->readOnly
493 ? OUString("read-only ") : OUString())
494 << i->type << " " << i->name //TODO: exceptions
495 << " to "
496 << (j->bound ? OUString("bound ") : OUString())
497 << (j->readOnly
498 ? OUString("read-only ") : OUString())
499 << j->type << " " << j->name //TODO: exceptions
500 << std::endl;
501 std::exit(EXIT_FAILURE);
504 if (ent2A->getDirectMethods().size()
505 != ent2B->getDirectMethods().size())
507 std::cerr
508 << "interface type " << name
509 << " number of direct methods changed from "
510 << ent2A->getDirectMethods().size() << " to "
511 << ent2B->getDirectMethods().size() << std::endl;
512 std::exit(EXIT_FAILURE);
514 for (auto
515 i(ent2A->getDirectMethods().begin()),
516 j(ent2B->getDirectMethods().begin());
517 i != ent2A->getDirectMethods().end(); ++i, ++j)
519 if (i->name != j->name || i->returnType != j->returnType
520 || i->exceptions != j->exceptions)
522 std::cerr
523 << "interface type " << name
524 << " direct method #"
525 << i - ent2A->getDirectMethods().begin() + 1
526 << " changed from "
527 << i->returnType << " " << i->name //TODO: exceptions
528 << " to " << j->returnType << " " << j->name //TODO: exceptions
529 << std::endl;
530 std::exit(EXIT_FAILURE);
532 if (i->parameters.size() != j->parameters.size()) {
533 std::cerr
534 << "interface type " << name
535 << " direct method " << i->name
536 << " number of parameters changed from "
537 << i->parameters.size() << " to "
538 << j->parameters.size() << std::endl;
539 std::exit(EXIT_FAILURE);
541 for (auto
542 k(i->parameters.begin()),
543 l(j->parameters.begin());
544 k != i->parameters.end(); ++k, ++l)
546 if (k->type != l->type || k->direction != l->direction)
548 std::cerr
549 << "interface type " << name
550 << " direct method " << i->name
551 << " parameter #"
552 << k - i->parameters.begin() + 1
553 << " changed from "
554 << showDirection(k->direction) << " "
555 << k->type << " to "
556 << showDirection(l->direction) << " "
557 << l->type << std::endl;
558 std::exit(EXIT_FAILURE);
560 if (k->name != l->name) {
561 std::cerr
562 << "interface type " << name
563 << " direct method " << i->name
564 << " parameter #"
565 << k - i->parameters.begin() + 1
566 << " changed name from " << k->name
567 << " to " << l->name << std::endl;
568 std::exit(EXIT_FAILURE);
572 break;
574 case unoidl::Entity::SORT_TYPEDEF:
576 rtl::Reference<unoidl::TypedefEntity> ent2A(
577 static_cast<unoidl::TypedefEntity *>(entA.get()));
578 rtl::Reference<unoidl::TypedefEntity> ent2B(
579 static_cast<unoidl::TypedefEntity *>(entB.get()));
580 if (ent2A->getType() != ent2B->getType()) {
581 std::cerr
582 << "typedef " << name << " type changed from "
583 << ent2A->getType() << " to " << ent2B->getType()
584 << std::endl;
585 std::exit(EXIT_FAILURE);
587 break;
589 case unoidl::Entity::SORT_CONSTANT_GROUP:
591 rtl::Reference<unoidl::ConstantGroupEntity> ent2A(
592 static_cast<unoidl::ConstantGroupEntity *>(entA.get()));
593 rtl::Reference<unoidl::ConstantGroupEntity> ent2B(
594 static_cast<unoidl::ConstantGroupEntity *>(entB.get()));
595 for (auto & i: ent2A->getMembers()) {
596 bool found = false;
597 for (auto & j: ent2B->getMembers()) {
598 if (i.name == j.name) {
599 if (i.value != j.value) {
600 std::cerr
601 << "constant group " << name
602 << " member " << i.name
603 << " changed value" << std::endl;
604 std::exit(EXIT_FAILURE);
606 found = true;
607 break;
610 if (!found) {
611 std::cerr
612 << "A constant group " << name << " member "
613 << i.name << " is not present in B"
614 << std::endl;
615 std::exit(EXIT_FAILURE);
618 break;
620 case unoidl::Entity::SORT_SINGLE_INTERFACE_BASED_SERVICE:
622 rtl::Reference<unoidl::SingleInterfaceBasedServiceEntity>
623 ent2A(
624 static_cast<unoidl::SingleInterfaceBasedServiceEntity *>(
625 entA.get()));
626 rtl::Reference<unoidl::SingleInterfaceBasedServiceEntity>
627 ent2B(
628 static_cast<unoidl::SingleInterfaceBasedServiceEntity *>(
629 entB.get()));
630 if (ent2A->getBase() != ent2B->getBase()) {
631 std::cerr
632 << "single-interface--based service " << name
633 << " base changed from " << ent2A->getBase()
634 << " to " << ent2B->getBase()
635 << std::endl;
636 std::exit(EXIT_FAILURE);
638 if (ent2A->getConstructors().size()
639 != ent2B->getConstructors().size())
641 std::cerr
642 << "single-interface--based service " << name
643 << " number of constructors changed from "
644 << ent2A->getConstructors().size() << " to "
645 << ent2B->getConstructors().size() << std::endl;
646 std::exit(EXIT_FAILURE);
648 for (auto
649 i(ent2A->getConstructors().begin()),
650 j(ent2B->getConstructors().begin());
651 i != ent2A->getConstructors().end(); ++i, ++j)
653 if (i->name != j->name || i->parameters != j->parameters
654 || i->exceptions != j->exceptions
655 || i->defaultConstructor != j->defaultConstructor)
657 std::cerr
658 << "single-interface--based service " << name
659 << " constructor #"
660 << i - ent2A->getConstructors().begin() + 1
661 << " changed from "
662 << (i->defaultConstructor
663 ? OUString("default ") : i->name) //TODO: parameters, exceptions
664 << " to "
665 << (j->defaultConstructor
666 ? OUString("default ") : j->name) //TODO: parameters, exceptions
667 << std::endl;
668 std::exit(EXIT_FAILURE);
671 break;
673 case unoidl::Entity::SORT_ACCUMULATION_BASED_SERVICE:
675 rtl::Reference<unoidl::AccumulationBasedServiceEntity>
676 ent2A(
677 static_cast<unoidl::AccumulationBasedServiceEntity *>(
678 entA.get()));
679 rtl::Reference<unoidl::AccumulationBasedServiceEntity>
680 ent2B(
681 static_cast<unoidl::AccumulationBasedServiceEntity *>(
682 entB.get()));
683 if (ent2A->getDirectMandatoryBaseServices().size()
684 != ent2B->getDirectMandatoryBaseServices().size())
686 std::cerr
687 << "accumulation-based service " << name
688 << (" number of direct mandatory base services"
689 " changed from ")
690 << ent2A->getDirectMandatoryBaseServices().size()
691 << " to "
692 << ent2B->getDirectMandatoryBaseServices().size()
693 << std::endl;
694 std::exit(EXIT_FAILURE);
696 for (auto
697 i(ent2A->getDirectMandatoryBaseServices().begin()),
698 j(ent2B->getDirectMandatoryBaseServices().begin());
699 i != ent2A->getDirectMandatoryBaseServices().end();
700 ++i, ++j)
702 if (i->name != j->name) {
703 std::cerr
704 << "accumulation-based service " << name
705 << " direct mandatory base service #"
706 << (i
707 - (ent2A->getDirectMandatoryBaseServices()
708 .begin())
709 + 1)
710 << " changed from " << i->name << " to "
711 << j->name << std::endl;
712 std::exit(EXIT_FAILURE);
715 if (ent2A->getDirectOptionalBaseServices().size()
716 > ent2B->getDirectOptionalBaseServices().size())
718 std::cerr
719 << "accumulation-based service " << name
720 << (" number of direct optional base services"
721 " shrank from ")
722 << ent2A->getDirectOptionalBaseServices().size()
723 << " to "
724 << ent2B->getDirectOptionalBaseServices().size()
725 << std::endl;
726 std::exit(EXIT_FAILURE);
728 for (auto & i: ent2A->getDirectOptionalBaseServices()) {
729 if (std::none_of(
730 ent2B->getDirectOptionalBaseServices().begin(),
731 ent2B->getDirectOptionalBaseServices().end(),
732 EqualsAnnotation(i.name)))
734 std::cerr
735 << "accumulation-based service " << name
736 << " direct optional base service " << i.name
737 << " was removed" << std::endl;
738 std::exit(EXIT_FAILURE);
741 if (ent2A->getDirectMandatoryBaseInterfaces().size()
742 != ent2B->getDirectMandatoryBaseInterfaces().size())
744 std::cerr
745 << "accumulation-based service " << name
746 << (" number of direct mandatory base interfaces"
747 " changed from ")
748 << ent2A->getDirectMandatoryBaseInterfaces().size()
749 << " to "
750 << ent2B->getDirectMandatoryBaseInterfaces().size()
751 << std::endl;
752 std::exit(EXIT_FAILURE);
754 for (auto
755 i(ent2A->getDirectMandatoryBaseInterfaces()
756 .begin()),
757 j(ent2B->getDirectMandatoryBaseInterfaces()
758 .begin());
759 i != ent2A->getDirectMandatoryBaseInterfaces().end();
760 ++i, ++j)
762 if (i->name != j->name) {
763 std::cerr
764 << "accumulation-based service " << name
765 << " direct mandatory base interface #"
766 << (i
767 - (ent2A->getDirectMandatoryBaseInterfaces()
768 .begin())
769 + 1)
770 << " changed from " << i->name << " to "
771 << j->name << std::endl;
772 std::exit(EXIT_FAILURE);
775 if (ent2A->getDirectOptionalBaseInterfaces().size()
776 > ent2B->getDirectOptionalBaseInterfaces().size())
778 std::cerr
779 << "accumulation-based service " << name
780 << (" number of direct optional base interfaces"
781 " shrank from ")
782 << ent2A->getDirectOptionalBaseInterfaces().size()
783 << " to "
784 << ent2B->getDirectOptionalBaseInterfaces().size()
785 << std::endl;
786 std::exit(EXIT_FAILURE);
788 for (auto & i: ent2A->getDirectOptionalBaseInterfaces()) {
789 if (std::none_of(
790 (ent2B->getDirectOptionalBaseInterfaces()
791 .begin()),
792 ent2B->getDirectOptionalBaseInterfaces().end(),
793 EqualsAnnotation(i.name)))
795 std::cerr
796 << "accumulation-based service " << name
797 << " direct optional base interface " << i.name
798 << " was removed" << std::endl;
799 std::exit(EXIT_FAILURE);
802 if (ent2A->getDirectProperties().size()
803 > ent2B->getDirectProperties().size())
805 std::cerr
806 << "accumulation-based service " << name
807 << " number of direct properties changed from "
808 << ent2A->getDirectProperties().size() << " to "
809 << ent2B->getDirectProperties().size() << std::endl;
810 std::exit(EXIT_FAILURE);
812 for (auto
813 i(ent2A->getDirectProperties().begin()),
814 j(ent2B->getDirectProperties().begin());
815 i != ent2A->getDirectProperties().end(); ++i, ++j)
817 if (i->name != j->name || i->type != j->type
818 || i->attributes != j->attributes)
820 std::cerr
821 << "accumulation-based service " << name
822 << " direct property #"
823 << i - ent2A->getDirectProperties().begin() + 1
824 << " changed from "
825 << i->type << " " << i->name //TODO: attributes
826 << " to "
827 << j->type << " " << j->name //TODO: attributes
828 << std::endl;
829 std::exit(EXIT_FAILURE);
832 for (auto
833 i(ent2B->getDirectProperties().begin()
834 + ent2A->getDirectProperties().size());
835 i != ent2B->getDirectProperties().end(); ++i)
837 if ((i->attributes & unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_OPTIONAL) == 0)
839 std::cerr
840 << "B accumulation-based service " << name
841 << " additional direct property " << i->name
842 << " is not optional" << std::endl;
843 std::exit(EXIT_FAILURE);
846 break;
848 case unoidl::Entity::SORT_INTERFACE_BASED_SINGLETON:
850 rtl::Reference<unoidl::InterfaceBasedSingletonEntity> ent2A(
851 static_cast<unoidl::InterfaceBasedSingletonEntity *>(
852 entA.get()));
853 rtl::Reference<unoidl::InterfaceBasedSingletonEntity> ent2B(
854 static_cast<unoidl::InterfaceBasedSingletonEntity *>(
855 entB.get()));
856 if (ent2A->getBase() != ent2B->getBase()) {
857 std::cerr
858 << "interface-based singleton " << name
859 << " base changed from " << ent2A->getBase()
860 << " to " << ent2B->getBase() << std::endl;
861 std::exit(EXIT_FAILURE);
863 break;
865 case unoidl::Entity::SORT_SERVICE_BASED_SINGLETON:
867 rtl::Reference<unoidl::ServiceBasedSingletonEntity> ent2A(
868 static_cast<unoidl::ServiceBasedSingletonEntity *>(
869 entA.get()));
870 rtl::Reference<unoidl::ServiceBasedSingletonEntity> ent2B(
871 static_cast<unoidl::ServiceBasedSingletonEntity *>(
872 entB.get()));
873 if (ent2A->getBase() != ent2B->getBase()) {
874 std::cerr
875 << "service-based singleton " << name
876 << " base changed from " << ent2A->getBase()
877 << " to " << ent2B->getBase() << std::endl;
878 std::exit(EXIT_FAILURE);
880 break;
882 case unoidl::Entity::SORT_MODULE:
883 assert(false && "this cannot happen");
889 bool valid(OUString const & identifier) {
890 for (sal_Int32 i = 0;; ++i) {
891 i = identifier.indexOf('_', i);
892 if (i == -1) {
893 return true;
895 if (!rtl::isAsciiUpperCase(identifier[0]) || identifier[i - 1] == '_') {
896 return false;
901 void checkIds(
902 rtl::Reference<unoidl::Provider> const & providerA, std::u16string_view prefix,
903 rtl::Reference<unoidl::MapCursor> const & cursor)
905 assert(cursor.is());
906 for (;;) {
907 OUString id;
908 rtl::Reference<unoidl::Entity> entB(cursor->getNext(&id));
909 if (!entB.is()) {
910 break;
912 OUString name(prefix + id);
913 rtl::Reference<unoidl::Entity> entA(providerA->findEntity(name));
914 if (!(entA.is() || valid(id))) {
915 std::cerr
916 << "entity name " << name << " uses an invalid identifier"
917 << std::endl;
918 std::exit(EXIT_FAILURE);
920 switch (entB->getSort()) {
921 case unoidl::Entity::SORT_MODULE:
922 checkIds(
923 providerA, OUString(name + "."),
924 (static_cast<unoidl::ModuleEntity *>(entB.get())
925 ->createCursor()));
926 break;
927 case unoidl::Entity::SORT_ENUM_TYPE:
928 if (!entA.is()) {
929 rtl::Reference<unoidl::EnumTypeEntity> ent2B(
930 static_cast<unoidl::EnumTypeEntity *>(entB.get()));
931 for (auto & i: ent2B->getMembers()) {
932 if (!valid(i.name)) {
933 std::cerr
934 << "enum type " << name << " member " << i.name
935 << " uses an invalid identifier" << std::endl;
936 std::exit(EXIT_FAILURE);
940 break;
941 case unoidl::Entity::SORT_PLAIN_STRUCT_TYPE:
942 if (!entA.is()) {
943 rtl::Reference<unoidl::PlainStructTypeEntity> ent2B(
944 static_cast<unoidl::PlainStructTypeEntity *>(
945 entB.get()));
946 for (auto & i: ent2B->getDirectMembers()) {
947 if (!valid(i.name)) {
948 std::cerr
949 << "plain struct type " << name << " direct member "
950 << i.name << " uses an invalid identifier"
951 << std::endl;
952 std::exit(EXIT_FAILURE);
956 break;
957 case unoidl::Entity::SORT_POLYMORPHIC_STRUCT_TYPE_TEMPLATE:
958 if (!entA.is()) {
959 rtl::Reference<unoidl::PolymorphicStructTypeTemplateEntity>
960 ent2B(
961 static_cast<
962 unoidl::PolymorphicStructTypeTemplateEntity *>(
963 entB.get()));
964 for (auto & i: ent2B->getTypeParameters()) {
965 if (!valid(i)) {
966 std::cerr
967 << "polymorphic struct type template " << name
968 << " type parameter " << i
969 << " uses an invalid identifier" << std::endl;
970 std::exit(EXIT_FAILURE);
973 for (auto & i: ent2B->getMembers()) {
974 if (!valid(i.name)) {
975 std::cerr
976 << "polymorphic struct type template " << name
977 << " member " << i.name
978 << " uses an invalid identifier" << std::endl;
979 std::exit(EXIT_FAILURE);
983 break;
984 case unoidl::Entity::SORT_EXCEPTION_TYPE:
985 if (!entA.is()) {
986 rtl::Reference<unoidl::ExceptionTypeEntity> ent2B(
987 static_cast<unoidl::ExceptionTypeEntity *>(entB.get()));
988 for (auto & i: ent2B->getDirectMembers()) {
989 if (!valid(i.name)) {
990 std::cerr
991 << "exception type " << name << " direct member "
992 << i.name << " uses an invalid identifier"
993 << std::endl;
994 std::exit(EXIT_FAILURE);
998 break;
999 case unoidl::Entity::SORT_INTERFACE_TYPE:
1000 if (!entA.is()) {
1001 rtl::Reference<unoidl::InterfaceTypeEntity> ent2B(
1002 static_cast<unoidl::InterfaceTypeEntity *>(entB.get()));
1003 for (auto & i: ent2B->getDirectAttributes()) {
1004 if (!valid(i.name)) {
1005 std::cerr
1006 << "interface type " << name << " direct attribute "
1007 << i.name << " uses an invalid identifier"
1008 << std::endl;
1009 std::exit(EXIT_FAILURE);
1012 for (auto & i: ent2B->getDirectMethods()) {
1013 if (!valid(i.name)) {
1014 std::cerr
1015 << "interface type " << name << " direct method "
1016 << i.name << " uses an invalid identifier"
1017 << std::endl;
1018 std::exit(EXIT_FAILURE);
1020 for (auto & j: i.parameters) {
1021 if (!valid(j.name)) {
1022 std::cerr
1023 << "interface type " << name
1024 << " direct method " << i.name << " parameter "
1025 << j.name << " uses an invalid identifier"
1026 << std::endl;
1027 std::exit(EXIT_FAILURE);
1032 break;
1033 case unoidl::Entity::SORT_TYPEDEF:
1034 case unoidl::Entity::SORT_INTERFACE_BASED_SINGLETON:
1035 case unoidl::Entity::SORT_SERVICE_BASED_SINGLETON:
1036 break;
1037 case unoidl::Entity::SORT_CONSTANT_GROUP:
1039 rtl::Reference<unoidl::ConstantGroupEntity> ent2B(
1040 static_cast<unoidl::ConstantGroupEntity *>(entB.get()));
1041 for (auto & i: ent2B->getMembers()) {
1042 bool found = false;
1043 if (entA.is()) {
1044 rtl::Reference<unoidl::ConstantGroupEntity> ent2A(
1045 static_cast<unoidl::ConstantGroupEntity *>(
1046 entA.get()));
1047 for (auto & j: ent2A->getMembers()) {
1048 if (i.name == j.name) {
1049 found = true;
1050 break;
1054 if (!(found || valid(i.name))) {
1055 std::cerr
1056 << "Constant group " << name << " member "
1057 << i.name << " uses an invalid identifier"
1058 << std::endl;
1059 std::exit(EXIT_FAILURE);
1062 break;
1064 case unoidl::Entity::SORT_SINGLE_INTERFACE_BASED_SERVICE:
1065 if (!entA.is()) {
1066 rtl::Reference<unoidl::SingleInterfaceBasedServiceEntity>
1067 ent2B(
1068 static_cast<unoidl::SingleInterfaceBasedServiceEntity *>(
1069 entB.get()));
1070 for (auto & i: ent2B->getConstructors()) {
1071 if (!valid(i.name)) {
1072 std::cerr
1073 << "single-interface--based service " << name
1074 << " constructor " << i.name
1075 << " uses an invalid identifier" << std::endl;
1076 std::exit(EXIT_FAILURE);
1078 for (auto & j: i.parameters) {
1079 if (!valid(j.name)) {
1080 std::cerr
1081 << "single-interface--based service " << name
1082 << " constructor " << i.name << " parameter "
1083 << j.name << " uses an invalid identifier"
1084 << std::endl;
1085 std::exit(EXIT_FAILURE);
1090 break;
1091 case unoidl::Entity::SORT_ACCUMULATION_BASED_SERVICE:
1093 rtl::Reference<unoidl::AccumulationBasedServiceEntity> ent2B(
1094 static_cast<unoidl::AccumulationBasedServiceEntity *>(
1095 entB.get()));
1096 std::vector<unoidl::AccumulationBasedServiceEntity::Property>::size_type
1097 n(entA.is()
1098 ? (static_cast<unoidl::AccumulationBasedServiceEntity *>(
1099 entA.get())
1100 ->getDirectProperties().size())
1101 : 0);
1102 assert(n <= ent2B->getDirectProperties().size());
1103 for (auto i(ent2B->getDirectProperties().begin() +n);
1104 i != ent2B->getDirectProperties().end(); ++i)
1106 if (!valid(i->name)) {
1107 std::cerr
1108 << "accumulation-based service " << name
1109 << " direct property " << i->name
1110 << " uses an invalid identifier" << std::endl;
1111 std::exit(EXIT_FAILURE);
1114 break;
1122 SAL_IMPLEMENT_MAIN() {
1123 try {
1124 sal_uInt32 args = rtl_getAppCommandArgCount();
1125 rtl::Reference<unoidl::Manager> mgr[2];
1126 mgr[0] = new unoidl::Manager;
1127 mgr[1] = new unoidl::Manager;
1128 rtl::Reference<unoidl::Provider> prov[2];
1129 int side = 0;
1130 bool ignoreUnpublished = false;
1131 for (sal_uInt32 i = 0; i != args; ++i) {
1132 bool delimiter = false;
1133 OUString uri;
1134 if (getArgument(
1135 i, &ignoreUnpublished, side == 0 ? &delimiter : nullptr,
1136 &uri))
1138 try {
1139 prov[side] = mgr[side]->addProvider(uri);
1140 } catch (unoidl::NoSuchFileException &) {
1141 std::cerr
1142 << "Input <" << uri << "> does not exist" << std::endl;
1143 std::exit(EXIT_FAILURE);
1145 } else if (delimiter) {
1146 side = 1;
1149 if (side == 0 || !(prov[0].is() && prov[1].is())) {
1150 badUsage();
1152 checkMap(prov[1], u"", prov[0]->createRootCursor(), ignoreUnpublished);
1153 checkIds(prov[0], u"", prov[1]->createRootCursor());
1154 return EXIT_SUCCESS;
1155 } catch (unoidl::FileFormatException & e1) {
1156 std::cerr
1157 << "Bad input <" << e1.getUri() << ">: " << e1.getDetail()
1158 << std::endl;
1159 std::exit(EXIT_FAILURE);
1160 } catch (std::exception & e1) {
1161 std::cerr << "Failure: " << e1.what() << std::endl;
1162 std::exit(EXIT_FAILURE);
1166 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */