bump product version to 6.4.0.3
[LibreOffice.git] / unoidl / source / unoidl-check.cxx
blobff42573f7d1b1baf8e9477efab8b74e60c973402
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 <vector>
18 #include <osl/file.hxx>
19 #include <osl/process.h>
20 #include <rtl/character.hxx>
21 #include <rtl/process.h>
22 #include <rtl/ref.hxx>
23 #include <rtl/ustring.hxx>
24 #include <sal/main.h>
25 #include <sal/types.h>
26 #include <unoidl/unoidl.hxx>
28 namespace unoidl {
30 static bool operator ==(ConstantValue const & lhs, ConstantValue const & rhs) {
31 if (lhs.type == rhs.type) {
32 switch (lhs.type) {
33 case ConstantValue::TYPE_BOOLEAN:
34 return lhs.booleanValue == rhs.booleanValue;
35 case ConstantValue::TYPE_BYTE:
36 return lhs.byteValue == rhs.byteValue;
37 case ConstantValue::TYPE_SHORT:
38 return lhs.shortValue == rhs.shortValue;
39 case ConstantValue::TYPE_UNSIGNED_SHORT:
40 return lhs.unsignedShortValue == rhs.unsignedShortValue;
41 case ConstantValue::TYPE_LONG:
42 return lhs.longValue == rhs.longValue;
43 case ConstantValue::TYPE_UNSIGNED_LONG:
44 return lhs.unsignedLongValue == rhs.unsignedLongValue;
45 case ConstantValue::TYPE_HYPER:
46 return lhs.hyperValue == rhs.hyperValue;
47 case ConstantValue::TYPE_UNSIGNED_HYPER:
48 return lhs.unsignedHyperValue == rhs.unsignedHyperValue;
49 case ConstantValue::TYPE_FLOAT:
50 return lhs.floatValue == rhs.floatValue;
51 case ConstantValue::TYPE_DOUBLE:
52 return lhs.doubleValue == rhs.doubleValue;
55 return false;
58 static bool operator !=(ConstantValue const & lhs, ConstantValue const & rhs) {
59 return !(lhs == rhs);
62 static bool operator ==(
63 SingleInterfaceBasedServiceEntity::Constructor::Parameter const & lhs,
64 SingleInterfaceBasedServiceEntity::Constructor::Parameter const & rhs)
66 return lhs.name == rhs.name && lhs.type == rhs.type && lhs.rest == rhs.rest;
71 namespace {
73 void badUsage() {
74 std::cerr
75 << "Usage:" << std::endl << std::endl
76 << (" unoidl-check [--ignore-unpublished] [<extra registries A>]"
77 " <registry A> --")
78 << std::endl << " [<extra registries B>] <registry B>" << std::endl
79 << std::endl
80 << ("where each <registry> is either a new- or legacy-format .rdb file,"
81 " a single .idl")
82 << std::endl
83 << ("file, or a root directory of an .idl file tree. Check that each"
84 " entity from")
85 << std::endl
86 << "<registry A> is also present in <registry B> in a compatible form."
87 << std::endl;
88 std::exit(EXIT_FAILURE);
91 bool getArgument(
92 sal_uInt32 argument, bool * ignoreUnpublished, bool * delimiter,
93 OUString * uri)
95 assert(ignoreUnpublished != nullptr);
96 assert(uri != nullptr);
97 OUString arg;
98 rtl_getAppCommandArg(argument, &arg.pData);
99 if (argument == 0 && arg == "--ignore-unpublished") {
100 *ignoreUnpublished = true;
101 return false;
103 if (arg == "--") {
104 if (delimiter == nullptr) {
105 badUsage();
107 *delimiter = true;
108 return false;
110 OUString url;
111 osl::FileBase::RC e1 = osl::FileBase::getFileURLFromSystemPath(arg, url);
112 if (e1 != osl::FileBase::E_None) {
113 std::cerr
114 << "Cannot convert \"" << arg << "\" to file URL, error code "
115 << +e1 << std::endl;
116 std::exit(EXIT_FAILURE);
118 OUString cwd;
119 oslProcessError e2 = osl_getProcessWorkingDir(&cwd.pData);
120 if (e2 != osl_Process_E_None) {
121 std::cerr
122 << "Cannot obtain working directory, error code " << +e2
123 << std::endl;
124 std::exit(EXIT_FAILURE);
126 e1 = osl::FileBase::getAbsoluteFileURL(cwd, url, *uri);
127 if (e1 != osl::FileBase::E_None) {
128 std::cerr
129 << "Cannot make \"" << url
130 << "\" into an absolute file URL, error code " << +e1 << std::endl;
131 std::exit(EXIT_FAILURE);
133 return true;
136 OUString showDirection(
137 unoidl::InterfaceTypeEntity::Method::Parameter::Direction direction)
139 switch (direction) {
140 case unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN:
141 return "[in]";
142 case unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_OUT:
143 return "[out]";
144 case unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN_OUT:
145 return "[inout]";
146 default:
147 assert(false && "this cannot happen"); for (;;) { std::abort(); }
151 struct EqualsAnnotation {
152 explicit EqualsAnnotation(OUString const & name): name_(name) {}
154 bool operator ()(unoidl::AnnotatedReference const & ref)
155 { return ref.name == name_; }
157 private:
158 OUString const name_;
161 void checkMap(
162 rtl::Reference<unoidl::Provider> const & providerB, OUString const & prefix,
163 rtl::Reference<unoidl::MapCursor> const & cursor, bool ignoreUnpublished)
165 assert(providerB.is());
166 assert(cursor.is());
167 for (;;) {
168 OUString id;
169 rtl::Reference<unoidl::Entity> entA(cursor->getNext(&id));
170 if (!entA.is()) {
171 break;
173 OUString name(prefix + id);
174 if (entA->getSort() == unoidl::Entity::SORT_MODULE) {
175 checkMap(
176 providerB, name + ".",
177 (static_cast<unoidl::ModuleEntity *>(entA.get())
178 ->createCursor()),
179 ignoreUnpublished);
180 } else {
181 bool pubA = dynamic_cast<unoidl::PublishableEntity&>(*entA).isPublished();
182 if (!pubA && ignoreUnpublished) {
183 continue;
185 rtl::Reference<unoidl::Entity> entB(providerB->findEntity(name));
186 if (!entB.is()) {
187 std::cerr
188 << "A entity " << name << " is not present in B"
189 << std::endl;
190 std::exit(EXIT_FAILURE);
192 if (entA->getSort() != entB->getSort()) {
193 std::cerr
194 << "A entity " << name << " is of different sort in B"
195 << std::endl;
196 std::exit(EXIT_FAILURE);
198 if (pubA && (!dynamic_cast<unoidl::PublishableEntity&>(*entB).isPublished()))
200 std::cerr
201 << "A published entity " << name << " is not published in B"
202 << std::endl;
203 std::exit(EXIT_FAILURE);
205 switch (entA->getSort()) {
206 case unoidl::Entity::SORT_ENUM_TYPE:
208 rtl::Reference<unoidl::EnumTypeEntity> ent2A(
209 static_cast<unoidl::EnumTypeEntity *>(entA.get()));
210 rtl::Reference<unoidl::EnumTypeEntity> ent2B(
211 static_cast<unoidl::EnumTypeEntity *>(entB.get()));
212 if (ent2A->getMembers().size()
213 != ent2B->getMembers().size())
215 std::cerr
216 << "enum type " << name
217 << " number of members changed from "
218 << ent2A->getMembers().size() << " to "
219 << ent2B->getMembers().size() << std::endl;
220 std::exit(EXIT_FAILURE);
222 for (auto
223 i(ent2A->getMembers().begin()),
224 j(ent2B->getMembers().begin());
225 i != ent2A->getMembers().end(); ++i, ++j)
227 if (i->name != j->name || i->value != j->value) {
228 std::cerr
229 << "enum type " << name << " member #"
230 << i - ent2A->getMembers().begin() + 1
231 << " changed from " << i->name << " = "
232 << i->value << " to " << j->name << " = "
233 << j->value << std::endl;
234 std::exit(EXIT_FAILURE);
237 break;
239 case unoidl::Entity::SORT_PLAIN_STRUCT_TYPE:
241 rtl::Reference<unoidl::PlainStructTypeEntity> ent2A(
242 static_cast<unoidl::PlainStructTypeEntity *>(
243 entA.get()));
244 rtl::Reference<unoidl::PlainStructTypeEntity> ent2B(
245 static_cast<unoidl::PlainStructTypeEntity *>(
246 entB.get()));
247 if (ent2A->getDirectBase() != ent2B->getDirectBase()) {
248 std::cerr
249 << "plain struct type " << name
250 << " direct base changed from "
251 << (ent2A->getDirectBase().isEmpty()
252 ? OUString("none") : ent2A->getDirectBase())
253 << " to "
254 << (ent2B->getDirectBase().isEmpty()
255 ? OUString("none") : ent2B->getDirectBase())
256 << std::endl;
257 std::exit(EXIT_FAILURE);
259 if (ent2A->getDirectMembers().size()
260 != ent2B->getDirectMembers().size())
262 std::cerr
263 << "plain struct type " << name
264 << " number of direct members changed from "
265 << ent2A->getDirectMembers().size() << " to "
266 << ent2B->getDirectMembers().size() << std::endl;
267 std::exit(EXIT_FAILURE);
269 for (auto
270 i(ent2A->getDirectMembers().begin()),
271 j(ent2B->getDirectMembers().begin());
272 i != ent2A->getDirectMembers().end(); ++i, ++j)
274 if (i->name != j->name || i->type != j->type) {
275 std::cerr
276 << "plain struct type " << name
277 << " direct member #"
278 << i - ent2A->getDirectMembers().begin() + 1
279 << " changed from " << i->type << " " << i->name
280 << " to " << j->type << " " << j->name
281 << std::endl;
282 std::exit(EXIT_FAILURE);
285 break;
287 case unoidl::Entity::SORT_POLYMORPHIC_STRUCT_TYPE_TEMPLATE:
289 rtl::Reference<unoidl::PolymorphicStructTypeTemplateEntity>
290 ent2A(
291 static_cast<unoidl::PolymorphicStructTypeTemplateEntity *>(
292 entA.get()));
293 rtl::Reference<unoidl::PolymorphicStructTypeTemplateEntity>
294 ent2B(
295 static_cast<unoidl::PolymorphicStructTypeTemplateEntity *>(
296 entB.get()));
297 if (ent2A->getTypeParameters().size()
298 != ent2B->getTypeParameters().size())
300 std::cerr
301 << "polymorphic struct type template " << name
302 << " number of type parameters changed from "
303 << ent2A->getTypeParameters().size() << " to "
304 << ent2B->getTypeParameters().size() << std::endl;
305 std::exit(EXIT_FAILURE);
307 for (auto
308 i(ent2A->getTypeParameters().begin()),
309 j(ent2B->getTypeParameters().begin());
310 i != ent2A->getTypeParameters().end(); ++i, ++j)
312 if (*i != *j) {
313 std::cerr
314 << "polymorphic struct type template " << name
315 << " type parameter #"
316 << i - ent2A->getTypeParameters().begin() + 1
317 << " changed from " << *i << " to " << *j
318 << std::endl;
319 std::exit(EXIT_FAILURE);
322 if (ent2A->getMembers().size()
323 != ent2B->getMembers().size())
325 std::cerr
326 << "polymorphic struct type template " << name
327 << " number of members changed from "
328 << ent2A->getMembers().size() << " to "
329 << ent2B->getMembers().size() << std::endl;
330 std::exit(EXIT_FAILURE);
332 for (auto
333 i(ent2A->getMembers().begin()),
334 j(ent2B->getMembers().begin());
335 i != ent2A->getMembers().end(); ++i, ++j)
337 if (i->name != j->name || i->type != j->type
338 || i->parameterized != j->parameterized)
340 std::cerr
341 << "polymorphic struct type template " << name
342 << " member #"
343 << i - ent2A->getMembers().begin() + 1
344 << " changed from "
345 << (i->parameterized
346 ? OUString("parameterized ") : OUString())
347 << i->type << " " << i->name
348 << " to "
349 << (j->parameterized
350 ? OUString("parameterized ") : OUString())
351 << j->type << " " << j->name
352 << std::endl;
353 std::exit(EXIT_FAILURE);
356 break;
358 case unoidl::Entity::SORT_EXCEPTION_TYPE:
360 rtl::Reference<unoidl::ExceptionTypeEntity> ent2A(
361 static_cast<unoidl::ExceptionTypeEntity *>(entA.get()));
362 rtl::Reference<unoidl::ExceptionTypeEntity> ent2B(
363 static_cast<unoidl::ExceptionTypeEntity *>(entB.get()));
364 if (ent2A->getDirectBase() != ent2B->getDirectBase()) {
365 std::cerr
366 << "exception type " << name
367 << " direct base changed from "
368 << (ent2A->getDirectBase().isEmpty()
369 ? OUString("none") : ent2A->getDirectBase())
370 << " to "
371 << (ent2B->getDirectBase().isEmpty()
372 ? OUString("none") : ent2B->getDirectBase())
373 << std::endl;
374 std::exit(EXIT_FAILURE);
376 if (ent2A->getDirectMembers().size()
377 != ent2B->getDirectMembers().size())
379 std::cerr
380 << "exception type " << name
381 << " number of direct members changed from "
382 << ent2A->getDirectMembers().size() << " to "
383 << ent2B->getDirectMembers().size() << std::endl;
384 std::exit(EXIT_FAILURE);
386 for (auto
387 i(ent2A->getDirectMembers().begin()),
388 j(ent2B->getDirectMembers().begin());
389 i != ent2A->getDirectMembers().end(); ++i, ++j)
391 if (i->name != j->name || i->type != j->type) {
392 std::cerr
393 << "exception type " << name
394 << " direct member #"
395 << i - ent2A->getDirectMembers().begin() + 1
396 << " changed from " << i->type << " " << i->name
397 << " to " << j->type << " " << j->name
398 << std::endl;
399 std::exit(EXIT_FAILURE);
402 break;
404 case unoidl::Entity::SORT_INTERFACE_TYPE:
406 rtl::Reference<unoidl::InterfaceTypeEntity> ent2A(
407 static_cast<unoidl::InterfaceTypeEntity *>(entA.get()));
408 rtl::Reference<unoidl::InterfaceTypeEntity> ent2B(
409 static_cast<unoidl::InterfaceTypeEntity *>(entB.get()));
410 if (ent2A->getDirectMandatoryBases().size()
411 != ent2B->getDirectMandatoryBases().size())
413 std::cerr
414 << "interface type " << name
415 << " number of direct mandatory bases changed from "
416 << ent2A->getDirectMandatoryBases().size() << " to "
417 << ent2B->getDirectMandatoryBases().size()
418 << std::endl;
419 std::exit(EXIT_FAILURE);
421 for (auto
422 i(ent2A->getDirectMandatoryBases().begin()),
423 j(ent2B->getDirectMandatoryBases().begin());
424 i != ent2A->getDirectMandatoryBases().end(); ++i, ++j)
426 if (i->name != j->name) {
427 std::cerr
428 << "interface type " << name
429 << " direct mandatory base #"
430 << (i - ent2A->getDirectMandatoryBases().begin()
431 + 1)
432 << " changed from " << i->name << " to "
433 << j->name << std::endl;
434 std::exit(EXIT_FAILURE);
437 if (ent2A->getDirectOptionalBases().size()
438 != ent2B->getDirectOptionalBases().size())
440 std::cerr
441 << "interface type " << name
442 << " number of direct optional bases changed from "
443 << ent2A->getDirectOptionalBases().size() << " to "
444 << ent2B->getDirectOptionalBases().size()
445 << std::endl;
446 std::exit(EXIT_FAILURE);
448 for (auto
449 i(ent2A->getDirectOptionalBases().begin()),
450 j(ent2B->getDirectOptionalBases().begin());
451 i != ent2A->getDirectOptionalBases().end(); ++i, ++j)
453 if (i->name != j->name) {
454 std::cerr
455 << "interface type " << name
456 << " direct optional base #"
457 << (i - ent2A->getDirectOptionalBases().begin()
458 + 1)
459 << " changed from " << i->name << " to "
460 << j->name << std::endl;
461 std::exit(EXIT_FAILURE);
464 if (ent2A->getDirectAttributes().size()
465 != ent2B->getDirectAttributes().size())
467 std::cerr
468 << "interface type " << name
469 << " number of direct attributes changed from "
470 << ent2A->getDirectAttributes().size() << " to "
471 << ent2B->getDirectAttributes().size() << std::endl;
472 std::exit(EXIT_FAILURE);
474 for (auto
475 i(ent2A->getDirectAttributes().begin()),
476 j(ent2B->getDirectAttributes().begin());
477 i != ent2A->getDirectAttributes().end(); ++i, ++j)
479 if (i->name != j->name || i->type != j->type
480 || i->bound != j->bound
481 || i->readOnly != j->readOnly
482 || i->getExceptions != j->getExceptions
483 || i->setExceptions != j->setExceptions)
485 std::cerr
486 << "interface type " << name
487 << " direct attribute #"
488 << i - ent2A->getDirectAttributes().begin() + 1
489 << " changed from "
490 << (i->bound ? OUString("bound ") : OUString())
491 << (i->readOnly
492 ? OUString("read-only ") : OUString())
493 << i->type << " " << i->name //TODO: exceptions
494 << " to "
495 << (j->bound ? OUString("bound ") : OUString())
496 << (j->readOnly
497 ? OUString("read-only ") : OUString())
498 << j->type << " " << j->name //TODO: exceptions
499 << std::endl;
500 std::exit(EXIT_FAILURE);
503 if (ent2A->getDirectMethods().size()
504 != ent2B->getDirectMethods().size())
506 std::cerr
507 << "interface type " << name
508 << " number of direct methods changed from "
509 << ent2A->getDirectMethods().size() << " to "
510 << ent2B->getDirectMethods().size() << std::endl;
511 std::exit(EXIT_FAILURE);
513 for (auto
514 i(ent2A->getDirectMethods().begin()),
515 j(ent2B->getDirectMethods().begin());
516 i != ent2A->getDirectMethods().end(); ++i, ++j)
518 if (i->name != j->name || i->returnType != j->returnType
519 || i->exceptions != j->exceptions)
521 std::cerr
522 << "interface type " << name
523 << " direct method #"
524 << i - ent2A->getDirectMethods().begin() + 1
525 << " changed from "
526 << i->returnType << " " << i->name //TODO: exceptions
527 << " to " << j->returnType << " " << j->name //TODO: exceptions
528 << std::endl;
529 std::exit(EXIT_FAILURE);
531 if (i->parameters.size() != j->parameters.size()) {
532 std::cerr
533 << "interface type " << name
534 << " direct method " << i->name
535 << " number of parameters changed from "
536 << i->parameters.size() << " to "
537 << j->parameters.size() << std::endl;
538 std::exit(EXIT_FAILURE);
540 for (auto
541 k(i->parameters.begin()),
542 l(j->parameters.begin());
543 k != i->parameters.end(); ++k, ++l)
545 if (k->type != l->type || k->direction != l->direction)
547 std::cerr
548 << "interface type " << name
549 << " direct method " << i->name
550 << " parameter #"
551 << k - i->parameters.begin() + 1
552 << " changed from "
553 << showDirection(k->direction) << " "
554 << k->type << " to "
555 << showDirection(l->direction) << " "
556 << l->type << std::endl;
557 std::exit(EXIT_FAILURE);
559 if (k->name != l->name) {
560 std::cerr
561 << "interface type " << name
562 << " direct method " << i->name
563 << " parameter #"
564 << k - i->parameters.begin() + 1
565 << " changed name from " << k->name
566 << " to " << l->name << std::endl;
567 std::exit(EXIT_FAILURE);
571 break;
573 case unoidl::Entity::SORT_TYPEDEF:
575 rtl::Reference<unoidl::TypedefEntity> ent2A(
576 static_cast<unoidl::TypedefEntity *>(entA.get()));
577 rtl::Reference<unoidl::TypedefEntity> ent2B(
578 static_cast<unoidl::TypedefEntity *>(entB.get()));
579 if (ent2A->getType() != ent2B->getType()) {
580 std::cerr
581 << "typedef " << name << " type changed from "
582 << ent2A->getType() << " to " << ent2B->getType()
583 << std::endl;
584 std::exit(EXIT_FAILURE);
586 break;
588 case unoidl::Entity::SORT_CONSTANT_GROUP:
590 rtl::Reference<unoidl::ConstantGroupEntity> ent2A(
591 static_cast<unoidl::ConstantGroupEntity *>(entA.get()));
592 rtl::Reference<unoidl::ConstantGroupEntity> ent2B(
593 static_cast<unoidl::ConstantGroupEntity *>(entB.get()));
594 for (auto & i: ent2A->getMembers()) {
595 bool found = false;
596 for (auto & j: ent2B->getMembers()) {
597 if (i.name == j.name) {
598 if (i.value != j.value) {
599 std::cerr
600 << "constant group " << name
601 << " member " << i.name
602 << " changed value" << std::endl;
603 std::exit(EXIT_FAILURE);
605 found = true;
606 break;
609 if (!found) {
610 std::cerr
611 << "A constant group " << name << " member "
612 << i.name << " is not present in B"
613 << std::endl;
614 std::exit(EXIT_FAILURE);
617 break;
619 case unoidl::Entity::SORT_SINGLE_INTERFACE_BASED_SERVICE:
621 rtl::Reference<unoidl::SingleInterfaceBasedServiceEntity>
622 ent2A(
623 static_cast<unoidl::SingleInterfaceBasedServiceEntity *>(
624 entA.get()));
625 rtl::Reference<unoidl::SingleInterfaceBasedServiceEntity>
626 ent2B(
627 static_cast<unoidl::SingleInterfaceBasedServiceEntity *>(
628 entB.get()));
629 if (ent2A->getBase() != ent2B->getBase()) {
630 std::cerr
631 << "single-interface--based service " << name
632 << " base changed from " << ent2A->getBase()
633 << " to " << ent2B->getBase()
634 << std::endl;
635 std::exit(EXIT_FAILURE);
637 if (ent2A->getConstructors().size()
638 != ent2B->getConstructors().size())
640 std::cerr
641 << "single-interface--based service " << name
642 << " number of constructors changed from "
643 << ent2A->getConstructors().size() << " to "
644 << ent2B->getConstructors().size() << std::endl;
645 std::exit(EXIT_FAILURE);
647 for (auto
648 i(ent2A->getConstructors().begin()),
649 j(ent2B->getConstructors().begin());
650 i != ent2A->getConstructors().end(); ++i, ++j)
652 if (i->name != j->name || i->parameters != j->parameters
653 || i->exceptions != j->exceptions
654 || i->defaultConstructor != j->defaultConstructor)
656 std::cerr
657 << "single-interface--based service " << name
658 << " constructor #"
659 << i - ent2A->getConstructors().begin() + 1
660 << " changed from "
661 << (i->defaultConstructor
662 ? OUString("default ") : i->name) //TODO: parameters, exceptions
663 << " to "
664 << (j->defaultConstructor
665 ? OUString("default ") : j->name) //TODO: parameters, exceptions
666 << std::endl;
667 std::exit(EXIT_FAILURE);
670 break;
672 case unoidl::Entity::SORT_ACCUMULATION_BASED_SERVICE:
674 rtl::Reference<unoidl::AccumulationBasedServiceEntity>
675 ent2A(
676 static_cast<unoidl::AccumulationBasedServiceEntity *>(
677 entA.get()));
678 rtl::Reference<unoidl::AccumulationBasedServiceEntity>
679 ent2B(
680 static_cast<unoidl::AccumulationBasedServiceEntity *>(
681 entB.get()));
682 if (ent2A->getDirectMandatoryBaseServices().size()
683 != ent2B->getDirectMandatoryBaseServices().size())
685 std::cerr
686 << "accumulation-based service " << name
687 << (" number of direct mandatory base services"
688 " changed from ")
689 << ent2A->getDirectMandatoryBaseServices().size()
690 << " to "
691 << ent2B->getDirectMandatoryBaseServices().size()
692 << std::endl;
693 std::exit(EXIT_FAILURE);
695 for (auto
696 i(ent2A->getDirectMandatoryBaseServices().begin()),
697 j(ent2B->getDirectMandatoryBaseServices().begin());
698 i != ent2A->getDirectMandatoryBaseServices().end();
699 ++i, ++j)
701 if (i->name != j->name) {
702 std::cerr
703 << "accumulation-based service " << name
704 << " direct mandatory base service #"
705 << (i
706 - (ent2A->getDirectMandatoryBaseServices()
707 .begin())
708 + 1)
709 << " changed from " << i->name << " to "
710 << j->name << std::endl;
711 std::exit(EXIT_FAILURE);
714 if (ent2A->getDirectOptionalBaseServices().size()
715 > ent2B->getDirectOptionalBaseServices().size())
717 std::cerr
718 << "accumulation-based service " << name
719 << (" number of direct optional base services"
720 " shrank from ")
721 << ent2A->getDirectOptionalBaseServices().size()
722 << " to "
723 << ent2B->getDirectOptionalBaseServices().size()
724 << std::endl;
725 std::exit(EXIT_FAILURE);
727 for (auto & i: ent2A->getDirectOptionalBaseServices()) {
728 if (std::none_of(
729 ent2B->getDirectOptionalBaseServices().begin(),
730 ent2B->getDirectOptionalBaseServices().end(),
731 EqualsAnnotation(i.name)))
733 std::cerr
734 << "accumulation-based service " << name
735 << " direct optional base service " << i.name
736 << " was removed" << std::endl;
737 std::exit(EXIT_FAILURE);
740 if (ent2A->getDirectMandatoryBaseInterfaces().size()
741 != ent2B->getDirectMandatoryBaseInterfaces().size())
743 std::cerr
744 << "accumulation-based service " << name
745 << (" number of direct mandatory base interfaces"
746 " changed from ")
747 << ent2A->getDirectMandatoryBaseInterfaces().size()
748 << " to "
749 << ent2B->getDirectMandatoryBaseInterfaces().size()
750 << std::endl;
751 std::exit(EXIT_FAILURE);
753 for (auto
754 i(ent2A->getDirectMandatoryBaseInterfaces()
755 .begin()),
756 j(ent2B->getDirectMandatoryBaseInterfaces()
757 .begin());
758 i != ent2A->getDirectMandatoryBaseInterfaces().end();
759 ++i, ++j)
761 if (i->name != j->name) {
762 std::cerr
763 << "accumulation-based service " << name
764 << " direct mandatory base interface #"
765 << (i
766 - (ent2A->getDirectMandatoryBaseInterfaces()
767 .begin())
768 + 1)
769 << " changed from " << i->name << " to "
770 << j->name << std::endl;
771 std::exit(EXIT_FAILURE);
774 if (ent2A->getDirectOptionalBaseInterfaces().size()
775 > ent2B->getDirectOptionalBaseInterfaces().size())
777 std::cerr
778 << "accumulation-based service " << name
779 << (" number of direct optional base interfaces"
780 " shrank from ")
781 << ent2A->getDirectOptionalBaseInterfaces().size()
782 << " to "
783 << ent2B->getDirectOptionalBaseInterfaces().size()
784 << std::endl;
785 std::exit(EXIT_FAILURE);
787 for (auto & i: ent2A->getDirectOptionalBaseInterfaces()) {
788 if (std::none_of(
789 (ent2B->getDirectOptionalBaseInterfaces()
790 .begin()),
791 ent2B->getDirectOptionalBaseInterfaces().end(),
792 EqualsAnnotation(i.name)))
794 std::cerr
795 << "accumulation-based service " << name
796 << " direct optional base interface " << i.name
797 << " was removed" << std::endl;
798 std::exit(EXIT_FAILURE);
801 if (ent2A->getDirectProperties().size()
802 > ent2B->getDirectProperties().size())
804 std::cerr
805 << "accumulation-based service " << name
806 << " number of direct properties changed from "
807 << ent2A->getDirectProperties().size() << " to "
808 << ent2B->getDirectProperties().size() << std::endl;
809 std::exit(EXIT_FAILURE);
811 for (auto
812 i(ent2A->getDirectProperties().begin()),
813 j(ent2B->getDirectProperties().begin());
814 i != ent2A->getDirectProperties().end(); ++i, ++j)
816 if (i->name != j->name || i->type != j->type
817 || i->attributes != j->attributes)
819 std::cerr
820 << "accumulation-based service " << name
821 << " direct property #"
822 << i - ent2A->getDirectProperties().begin() + 1
823 << " changed from "
824 << i->type << " " << i->name //TODO: attributes
825 << " to "
826 << j->type << " " << j->name //TODO: attributes
827 << std::endl;
828 std::exit(EXIT_FAILURE);
831 for (auto
832 i(ent2B->getDirectProperties().begin()
833 + ent2A->getDirectProperties().size());
834 i != ent2B->getDirectProperties().end(); ++i)
836 if ((i->attributes & unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_OPTIONAL) == 0)
838 std::cerr
839 << "B accumulation-based service " << name
840 << " additional direct property " << i->name
841 << " is not optional" << std::endl;
842 std::exit(EXIT_FAILURE);
845 break;
847 case unoidl::Entity::SORT_INTERFACE_BASED_SINGLETON:
849 rtl::Reference<unoidl::InterfaceBasedSingletonEntity> ent2A(
850 static_cast<unoidl::InterfaceBasedSingletonEntity *>(
851 entA.get()));
852 rtl::Reference<unoidl::InterfaceBasedSingletonEntity> ent2B(
853 static_cast<unoidl::InterfaceBasedSingletonEntity *>(
854 entB.get()));
855 if (ent2A->getBase() != ent2B->getBase()) {
856 std::cerr
857 << "interface-based singleton " << name
858 << " base changed from " << ent2A->getBase()
859 << " to " << ent2B->getBase() << std::endl;
860 std::exit(EXIT_FAILURE);
862 break;
864 case unoidl::Entity::SORT_SERVICE_BASED_SINGLETON:
866 rtl::Reference<unoidl::ServiceBasedSingletonEntity> ent2A(
867 static_cast<unoidl::ServiceBasedSingletonEntity *>(
868 entA.get()));
869 rtl::Reference<unoidl::ServiceBasedSingletonEntity> ent2B(
870 static_cast<unoidl::ServiceBasedSingletonEntity *>(
871 entB.get()));
872 if (ent2A->getBase() != ent2B->getBase()) {
873 std::cerr
874 << "service-based singleton " << name
875 << " base changed from " << ent2A->getBase()
876 << " to " << ent2B->getBase() << std::endl;
877 std::exit(EXIT_FAILURE);
879 break;
881 case unoidl::Entity::SORT_MODULE:
882 assert(false && "this cannot happen");
888 bool valid(OUString const & identifier) {
889 for (sal_Int32 i = 0;; ++i) {
890 i = identifier.indexOf('_', i);
891 if (i == -1) {
892 return true;
894 if (!rtl::isAsciiUpperCase(identifier[0]) || identifier[i - 1] == '_') {
895 return false;
900 void checkIds(
901 rtl::Reference<unoidl::Provider> const & providerA, OUString const & prefix,
902 rtl::Reference<unoidl::MapCursor> const & cursor)
904 assert(cursor.is());
905 for (;;) {
906 OUString id;
907 rtl::Reference<unoidl::Entity> entB(cursor->getNext(&id));
908 if (!entB.is()) {
909 break;
911 OUString name(prefix + id);
912 rtl::Reference<unoidl::Entity> entA(providerA->findEntity(name));
913 if (!(entA.is() || valid(id))) {
914 std::cerr
915 << "entity name " << name << " uses an invalid identifier"
916 << std::endl;
917 std::exit(EXIT_FAILURE);
919 switch (entB->getSort()) {
920 case unoidl::Entity::SORT_MODULE:
921 checkIds(
922 providerA, name + ".",
923 (static_cast<unoidl::ModuleEntity *>(entB.get())
924 ->createCursor()));
925 break;
926 case unoidl::Entity::SORT_ENUM_TYPE:
927 if (!entA.is()) {
928 rtl::Reference<unoidl::EnumTypeEntity> ent2B(
929 static_cast<unoidl::EnumTypeEntity *>(entB.get()));
930 for (auto & i: ent2B->getMembers()) {
931 if (!valid(i.name)) {
932 std::cerr
933 << "enum type " << name << " member " << i.name
934 << " uses an invalid identifier" << std::endl;
935 std::exit(EXIT_FAILURE);
939 break;
940 case unoidl::Entity::SORT_PLAIN_STRUCT_TYPE:
941 if (!entA.is()) {
942 rtl::Reference<unoidl::PlainStructTypeEntity> ent2B(
943 static_cast<unoidl::PlainStructTypeEntity *>(
944 entB.get()));
945 for (auto & i: ent2B->getDirectMembers()) {
946 if (!valid(i.name)) {
947 std::cerr
948 << "plain struct type " << name << " direct member "
949 << i.name << " uses an invalid identifier"
950 << std::endl;
951 std::exit(EXIT_FAILURE);
955 break;
956 case unoidl::Entity::SORT_POLYMORPHIC_STRUCT_TYPE_TEMPLATE:
957 if (!entA.is()) {
958 rtl::Reference<unoidl::PolymorphicStructTypeTemplateEntity>
959 ent2B(
960 static_cast<
961 unoidl::PolymorphicStructTypeTemplateEntity *>(
962 entB.get()));
963 for (auto & i: ent2B->getTypeParameters()) {
964 if (!valid(i)) {
965 std::cerr
966 << "polymorphic struct type template " << name
967 << " type parameter " << i
968 << " uses an invalid identifier" << std::endl;
969 std::exit(EXIT_FAILURE);
972 for (auto & i: ent2B->getMembers()) {
973 if (!valid(i.name)) {
974 std::cerr
975 << "polymorphic struct type template " << name
976 << " member " << i.name
977 << " uses an invalid identifier" << std::endl;
978 std::exit(EXIT_FAILURE);
982 break;
983 case unoidl::Entity::SORT_EXCEPTION_TYPE:
984 if (!entA.is()) {
985 rtl::Reference<unoidl::ExceptionTypeEntity> ent2B(
986 static_cast<unoidl::ExceptionTypeEntity *>(entB.get()));
987 for (auto & i: ent2B->getDirectMembers()) {
988 if (!valid(i.name)) {
989 std::cerr
990 << "exception type " << name << " direct member "
991 << i.name << " uses an invalid identifier"
992 << std::endl;
993 std::exit(EXIT_FAILURE);
997 break;
998 case unoidl::Entity::SORT_INTERFACE_TYPE:
999 if (!entA.is()) {
1000 rtl::Reference<unoidl::InterfaceTypeEntity> ent2B(
1001 static_cast<unoidl::InterfaceTypeEntity *>(entB.get()));
1002 for (auto & i: ent2B->getDirectAttributes()) {
1003 if (!valid(i.name)) {
1004 std::cerr
1005 << "interface type " << name << " direct attribute "
1006 << i.name << " uses an invalid identifier"
1007 << std::endl;
1008 std::exit(EXIT_FAILURE);
1011 for (auto & i: ent2B->getDirectMethods()) {
1012 if (!valid(i.name)) {
1013 std::cerr
1014 << "interface type " << name << " direct method "
1015 << i.name << " uses an invalid identifier"
1016 << std::endl;
1017 std::exit(EXIT_FAILURE);
1019 for (auto & j: i.parameters) {
1020 if (!valid(j.name)) {
1021 std::cerr
1022 << "interface type " << name
1023 << " direct method " << i.name << " parameter "
1024 << j.name << " uses an invalid identifier"
1025 << std::endl;
1026 std::exit(EXIT_FAILURE);
1031 break;
1032 case unoidl::Entity::SORT_TYPEDEF:
1033 case unoidl::Entity::SORT_INTERFACE_BASED_SINGLETON:
1034 case unoidl::Entity::SORT_SERVICE_BASED_SINGLETON:
1035 break;
1036 case unoidl::Entity::SORT_CONSTANT_GROUP:
1038 rtl::Reference<unoidl::ConstantGroupEntity> ent2B(
1039 static_cast<unoidl::ConstantGroupEntity *>(entB.get()));
1040 for (auto & i: ent2B->getMembers()) {
1041 bool found = false;
1042 if (entA.is()) {
1043 rtl::Reference<unoidl::ConstantGroupEntity> ent2A(
1044 static_cast<unoidl::ConstantGroupEntity *>(
1045 entA.get()));
1046 for (auto & j: ent2A->getMembers()) {
1047 if (i.name == j.name) {
1048 found = true;
1049 break;
1053 if (!(found || valid(i.name))) {
1054 std::cerr
1055 << "Constant group " << name << " member "
1056 << i.name << " uses an invalid identifier"
1057 << std::endl;
1058 std::exit(EXIT_FAILURE);
1061 break;
1063 case unoidl::Entity::SORT_SINGLE_INTERFACE_BASED_SERVICE:
1064 if (!entA.is()) {
1065 rtl::Reference<unoidl::SingleInterfaceBasedServiceEntity>
1066 ent2B(
1067 static_cast<unoidl::SingleInterfaceBasedServiceEntity *>(
1068 entB.get()));
1069 for (auto & i: ent2B->getConstructors()) {
1070 if (!valid(i.name)) {
1071 std::cerr
1072 << "single-interface--based service " << name
1073 << " constructor " << i.name
1074 << " uses an invalid identifier" << std::endl;
1075 std::exit(EXIT_FAILURE);
1077 for (auto & j: i.parameters) {
1078 if (!valid(j.name)) {
1079 std::cerr
1080 << "single-interface--based service " << name
1081 << " constructor " << i.name << " parameter "
1082 << j.name << " uses an invalid identifier"
1083 << std::endl;
1084 std::exit(EXIT_FAILURE);
1089 break;
1090 case unoidl::Entity::SORT_ACCUMULATION_BASED_SERVICE:
1092 rtl::Reference<unoidl::AccumulationBasedServiceEntity> ent2B(
1093 static_cast<unoidl::AccumulationBasedServiceEntity *>(
1094 entB.get()));
1095 std::vector<unoidl::AccumulationBasedServiceEntity::Property>::size_type
1096 n(entA.is()
1097 ? (static_cast<unoidl::AccumulationBasedServiceEntity *>(
1098 entA.get())
1099 ->getDirectProperties().size())
1100 : 0);
1101 assert(n <= ent2B->getDirectProperties().size());
1102 for (auto i(ent2B->getDirectProperties().begin() +n);
1103 i != ent2B->getDirectProperties().end(); ++i)
1105 if (!valid(i->name)) {
1106 std::cerr
1107 << "accumulation-based service " << name
1108 << " direct property " << i->name
1109 << " uses an invalid identifier" << std::endl;
1110 std::exit(EXIT_FAILURE);
1113 break;
1121 SAL_IMPLEMENT_MAIN() {
1122 try {
1123 sal_uInt32 args = rtl_getAppCommandArgCount();
1124 rtl::Reference<unoidl::Manager> mgr[2];
1125 mgr[0] = new unoidl::Manager;
1126 mgr[1] = new unoidl::Manager;
1127 rtl::Reference<unoidl::Provider> prov[2];
1128 int side = 0;
1129 bool ignoreUnpublished = false;
1130 for (sal_uInt32 i = 0; i != args; ++i) {
1131 bool delimiter = false;
1132 OUString uri;
1133 if (getArgument(
1134 i, &ignoreUnpublished, side == 0 ? &delimiter : nullptr,
1135 &uri))
1137 try {
1138 prov[side] = mgr[side]->addProvider(uri);
1139 } catch (unoidl::NoSuchFileException &) {
1140 std::cerr
1141 << "Input <" << uri << "> does not exist" << std::endl;
1142 std::exit(EXIT_FAILURE);
1144 } else if (delimiter) {
1145 side = 1;
1148 if (side == 0 || !(prov[0].is() && prov[1].is())) {
1149 badUsage();
1151 checkMap(prov[1], "", prov[0]->createRootCursor(), ignoreUnpublished);
1152 checkIds(prov[0], "", prov[1]->createRootCursor());
1153 return EXIT_SUCCESS;
1154 } catch (unoidl::FileFormatException & e1) {
1155 std::cerr
1156 << "Bad input <" << e1.getUri() << ">: " << e1.getDetail()
1157 << std::endl;
1158 std::exit(EXIT_FAILURE);
1159 } catch (std::exception & e1) {
1160 std::cerr << "Failure: " << e1.what() << std::endl;
1161 std::exit(EXIT_FAILURE);
1165 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */