diff options
Diffstat (limited to 'unoidl/source/unoidl-check.cxx')
-rw-r--r-- | unoidl/source/unoidl-check.cxx | 1167 |
1 files changed, 1167 insertions, 0 deletions
diff --git a/unoidl/source/unoidl-check.cxx b/unoidl/source/unoidl-check.cxx new file mode 100644 index 0000000000..fdeb74441f --- /dev/null +++ b/unoidl/source/unoidl-check.cxx @@ -0,0 +1,1167 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <sal/config.h> + +#include <algorithm> +#include <cassert> +#include <cstdlib> +#include <iostream> +#include <string_view> +#include <utility> +#include <vector> + +#include <osl/file.hxx> +#include <osl/process.h> +#include <rtl/character.hxx> +#include <rtl/process.h> +#include <rtl/ref.hxx> +#include <rtl/ustring.hxx> +#include <sal/main.h> +#include <sal/types.h> +#include <unoidl/unoidl.hxx> + +namespace unoidl { + +static bool operator ==(ConstantValue const & lhs, ConstantValue const & rhs) { + if (lhs.type == rhs.type) { + switch (lhs.type) { + case ConstantValue::TYPE_BOOLEAN: + return lhs.booleanValue == rhs.booleanValue; + case ConstantValue::TYPE_BYTE: + return lhs.byteValue == rhs.byteValue; + case ConstantValue::TYPE_SHORT: + return lhs.shortValue == rhs.shortValue; + case ConstantValue::TYPE_UNSIGNED_SHORT: + return lhs.unsignedShortValue == rhs.unsignedShortValue; + case ConstantValue::TYPE_LONG: + return lhs.longValue == rhs.longValue; + case ConstantValue::TYPE_UNSIGNED_LONG: + return lhs.unsignedLongValue == rhs.unsignedLongValue; + case ConstantValue::TYPE_HYPER: + return lhs.hyperValue == rhs.hyperValue; + case ConstantValue::TYPE_UNSIGNED_HYPER: + return lhs.unsignedHyperValue == rhs.unsignedHyperValue; + case ConstantValue::TYPE_FLOAT: + return lhs.floatValue == rhs.floatValue; + case ConstantValue::TYPE_DOUBLE: + return lhs.doubleValue == rhs.doubleValue; + } + } + return false; +} + +static bool operator !=(ConstantValue const & lhs, ConstantValue const & rhs) { + return !(lhs == rhs); +} + +static bool operator ==( + SingleInterfaceBasedServiceEntity::Constructor::Parameter const & lhs, + SingleInterfaceBasedServiceEntity::Constructor::Parameter const & rhs) +{ + return lhs.name == rhs.name && lhs.type == rhs.type && lhs.rest == rhs.rest; +} + +} + +namespace { + +void badUsage() { + std::cerr + << "Usage:" << std::endl << std::endl + << (" unoidl-check [--ignore-unpublished] [<extra registries A>]" + " <registry A> --") + << std::endl << " [<extra registries B>] <registry B>" << std::endl + << std::endl + << ("where each <registry> is either a new- or legacy-format .rdb file," + " a single .idl") + << std::endl + << ("file, or a root directory of an .idl file tree. Check that each" + " entity from") + << std::endl + << "<registry A> is also present in <registry B> in a compatible form." + << std::endl; + std::exit(EXIT_FAILURE); +} + +bool getArgument( + sal_uInt32 argument, bool * ignoreUnpublished, bool * delimiter, + OUString * uri) +{ + assert(ignoreUnpublished != nullptr); + assert(uri != nullptr); + OUString arg; + rtl_getAppCommandArg(argument, &arg.pData); + if (argument == 0 && arg == "--ignore-unpublished") { + *ignoreUnpublished = true; + return false; + } + if (arg == "--") { + if (delimiter == nullptr) { + badUsage(); + } + *delimiter = true; + return false; + } + OUString url; + osl::FileBase::RC e1 = osl::FileBase::getFileURLFromSystemPath(arg, url); + if (e1 != osl::FileBase::E_None) { + std::cerr + << "Cannot convert \"" << arg << "\" to file URL, error code " + << +e1 << std::endl; + std::exit(EXIT_FAILURE); + } + OUString cwd; + oslProcessError e2 = osl_getProcessWorkingDir(&cwd.pData); + if (e2 != osl_Process_E_None) { + std::cerr + << "Cannot obtain working directory, error code " << +e2 + << std::endl; + std::exit(EXIT_FAILURE); + } + e1 = osl::FileBase::getAbsoluteFileURL(cwd, url, *uri); + if (e1 != osl::FileBase::E_None) { + std::cerr + << "Cannot make \"" << url + << "\" into an absolute file URL, error code " << +e1 << std::endl; + std::exit(EXIT_FAILURE); + } + return true; +} + +OUString showDirection( + unoidl::InterfaceTypeEntity::Method::Parameter::Direction direction) +{ + switch (direction) { + case unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN: + return "[in]"; + case unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_OUT: + return "[out]"; + case unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN_OUT: + return "[inout]"; + default: + assert(false && "this cannot happen"); for (;;) { std::abort(); } + } +} + +struct EqualsAnnotation { + explicit EqualsAnnotation(OUString name): name_(std::move(name)) {} + + bool operator ()(unoidl::AnnotatedReference const & ref) + { return ref.name == name_; } + +private: + OUString name_; +}; + +void checkMap( + rtl::Reference<unoidl::Provider> const & providerB, std::u16string_view prefix, + rtl::Reference<unoidl::MapCursor> const & cursor, bool ignoreUnpublished) +{ + assert(providerB.is()); + assert(cursor.is()); + for (;;) { + OUString id; + rtl::Reference<unoidl::Entity> entA(cursor->getNext(&id)); + if (!entA.is()) { + break; + } + OUString name(prefix + id); + if (entA->getSort() == unoidl::Entity::SORT_MODULE) { + checkMap( + providerB, Concat2View(name + "."), + (static_cast<unoidl::ModuleEntity *>(entA.get()) + ->createCursor()), + ignoreUnpublished); + } else { + bool pubA = dynamic_cast<unoidl::PublishableEntity&>(*entA).isPublished(); + if (!pubA && ignoreUnpublished) { + continue; + } + rtl::Reference<unoidl::Entity> entB(providerB->findEntity(name)); + if (!entB.is()) { + std::cerr + << "A entity " << name << " is not present in B" + << std::endl; + std::exit(EXIT_FAILURE); + } + if (entA->getSort() != entB->getSort()) { + std::cerr + << "A entity " << name << " is of different sort in B" + << std::endl; + std::exit(EXIT_FAILURE); + } + if (pubA && (!dynamic_cast<unoidl::PublishableEntity&>(*entB).isPublished())) + { + std::cerr + << "A published entity " << name << " is not published in B" + << std::endl; + std::exit(EXIT_FAILURE); + } + switch (entA->getSort()) { + case unoidl::Entity::SORT_ENUM_TYPE: + { + rtl::Reference<unoidl::EnumTypeEntity> ent2A( + static_cast<unoidl::EnumTypeEntity *>(entA.get())); + rtl::Reference<unoidl::EnumTypeEntity> ent2B( + static_cast<unoidl::EnumTypeEntity *>(entB.get())); + if (ent2A->getMembers().size() + != ent2B->getMembers().size()) + { + std::cerr + << "enum type " << name + << " number of members changed from " + << ent2A->getMembers().size() << " to " + << ent2B->getMembers().size() << std::endl; + std::exit(EXIT_FAILURE); + } + for (auto + i(ent2A->getMembers().begin()), + j(ent2B->getMembers().begin()); + i != ent2A->getMembers().end(); ++i, ++j) + { + if (i->name != j->name || i->value != j->value) { + std::cerr + << "enum type " << name << " member #" + << i - ent2A->getMembers().begin() + 1 + << " changed from " << i->name << " = " + << i->value << " to " << j->name << " = " + << j->value << std::endl; + std::exit(EXIT_FAILURE); + } + } + break; + } + case unoidl::Entity::SORT_PLAIN_STRUCT_TYPE: + { + rtl::Reference<unoidl::PlainStructTypeEntity> ent2A( + static_cast<unoidl::PlainStructTypeEntity *>( + entA.get())); + rtl::Reference<unoidl::PlainStructTypeEntity> ent2B( + static_cast<unoidl::PlainStructTypeEntity *>( + entB.get())); + if (ent2A->getDirectBase() != ent2B->getDirectBase()) { + std::cerr + << "plain struct type " << name + << " direct base changed from " + << (ent2A->getDirectBase().isEmpty() + ? OUString("none") : ent2A->getDirectBase()) + << " to " + << (ent2B->getDirectBase().isEmpty() + ? OUString("none") : ent2B->getDirectBase()) + << std::endl; + std::exit(EXIT_FAILURE); + } + if (ent2A->getDirectMembers().size() + != ent2B->getDirectMembers().size()) + { + std::cerr + << "plain struct type " << name + << " number of direct members changed from " + << ent2A->getDirectMembers().size() << " to " + << ent2B->getDirectMembers().size() << std::endl; + std::exit(EXIT_FAILURE); + } + for (auto + i(ent2A->getDirectMembers().begin()), + j(ent2B->getDirectMembers().begin()); + i != ent2A->getDirectMembers().end(); ++i, ++j) + { + if (i->name != j->name || i->type != j->type) { + std::cerr + << "plain struct type " << name + << " direct member #" + << i - ent2A->getDirectMembers().begin() + 1 + << " changed from " << i->type << " " << i->name + << " to " << j->type << " " << j->name + << std::endl; + std::exit(EXIT_FAILURE); + } + } + break; + } + case unoidl::Entity::SORT_POLYMORPHIC_STRUCT_TYPE_TEMPLATE: + { + rtl::Reference<unoidl::PolymorphicStructTypeTemplateEntity> + ent2A( + static_cast<unoidl::PolymorphicStructTypeTemplateEntity *>( + entA.get())); + rtl::Reference<unoidl::PolymorphicStructTypeTemplateEntity> + ent2B( + static_cast<unoidl::PolymorphicStructTypeTemplateEntity *>( + entB.get())); + if (ent2A->getTypeParameters().size() + != ent2B->getTypeParameters().size()) + { + std::cerr + << "polymorphic struct type template " << name + << " number of type parameters changed from " + << ent2A->getTypeParameters().size() << " to " + << ent2B->getTypeParameters().size() << std::endl; + std::exit(EXIT_FAILURE); + } + for (auto + i(ent2A->getTypeParameters().begin()), + j(ent2B->getTypeParameters().begin()); + i != ent2A->getTypeParameters().end(); ++i, ++j) + { + if (*i != *j) { + std::cerr + << "polymorphic struct type template " << name + << " type parameter #" + << i - ent2A->getTypeParameters().begin() + 1 + << " changed from " << *i << " to " << *j + << std::endl; + std::exit(EXIT_FAILURE); + } + } + if (ent2A->getMembers().size() + != ent2B->getMembers().size()) + { + std::cerr + << "polymorphic struct type template " << name + << " number of members changed from " + << ent2A->getMembers().size() << " to " + << ent2B->getMembers().size() << std::endl; + std::exit(EXIT_FAILURE); + } + for (auto + i(ent2A->getMembers().begin()), + j(ent2B->getMembers().begin()); + i != ent2A->getMembers().end(); ++i, ++j) + { + if (i->name != j->name || i->type != j->type + || i->parameterized != j->parameterized) + { + std::cerr + << "polymorphic struct type template " << name + << " member #" + << i - ent2A->getMembers().begin() + 1 + << " changed from " + << (i->parameterized + ? OUString("parameterized ") : OUString()) + << i->type << " " << i->name + << " to " + << (j->parameterized + ? OUString("parameterized ") : OUString()) + << j->type << " " << j->name + << std::endl; + std::exit(EXIT_FAILURE); + } + } + break; + } + case unoidl::Entity::SORT_EXCEPTION_TYPE: + { + rtl::Reference<unoidl::ExceptionTypeEntity> ent2A( + static_cast<unoidl::ExceptionTypeEntity *>(entA.get())); + rtl::Reference<unoidl::ExceptionTypeEntity> ent2B( + static_cast<unoidl::ExceptionTypeEntity *>(entB.get())); + if (ent2A->getDirectBase() != ent2B->getDirectBase()) { + std::cerr + << "exception type " << name + << " direct base changed from " + << (ent2A->getDirectBase().isEmpty() + ? OUString("none") : ent2A->getDirectBase()) + << " to " + << (ent2B->getDirectBase().isEmpty() + ? OUString("none") : ent2B->getDirectBase()) + << std::endl; + std::exit(EXIT_FAILURE); + } + if (ent2A->getDirectMembers().size() + != ent2B->getDirectMembers().size()) + { + std::cerr + << "exception type " << name + << " number of direct members changed from " + << ent2A->getDirectMembers().size() << " to " + << ent2B->getDirectMembers().size() << std::endl; + std::exit(EXIT_FAILURE); + } + for (auto + i(ent2A->getDirectMembers().begin()), + j(ent2B->getDirectMembers().begin()); + i != ent2A->getDirectMembers().end(); ++i, ++j) + { + if (i->name != j->name || i->type != j->type) { + std::cerr + << "exception type " << name + << " direct member #" + << i - ent2A->getDirectMembers().begin() + 1 + << " changed from " << i->type << " " << i->name + << " to " << j->type << " " << j->name + << std::endl; + std::exit(EXIT_FAILURE); + } + } + break; + } + case unoidl::Entity::SORT_INTERFACE_TYPE: + { + rtl::Reference<unoidl::InterfaceTypeEntity> ent2A( + static_cast<unoidl::InterfaceTypeEntity *>(entA.get())); + rtl::Reference<unoidl::InterfaceTypeEntity> ent2B( + static_cast<unoidl::InterfaceTypeEntity *>(entB.get())); + if (ent2A->getDirectMandatoryBases().size() + != ent2B->getDirectMandatoryBases().size()) + { + std::cerr + << "interface type " << name + << " number of direct mandatory bases changed from " + << ent2A->getDirectMandatoryBases().size() << " to " + << ent2B->getDirectMandatoryBases().size() + << std::endl; + std::exit(EXIT_FAILURE); + } + for (auto + i(ent2A->getDirectMandatoryBases().begin()), + j(ent2B->getDirectMandatoryBases().begin()); + i != ent2A->getDirectMandatoryBases().end(); ++i, ++j) + { + if (i->name != j->name) { + std::cerr + << "interface type " << name + << " direct mandatory base #" + << (i - ent2A->getDirectMandatoryBases().begin() + + 1) + << " changed from " << i->name << " to " + << j->name << std::endl; + std::exit(EXIT_FAILURE); + } + } + if (ent2A->getDirectOptionalBases().size() + != ent2B->getDirectOptionalBases().size()) + { + std::cerr + << "interface type " << name + << " number of direct optional bases changed from " + << ent2A->getDirectOptionalBases().size() << " to " + << ent2B->getDirectOptionalBases().size() + << std::endl; + std::exit(EXIT_FAILURE); + } + for (auto + i(ent2A->getDirectOptionalBases().begin()), + j(ent2B->getDirectOptionalBases().begin()); + i != ent2A->getDirectOptionalBases().end(); ++i, ++j) + { + if (i->name != j->name) { + std::cerr + << "interface type " << name + << " direct optional base #" + << (i - ent2A->getDirectOptionalBases().begin() + + 1) + << " changed from " << i->name << " to " + << j->name << std::endl; + std::exit(EXIT_FAILURE); + } + } + if (ent2A->getDirectAttributes().size() + != ent2B->getDirectAttributes().size()) + { + std::cerr + << "interface type " << name + << " number of direct attributes changed from " + << ent2A->getDirectAttributes().size() << " to " + << ent2B->getDirectAttributes().size() << std::endl; + std::exit(EXIT_FAILURE); + } + for (auto + i(ent2A->getDirectAttributes().begin()), + j(ent2B->getDirectAttributes().begin()); + i != ent2A->getDirectAttributes().end(); ++i, ++j) + { + if (i->name != j->name || i->type != j->type + || i->bound != j->bound + || i->readOnly != j->readOnly + || i->getExceptions != j->getExceptions + || i->setExceptions != j->setExceptions) + { + std::cerr + << "interface type " << name + << " direct attribute #" + << i - ent2A->getDirectAttributes().begin() + 1 + << " changed from " + << (i->bound ? OUString("bound ") : OUString()) + << (i->readOnly + ? OUString("read-only ") : OUString()) + << i->type << " " << i->name //TODO: exceptions + << " to " + << (j->bound ? OUString("bound ") : OUString()) + << (j->readOnly + ? OUString("read-only ") : OUString()) + << j->type << " " << j->name //TODO: exceptions + << std::endl; + std::exit(EXIT_FAILURE); + } + } + if (ent2A->getDirectMethods().size() + != ent2B->getDirectMethods().size()) + { + std::cerr + << "interface type " << name + << " number of direct methods changed from " + << ent2A->getDirectMethods().size() << " to " + << ent2B->getDirectMethods().size() << std::endl; + std::exit(EXIT_FAILURE); + } + for (auto + i(ent2A->getDirectMethods().begin()), + j(ent2B->getDirectMethods().begin()); + i != ent2A->getDirectMethods().end(); ++i, ++j) + { + if (i->name != j->name || i->returnType != j->returnType + || i->exceptions != j->exceptions) + { + std::cerr + << "interface type " << name + << " direct method #" + << i - ent2A->getDirectMethods().begin() + 1 + << " changed from " + << i->returnType << " " << i->name //TODO: exceptions + << " to " << j->returnType << " " << j->name //TODO: exceptions + << std::endl; + std::exit(EXIT_FAILURE); + } + if (i->parameters.size() != j->parameters.size()) { + std::cerr + << "interface type " << name + << " direct method " << i->name + << " number of parameters changed from " + << i->parameters.size() << " to " + << j->parameters.size() << std::endl; + std::exit(EXIT_FAILURE); + } + for (auto + k(i->parameters.begin()), + l(j->parameters.begin()); + k != i->parameters.end(); ++k, ++l) + { + if (k->type != l->type || k->direction != l->direction) + { + std::cerr + << "interface type " << name + << " direct method " << i->name + << " parameter #" + << k - i->parameters.begin() + 1 + << " changed from " + << showDirection(k->direction) << " " + << k->type << " to " + << showDirection(l->direction) << " " + << l->type << std::endl; + std::exit(EXIT_FAILURE); + } + if (k->name != l->name) { + std::cerr + << "interface type " << name + << " direct method " << i->name + << " parameter #" + << k - i->parameters.begin() + 1 + << " changed name from " << k->name + << " to " << l->name << std::endl; + std::exit(EXIT_FAILURE); + } + } + } + break; + } + case unoidl::Entity::SORT_TYPEDEF: + { + rtl::Reference<unoidl::TypedefEntity> ent2A( + static_cast<unoidl::TypedefEntity *>(entA.get())); + rtl::Reference<unoidl::TypedefEntity> ent2B( + static_cast<unoidl::TypedefEntity *>(entB.get())); + if (ent2A->getType() != ent2B->getType()) { + std::cerr + << "typedef " << name << " type changed from " + << ent2A->getType() << " to " << ent2B->getType() + << std::endl; + std::exit(EXIT_FAILURE); + } + break; + } + case unoidl::Entity::SORT_CONSTANT_GROUP: + { + rtl::Reference<unoidl::ConstantGroupEntity> ent2A( + static_cast<unoidl::ConstantGroupEntity *>(entA.get())); + rtl::Reference<unoidl::ConstantGroupEntity> ent2B( + static_cast<unoidl::ConstantGroupEntity *>(entB.get())); + for (auto & i: ent2A->getMembers()) { + bool found = false; + for (auto & j: ent2B->getMembers()) { + if (i.name == j.name) { + if (i.value != j.value) { + std::cerr + << "constant group " << name + << " member " << i.name + << " changed value" << std::endl; + std::exit(EXIT_FAILURE); + } + found = true; + break; + } + } + if (!found) { + std::cerr + << "A constant group " << name << " member " + << i.name << " is not present in B" + << std::endl; + std::exit(EXIT_FAILURE); + } + } + break; + } + case unoidl::Entity::SORT_SINGLE_INTERFACE_BASED_SERVICE: + { + rtl::Reference<unoidl::SingleInterfaceBasedServiceEntity> + ent2A( + static_cast<unoidl::SingleInterfaceBasedServiceEntity *>( + entA.get())); + rtl::Reference<unoidl::SingleInterfaceBasedServiceEntity> + ent2B( + static_cast<unoidl::SingleInterfaceBasedServiceEntity *>( + entB.get())); + if (ent2A->getBase() != ent2B->getBase()) { + std::cerr + << "single-interface--based service " << name + << " base changed from " << ent2A->getBase() + << " to " << ent2B->getBase() + << std::endl; + std::exit(EXIT_FAILURE); + } + if (ent2A->getConstructors().size() + != ent2B->getConstructors().size()) + { + std::cerr + << "single-interface--based service " << name + << " number of constructors changed from " + << ent2A->getConstructors().size() << " to " + << ent2B->getConstructors().size() << std::endl; + std::exit(EXIT_FAILURE); + } + for (auto + i(ent2A->getConstructors().begin()), + j(ent2B->getConstructors().begin()); + i != ent2A->getConstructors().end(); ++i, ++j) + { + if (i->name != j->name || i->parameters != j->parameters + || i->exceptions != j->exceptions + || i->defaultConstructor != j->defaultConstructor) + { + std::cerr + << "single-interface--based service " << name + << " constructor #" + << i - ent2A->getConstructors().begin() + 1 + << " changed from " + << (i->defaultConstructor + ? OUString("default ") : i->name) //TODO: parameters, exceptions + << " to " + << (j->defaultConstructor + ? OUString("default ") : j->name) //TODO: parameters, exceptions + << std::endl; + std::exit(EXIT_FAILURE); + } + } + break; + } + case unoidl::Entity::SORT_ACCUMULATION_BASED_SERVICE: + { + rtl::Reference<unoidl::AccumulationBasedServiceEntity> + ent2A( + static_cast<unoidl::AccumulationBasedServiceEntity *>( + entA.get())); + rtl::Reference<unoidl::AccumulationBasedServiceEntity> + ent2B( + static_cast<unoidl::AccumulationBasedServiceEntity *>( + entB.get())); + if (ent2A->getDirectMandatoryBaseServices().size() + != ent2B->getDirectMandatoryBaseServices().size()) + { + std::cerr + << "accumulation-based service " << name + << (" number of direct mandatory base services" + " changed from ") + << ent2A->getDirectMandatoryBaseServices().size() + << " to " + << ent2B->getDirectMandatoryBaseServices().size() + << std::endl; + std::exit(EXIT_FAILURE); + } + for (auto + i(ent2A->getDirectMandatoryBaseServices().begin()), + j(ent2B->getDirectMandatoryBaseServices().begin()); + i != ent2A->getDirectMandatoryBaseServices().end(); + ++i, ++j) + { + if (i->name != j->name) { + std::cerr + << "accumulation-based service " << name + << " direct mandatory base service #" + << (i + - (ent2A->getDirectMandatoryBaseServices() + .begin()) + + 1) + << " changed from " << i->name << " to " + << j->name << std::endl; + std::exit(EXIT_FAILURE); + } + } + if (ent2A->getDirectOptionalBaseServices().size() + > ent2B->getDirectOptionalBaseServices().size()) + { + std::cerr + << "accumulation-based service " << name + << (" number of direct optional base services" + " shrank from ") + << ent2A->getDirectOptionalBaseServices().size() + << " to " + << ent2B->getDirectOptionalBaseServices().size() + << std::endl; + std::exit(EXIT_FAILURE); + } + for (auto & i: ent2A->getDirectOptionalBaseServices()) { + if (std::none_of( + ent2B->getDirectOptionalBaseServices().begin(), + ent2B->getDirectOptionalBaseServices().end(), + EqualsAnnotation(i.name))) + { + std::cerr + << "accumulation-based service " << name + << " direct optional base service " << i.name + << " was removed" << std::endl; + std::exit(EXIT_FAILURE); + } + } + if (ent2A->getDirectMandatoryBaseInterfaces().size() + != ent2B->getDirectMandatoryBaseInterfaces().size()) + { + std::cerr + << "accumulation-based service " << name + << (" number of direct mandatory base interfaces" + " changed from ") + << ent2A->getDirectMandatoryBaseInterfaces().size() + << " to " + << ent2B->getDirectMandatoryBaseInterfaces().size() + << std::endl; + std::exit(EXIT_FAILURE); + } + for (auto + i(ent2A->getDirectMandatoryBaseInterfaces() + .begin()), + j(ent2B->getDirectMandatoryBaseInterfaces() + .begin()); + i != ent2A->getDirectMandatoryBaseInterfaces().end(); + ++i, ++j) + { + if (i->name != j->name) { + std::cerr + << "accumulation-based service " << name + << " direct mandatory base interface #" + << (i + - (ent2A->getDirectMandatoryBaseInterfaces() + .begin()) + + 1) + << " changed from " << i->name << " to " + << j->name << std::endl; + std::exit(EXIT_FAILURE); + } + } + if (ent2A->getDirectOptionalBaseInterfaces().size() + > ent2B->getDirectOptionalBaseInterfaces().size()) + { + std::cerr + << "accumulation-based service " << name + << (" number of direct optional base interfaces" + " shrank from ") + << ent2A->getDirectOptionalBaseInterfaces().size() + << " to " + << ent2B->getDirectOptionalBaseInterfaces().size() + << std::endl; + std::exit(EXIT_FAILURE); + } + for (auto & i: ent2A->getDirectOptionalBaseInterfaces()) { + if (std::none_of( + (ent2B->getDirectOptionalBaseInterfaces() + .begin()), + ent2B->getDirectOptionalBaseInterfaces().end(), + EqualsAnnotation(i.name))) + { + std::cerr + << "accumulation-based service " << name + << " direct optional base interface " << i.name + << " was removed" << std::endl; + std::exit(EXIT_FAILURE); + } + } + if (ent2A->getDirectProperties().size() + > ent2B->getDirectProperties().size()) + { + std::cerr + << "accumulation-based service " << name + << " number of direct properties changed from " + << ent2A->getDirectProperties().size() << " to " + << ent2B->getDirectProperties().size() << std::endl; + std::exit(EXIT_FAILURE); + } + for (auto + i(ent2A->getDirectProperties().begin()), + j(ent2B->getDirectProperties().begin()); + i != ent2A->getDirectProperties().end(); ++i, ++j) + { + if (i->name != j->name || i->type != j->type + || i->attributes != j->attributes) + { + std::cerr + << "accumulation-based service " << name + << " direct property #" + << i - ent2A->getDirectProperties().begin() + 1 + << " changed from " + << i->type << " " << i->name //TODO: attributes + << " to " + << j->type << " " << j->name //TODO: attributes + << std::endl; + std::exit(EXIT_FAILURE); + } + } + for (auto + i(ent2B->getDirectProperties().begin() + + ent2A->getDirectProperties().size()); + i != ent2B->getDirectProperties().end(); ++i) + { + if ((i->attributes & unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_OPTIONAL) == 0) + { + std::cerr + << "B accumulation-based service " << name + << " additional direct property " << i->name + << " is not optional" << std::endl; + std::exit(EXIT_FAILURE); + } + } + break; + } + case unoidl::Entity::SORT_INTERFACE_BASED_SINGLETON: + { + rtl::Reference<unoidl::InterfaceBasedSingletonEntity> ent2A( + static_cast<unoidl::InterfaceBasedSingletonEntity *>( + entA.get())); + rtl::Reference<unoidl::InterfaceBasedSingletonEntity> ent2B( + static_cast<unoidl::InterfaceBasedSingletonEntity *>( + entB.get())); + if (ent2A->getBase() != ent2B->getBase()) { + std::cerr + << "interface-based singleton " << name + << " base changed from " << ent2A->getBase() + << " to " << ent2B->getBase() << std::endl; + std::exit(EXIT_FAILURE); + } + break; + } + case unoidl::Entity::SORT_SERVICE_BASED_SINGLETON: + { + rtl::Reference<unoidl::ServiceBasedSingletonEntity> ent2A( + static_cast<unoidl::ServiceBasedSingletonEntity *>( + entA.get())); + rtl::Reference<unoidl::ServiceBasedSingletonEntity> ent2B( + static_cast<unoidl::ServiceBasedSingletonEntity *>( + entB.get())); + if (ent2A->getBase() != ent2B->getBase()) { + std::cerr + << "service-based singleton " << name + << " base changed from " << ent2A->getBase() + << " to " << ent2B->getBase() << std::endl; + std::exit(EXIT_FAILURE); + } + break; + } + case unoidl::Entity::SORT_MODULE: + assert(false && "this cannot happen"); + } + } + } +} + +bool valid(std::u16string_view identifier) { + for (size_t i = 0;; ++i) { + i = identifier.find('_', i); + if (i == std::u16string_view::npos) { + return true; + } + if (!rtl::isAsciiUpperCase(identifier[0]) || identifier[i - 1] == '_') { + return false; + } + } +} + +void checkIds( + rtl::Reference<unoidl::Provider> const & providerA, std::u16string_view prefix, + rtl::Reference<unoidl::MapCursor> const & cursor) +{ + assert(cursor.is()); + for (;;) { + OUString id; + rtl::Reference<unoidl::Entity> entB(cursor->getNext(&id)); + if (!entB.is()) { + break; + } + OUString name(prefix + id); + rtl::Reference<unoidl::Entity> entA(providerA->findEntity(name)); + if (!(entA.is() || valid(id))) { + std::cerr + << "entity name " << name << " uses an invalid identifier" + << std::endl; + std::exit(EXIT_FAILURE); + } + switch (entB->getSort()) { + case unoidl::Entity::SORT_MODULE: + checkIds( + providerA, Concat2View(name + "."), + (static_cast<unoidl::ModuleEntity *>(entB.get()) + ->createCursor())); + break; + case unoidl::Entity::SORT_ENUM_TYPE: + if (!entA.is()) { + rtl::Reference<unoidl::EnumTypeEntity> ent2B( + static_cast<unoidl::EnumTypeEntity *>(entB.get())); + for (auto & i: ent2B->getMembers()) { + if (!valid(i.name)) { + std::cerr + << "enum type " << name << " member " << i.name + << " uses an invalid identifier" << std::endl; + std::exit(EXIT_FAILURE); + } + } + } + break; + case unoidl::Entity::SORT_PLAIN_STRUCT_TYPE: + if (!entA.is()) { + rtl::Reference<unoidl::PlainStructTypeEntity> ent2B( + static_cast<unoidl::PlainStructTypeEntity *>( + entB.get())); + for (auto & i: ent2B->getDirectMembers()) { + if (!valid(i.name)) { + std::cerr + << "plain struct type " << name << " direct member " + << i.name << " uses an invalid identifier" + << std::endl; + std::exit(EXIT_FAILURE); + } + } + } + break; + case unoidl::Entity::SORT_POLYMORPHIC_STRUCT_TYPE_TEMPLATE: + if (!entA.is()) { + rtl::Reference<unoidl::PolymorphicStructTypeTemplateEntity> + ent2B( + static_cast< + unoidl::PolymorphicStructTypeTemplateEntity *>( + entB.get())); + for (auto & i: ent2B->getTypeParameters()) { + if (!valid(i)) { + std::cerr + << "polymorphic struct type template " << name + << " type parameter " << i + << " uses an invalid identifier" << std::endl; + std::exit(EXIT_FAILURE); + } + } + for (auto & i: ent2B->getMembers()) { + if (!valid(i.name)) { + std::cerr + << "polymorphic struct type template " << name + << " member " << i.name + << " uses an invalid identifier" << std::endl; + std::exit(EXIT_FAILURE); + } + } + } + break; + case unoidl::Entity::SORT_EXCEPTION_TYPE: + if (!entA.is()) { + rtl::Reference<unoidl::ExceptionTypeEntity> ent2B( + static_cast<unoidl::ExceptionTypeEntity *>(entB.get())); + for (auto & i: ent2B->getDirectMembers()) { + if (!valid(i.name)) { + std::cerr + << "exception type " << name << " direct member " + << i.name << " uses an invalid identifier" + << std::endl; + std::exit(EXIT_FAILURE); + } + } + } + break; + case unoidl::Entity::SORT_INTERFACE_TYPE: + if (!entA.is()) { + rtl::Reference<unoidl::InterfaceTypeEntity> ent2B( + static_cast<unoidl::InterfaceTypeEntity *>(entB.get())); + for (auto & i: ent2B->getDirectAttributes()) { + if (!valid(i.name)) { + std::cerr + << "interface type " << name << " direct attribute " + << i.name << " uses an invalid identifier" + << std::endl; + std::exit(EXIT_FAILURE); + } + } + for (auto & i: ent2B->getDirectMethods()) { + if (!valid(i.name)) { + std::cerr + << "interface type " << name << " direct method " + << i.name << " uses an invalid identifier" + << std::endl; + std::exit(EXIT_FAILURE); + } + for (auto & j: i.parameters) { + if (!valid(j.name)) { + std::cerr + << "interface type " << name + << " direct method " << i.name << " parameter " + << j.name << " uses an invalid identifier" + << std::endl; + std::exit(EXIT_FAILURE); + } + } + } + } + break; + case unoidl::Entity::SORT_TYPEDEF: + case unoidl::Entity::SORT_INTERFACE_BASED_SINGLETON: + case unoidl::Entity::SORT_SERVICE_BASED_SINGLETON: + break; + case unoidl::Entity::SORT_CONSTANT_GROUP: + { + rtl::Reference<unoidl::ConstantGroupEntity> ent2B( + static_cast<unoidl::ConstantGroupEntity *>(entB.get())); + for (auto & i: ent2B->getMembers()) { + bool found = false; + if (entA.is()) { + rtl::Reference<unoidl::ConstantGroupEntity> ent2A( + static_cast<unoidl::ConstantGroupEntity *>( + entA.get())); + for (auto & j: ent2A->getMembers()) { + if (i.name == j.name) { + found = true; + break; + } + } + } + if (!(found || valid(i.name))) { + std::cerr + << "Constant group " << name << " member " + << i.name << " uses an invalid identifier" + << std::endl; + std::exit(EXIT_FAILURE); + } + } + break; + } + case unoidl::Entity::SORT_SINGLE_INTERFACE_BASED_SERVICE: + if (!entA.is()) { + rtl::Reference<unoidl::SingleInterfaceBasedServiceEntity> + ent2B( + static_cast<unoidl::SingleInterfaceBasedServiceEntity *>( + entB.get())); + for (auto & i: ent2B->getConstructors()) { + if (!valid(i.name)) { + std::cerr + << "single-interface--based service " << name + << " constructor " << i.name + << " uses an invalid identifier" << std::endl; + std::exit(EXIT_FAILURE); + } + for (auto & j: i.parameters) { + if (!valid(j.name)) { + std::cerr + << "single-interface--based service " << name + << " constructor " << i.name << " parameter " + << j.name << " uses an invalid identifier" + << std::endl; + std::exit(EXIT_FAILURE); + } + } + } + } + break; + case unoidl::Entity::SORT_ACCUMULATION_BASED_SERVICE: + { + rtl::Reference<unoidl::AccumulationBasedServiceEntity> ent2B( + static_cast<unoidl::AccumulationBasedServiceEntity *>( + entB.get())); + std::vector<unoidl::AccumulationBasedServiceEntity::Property>::size_type + n(entA.is() + ? (static_cast<unoidl::AccumulationBasedServiceEntity *>( + entA.get()) + ->getDirectProperties().size()) + : 0); + assert(n <= ent2B->getDirectProperties().size()); + for (auto i(ent2B->getDirectProperties().begin() +n); + i != ent2B->getDirectProperties().end(); ++i) + { + if (!valid(i->name)) { + std::cerr + << "accumulation-based service " << name + << " direct property " << i->name + << " uses an invalid identifier" << std::endl; + std::exit(EXIT_FAILURE); + } + } + break; + } + } + } +} + +} + +SAL_IMPLEMENT_MAIN() { + try { + sal_uInt32 args = rtl_getAppCommandArgCount(); + rtl::Reference<unoidl::Manager> mgr[2]; + mgr[0] = new unoidl::Manager; + mgr[1] = new unoidl::Manager; + rtl::Reference<unoidl::Provider> prov[2]; + int side = 0; + bool ignoreUnpublished = false; + for (sal_uInt32 i = 0; i != args; ++i) { + bool delimiter = false; + OUString uri; + if (getArgument( + i, &ignoreUnpublished, side == 0 ? &delimiter : nullptr, + &uri)) + { + try { + prov[side] = mgr[side]->addProvider(uri); + } catch (unoidl::NoSuchFileException &) { + std::cerr + << "Input <" << uri << "> does not exist" << std::endl; + std::exit(EXIT_FAILURE); + } + } else if (delimiter) { + side = 1; + } + } + if (side == 0 || !(prov[0].is() && prov[1].is())) { + badUsage(); + } + checkMap(prov[1], u"", prov[0]->createRootCursor(), ignoreUnpublished); + checkIds(prov[0], u"", prov[1]->createRootCursor()); + return EXIT_SUCCESS; + } catch (unoidl::FileFormatException & e1) { + std::cerr + << "Bad input <" << e1.getUri() << ">: " << e1.getDetail() + << std::endl; + std::exit(EXIT_FAILURE); + } catch (std::exception & e1) { + std::cerr << "Failure: " << e1.what() << std::endl; + std::exit(EXIT_FAILURE); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |