summaryrefslogtreecommitdiff
path: root/unoidl
diff options
context:
space:
mode:
authorStephan Bergmann <sbergman@redhat.com>2013-11-25 17:25:08 +0100
committerStephan Bergmann <sbergman@redhat.com>2013-11-25 17:27:36 +0100
commitf16aa10d1a0f8ae69fdd617f054e6bfe2a063517 (patch)
treeafb641c9c8b4df5efb7760045ee3df25e7b36aaa /unoidl
parent592ad650350d5a7dda2b0729f109c0cfbaf98e6e (diff)
Fix unoidl sourceprovider interface base and member checks
...and enable tests shared with idlc Change-Id: I422b16c9b2636835d276cc2085cb640073894c97 (cherry picked from commit 454f3f72c5d7a6f92debb4e4756e330397d507e6)
Diffstat (limited to 'unoidl')
-rw-r--r--unoidl/CustomTarget_unoidl-write_test.mk91
-rw-r--r--unoidl/Module_unoidl.mk1
-rw-r--r--unoidl/source/sourceprovider-parser.y551
-rw-r--r--unoidl/source/sourceprovider-scanner.hxx78
4 files changed, 638 insertions, 83 deletions
diff --git a/unoidl/CustomTarget_unoidl-write_test.mk b/unoidl/CustomTarget_unoidl-write_test.mk
new file mode 100644
index 000000000000..22c25b0085c5
--- /dev/null
+++ b/unoidl/CustomTarget_unoidl-write_test.mk
@@ -0,0 +1,91 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_CustomTarget_CustomTarget,unoidl/unoidl-write_test))
+
+# this target is phony to run it every time
+.PHONY : $(call gb_CustomTarget_get_target,unoidl/unoidl-write_test)
+
+$(call gb_CustomTarget_get_target,unoidl/unoidl-write_test) : \
+ $(call gb_Executable_get_runtime_dependencies,unoidl-write) \
+ $(SRCDIR)/solenv/bin/exectest.pl \
+ $(SRCDIR)/idlc/test/parser/attribute.tests \
+ $(SRCDIR)/idlc/test/parser/constant.tests \
+ $(SRCDIR)/idlc/test/parser/constructor.tests \
+ $(SRCDIR)/idlc/test/parser/interfaceinheritance.tests \
+ $(SRCDIR)/idlc/test/parser/methodoverload.tests \
+ $(SRCDIR)/idlc/test/parser/polystruct.tests \
+ $(SRCDIR)/idlc/test/parser/published.tests \
+ $(SRCDIR)/idlc/test/parser/struct.tests \
+ $(SRCDIR)/idlc/test/parser/typedef.tests \
+ | $(call gb_CustomTarget_get_workdir,unoidl/unoidl-write_test)/.dir
+ $(call gb_Helper_abbreviate_dirs,( \
+ $(PERL) $(SRCDIR)/solenv/bin/exectest.pl \
+ $(SRCDIR)/idlc/test/parser/attribute.tests \
+ $(call gb_CustomTarget_get_workdir,unoidl/unoidl-write_test)/in.idl \
+ 1 $(call gb_Executable_get_command,unoidl-write) $(SRCDIR)/udkapi \
+ {} \
+ $(call gb_CustomTarget_get_workdir,unoidl/unoidl-write_test)/out.rdb \
+ && $(PERL) $(SRCDIR)/solenv/bin/exectest.pl \
+ $(SRCDIR)/idlc/test/parser/constant.tests \
+ $(call gb_CustomTarget_get_workdir,unoidl/unoidl-write_test)/in.idl \
+ 1 $(call gb_Executable_get_command,unoidl-write) $(SRCDIR)/udkapi \
+ {} \
+ $(call gb_CustomTarget_get_workdir,unoidl/unoidl-write_test)/out.rdb \
+ && $(PERL) $(SRCDIR)/solenv/bin/exectest.pl \
+ $(SRCDIR)/idlc/test/parser/constructor.tests \
+ $(call gb_CustomTarget_get_workdir,unoidl/unoidl-write_test)/in.idl \
+ 1 $(call gb_Executable_get_command,unoidl-write) $(SRCDIR)/udkapi \
+ {} \
+ $(call gb_CustomTarget_get_workdir,unoidl/unoidl-write_test)/out.rdb \
+ && $(PERL) $(SRCDIR)/solenv/bin/exectest.pl \
+ $(SRCDIR)/idlc/test/parser/interfaceinheritance.tests \
+ $(call gb_CustomTarget_get_workdir,unoidl/unoidl-write_test)/in.idl \
+ 1 $(call gb_Executable_get_command,unoidl-write) $(SRCDIR)/udkapi \
+ {} \
+ $(call gb_CustomTarget_get_workdir,unoidl/unoidl-write_test)/out.rdb \
+ && $(PERL) $(SRCDIR)/solenv/bin/exectest.pl \
+ $(SRCDIR)/idlc/test/parser/methodoverload.tests \
+ $(call gb_CustomTarget_get_workdir,unoidl/unoidl-write_test)/in.idl \
+ 1 $(call gb_Executable_get_command,unoidl-write) $(SRCDIR)/udkapi \
+ {} \
+ $(call gb_CustomTarget_get_workdir,unoidl/unoidl-write_test)/out.rdb \
+ && $(PERL) $(SRCDIR)/solenv/bin/exectest.pl \
+ $(SRCDIR)/idlc/test/parser/oldstyle.tests \
+ $(call gb_CustomTarget_get_workdir,unoidl/unoidl-write_test)/in.idl \
+ 1 $(call gb_Executable_get_command,unoidl-write) $(SRCDIR)/udkapi \
+ {} \
+ $(call gb_CustomTarget_get_workdir,unoidl/unoidl-write_test)/out.rdb \
+ && $(PERL) $(SRCDIR)/solenv/bin/exectest.pl \
+ $(SRCDIR)/idlc/test/parser/polystruct.tests \
+ $(call gb_CustomTarget_get_workdir,unoidl/unoidl-write_test)/in.idl \
+ 1 $(call gb_Executable_get_command,unoidl-write) $(SRCDIR)/udkapi \
+ {} \
+ $(call gb_CustomTarget_get_workdir,unoidl/unoidl-write_test)/out.rdb \
+ && $(PERL) $(SRCDIR)/solenv/bin/exectest.pl \
+ $(SRCDIR)/idlc/test/parser/published.tests \
+ $(call gb_CustomTarget_get_workdir,unoidl/unoidl-write_test)/in.idl \
+ 1 $(call gb_Executable_get_command,unoidl-write) $(SRCDIR)/udkapi \
+ {} \
+ $(call gb_CustomTarget_get_workdir,unoidl/unoidl-write_test)/out.rdb \
+ && $(PERL) $(SRCDIR)/solenv/bin/exectest.pl \
+ $(SRCDIR)/idlc/test/parser/struct.tests \
+ $(call gb_CustomTarget_get_workdir,unoidl/unoidl-write_test)/in.idl \
+ 1 $(call gb_Executable_get_command,unoidl-write) $(SRCDIR)/udkapi \
+ {} \
+ $(call gb_CustomTarget_get_workdir,unoidl/unoidl-write_test)/out.rdb \
+ && $(PERL) $(SRCDIR)/solenv/bin/exectest.pl \
+ $(SRCDIR)/idlc/test/parser/typedef.tests \
+ $(call gb_CustomTarget_get_workdir,unoidl/unoidl-write_test)/in.idl \
+ 1 $(call gb_Executable_get_command,unoidl-write) $(SRCDIR)/udkapi \
+ {} \
+ $(call gb_CustomTarget_get_workdir,unoidl/unoidl-write_test)/out.rdb) \
+ > $@.log 2>&1 || (cat $@.log && false))
+
+# vim: set noet sw=4 ts=4:
diff --git a/unoidl/Module_unoidl.mk b/unoidl/Module_unoidl.mk
index e377ba8162c3..0136485660a8 100644
--- a/unoidl/Module_unoidl.mk
+++ b/unoidl/Module_unoidl.mk
@@ -16,6 +16,7 @@ $(eval $(call gb_Module_add_targets,unoidl, \
))
$(eval $(call gb_Module_add_targets_for_build,unoidl, \
+ CustomTarget_unoidl-write_test \
Executable_unoidl-check \
Executable_unoidl-write \
))
diff --git a/unoidl/source/sourceprovider-parser.y b/unoidl/source/sourceprovider-parser.y
index e377ac4cf9d9..f7f022fa0461 100644
--- a/unoidl/source/sourceprovider-parser.y
+++ b/unoidl/source/sourceprovider-parser.y
@@ -316,7 +316,7 @@ Found findEntity(
YYLTYPE location, yyscan_t yyscanner,
unoidl::detail::SourceProviderScannerData * data,
bool resolveInterfaceDefinitions, OUString * name,
- unoidl::detail::SourceProviderEntity const ** entity,
+ unoidl::detail::SourceProviderEntity const ** entity, bool * typedefed,
unoidl::detail::SourceProviderType * typedefedType)
{
//TODO: avoid recursion
@@ -339,6 +339,9 @@ Found findEntity(
// fall through
case unoidl::detail::SourceProviderEntity::KIND_EXTERNAL:
if (e->entity->getSort() == unoidl::Entity::SORT_TYPEDEF) {
+ if (typedefed != 0) {
+ *typedefed = true;
+ }
if (data->publishedContext
&& !static_cast<unoidl::TypedefEntity *>(
e->entity.get())->isPublished())
@@ -413,7 +416,7 @@ Found findEntity(
switch (
findEntity(
location, yyscanner, data, false,
- &argName, &argEnt, &argType))
+ &argName, &argEnt, 0, &argType))
{
case FOUND_ERROR:
return FOUND_ERROR;
@@ -1088,7 +1091,7 @@ plainStructDefn:
if ($5 != 0) {
baseName = convertName($5);
unoidl::detail::SourceProviderEntity const * p;
- if (findEntity(@5, yyscanner, data, false, &baseName, &p, 0)
+ if (findEntity(@5, yyscanner, data, false, &baseName, &p, 0, 0)
== FOUND_ERROR)
{
YYERROR;
@@ -1219,7 +1222,7 @@ exceptionDefn:
if ($5 != 0) {
baseName = convertName($5);
unoidl::detail::SourceProviderEntity const * p;
- if (findEntity(@5, yyscanner, data, false, &baseName, &p, 0)
+ if (findEntity(@5, yyscanner, data, false, &baseName, &p, 0, 0)
== FOUND_ERROR)
{
YYERROR;
@@ -1371,7 +1374,8 @@ structMember:
break;
}
unoidl::detail::SourceProviderEntity const * p;
- if (findEntity(@2, yyscanner, data, false, &baseName, &p, 0)
+ if (findEntity(
+ @2, yyscanner, data, false, &baseName, &p, 0, 0)
== FOUND_ERROR)
{
YYERROR;
@@ -1471,7 +1475,7 @@ structMember:
}
unoidl::detail::SourceProviderEntity const * p;
if (findEntity(
- @2, yyscanner, data, false, &baseName, &p, 0)
+ @2, yyscanner, data, false, &baseName, &p, 0, 0)
== FOUND_ERROR)
{
YYERROR;
@@ -1511,7 +1515,7 @@ interfaceDefn:
if ($5 != 0) {
baseName = convertName($5);
unoidl::detail::SourceProviderEntity const * p;
- if (findEntity(@5, yyscanner, data, true, &baseName, &p, 0)
+ if (findEntity(@5, yyscanner, data, true, &baseName, &p, 0, 0)
== FOUND_ERROR)
{
YYERROR;
@@ -1558,25 +1562,35 @@ interfaceDefn:
break;
}
}
- data->entities[data->currentName] = unoidl::detail::SourceProviderEntity(
+ rtl::Reference<unoidl::detail::SourceProviderInterfaceTypeEntityPad> pad(
new unoidl::detail::SourceProviderInterfaceTypeEntityPad(
- $2, baseName, baseEnt));
+ $2, baseEnt.is()));
+ if (baseEnt.is()
+ && !pad->addDirectBase(
+ @4, yyscanner, data,
+ unoidl::detail::SourceProviderInterfaceTypeEntityPad::DirectBase(
+ baseName, baseEnt, std::vector<OUString>()),
+ false))
+ {
+ YYERROR;
+ }
+ data->entities[data->currentName] = unoidl::detail::SourceProviderEntity(
+ pad.get());
}
'{' interfaceMembers '}' ';'
{
- //TODO: check direct member uniqueness
unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
unoidl::detail::SourceProviderEntity * ent = getCurrentEntity(data);
unoidl::detail::SourceProviderInterfaceTypeEntityPad * pad =
dynamic_cast<unoidl::detail::SourceProviderInterfaceTypeEntityPad *>(
ent->pad.get());
assert(pad != 0);
- if (pad->mandatoryBases.empty()
+ if (pad->directMandatoryBases.empty()
&& data->currentName != "com.sun.star.uno.XInterface")
{
OUString base(".com.sun.star.uno.XInterface");
unoidl::detail::SourceProviderEntity const * p;
- if (findEntity(@4, yyscanner, data, true, &base, &p, 0)
+ if (findEntity(@4, yyscanner, data, true, &base, &p, 0, 0)
== FOUND_ERROR)
{
YYERROR;
@@ -1591,29 +1605,35 @@ interfaceDefn:
+ " does not resolve to an existing interface type"));
YYERROR;
}
- pad->mandatoryBases.push_back(
- unoidl::detail::SourceProviderInterfaceTypeEntityPad::Base(
- base,
- static_cast<unoidl::InterfaceTypeEntity *>(p->entity.get()),
- std::vector<OUString>()));
+ if (!pad->addDirectBase(
+ @3, yyscanner, data,
+ unoidl::detail::SourceProviderInterfaceTypeEntityPad::DirectBase(
+ base,
+ static_cast<unoidl::InterfaceTypeEntity *>(
+ p->entity.get()),
+ std::vector<OUString>()),
+ false))
+ {
+ YYERROR;
+ }
}
std::vector<unoidl::AnnotatedReference> mbases;
- for (std::vector<unoidl::detail::SourceProviderInterfaceTypeEntityPad::Base>::const_iterator
- i(pad->mandatoryBases.begin());
- i != pad->mandatoryBases.end(); ++i)
+ for (std::vector<unoidl::detail::SourceProviderInterfaceTypeEntityPad::DirectBase>::const_iterator
+ i(pad->directMandatoryBases.begin());
+ i != pad->directMandatoryBases.end(); ++i)
{
mbases.push_back(unoidl::AnnotatedReference(i->name, i->annotations));
}
std::vector<unoidl::AnnotatedReference> obases;
- for (std::vector<unoidl::detail::SourceProviderInterfaceTypeEntityPad::Base>::const_iterator
- i(pad->optionalBases.begin());
- i != pad->optionalBases.end(); ++i)
+ for (std::vector<unoidl::detail::SourceProviderInterfaceTypeEntityPad::DirectBase>::const_iterator
+ i(pad->directOptionalBases.begin());
+ i != pad->directOptionalBases.end(); ++i)
{
obases.push_back(unoidl::AnnotatedReference(i->name, i->annotations));
}
ent->entity = new unoidl::InterfaceTypeEntity(
- pad->isPublished(), mbases, obases, pad->attributes, pad->methods,
- annotations($1));
+ pad->isPublished(), mbases, obases, pad->directAttributes,
+ pad->directMethods, annotations($1));
ent->pad.clear();
clearCurrentState(data);
}
@@ -1651,8 +1671,12 @@ interfaceBase:
YYERROR;
}
bool opt = ($2 & unoidl::detail::FLAG_OPTIONAL) != 0;
+ OUString orgName(name);
unoidl::detail::SourceProviderEntity const * p;
- if (findEntity(@4, yyscanner, data, true, &name, &p, 0) == FOUND_ERROR) {
+ bool typedefed = false;
+ if (findEntity(@4, yyscanner, data, true, &name, &p, &typedefed, 0)
+ == FOUND_ERROR)
+ {
YYERROR;
}
if (p == 0 || !p->entity.is()
@@ -1664,22 +1688,30 @@ interfaceBase:
+ " does not resolve to an existing interface type"));
YYERROR;
}
- if (data->publishedContext
- && !(static_cast<unoidl::InterfaceTypeEntity *>(p->entity.get())
- ->isPublished()))
- {
+ if (typedefed) {
+ error(
+ @4, yyscanner,
+ ("interface type " + data->currentName + " direct base " + orgName
+ + " is a typedef"));
+ YYERROR;
+ }
+ rtl::Reference<unoidl::InterfaceTypeEntity> ent(
+ static_cast<unoidl::InterfaceTypeEntity *>(p->entity.get()));
+ if (data->publishedContext && !ent->isPublished()) {
error(
@4, yyscanner,
("published interface type " + data->currentName + " direct base "
+ name + " is unpublished"));
YYERROR;
}
- //TODO: check uniqueness (incl. that opt base != XInterface)
- (opt ? pad->optionalBases : pad->mandatoryBases).push_back(
- unoidl::detail::SourceProviderInterfaceTypeEntityPad::Base(
- name,
- static_cast<unoidl::InterfaceTypeEntity *>(p->entity.get()),
- annotations($1)));
+ if (!pad->addDirectBase(
+ @4, yyscanner, data,
+ unoidl::detail::SourceProviderInterfaceTypeEntityPad::DirectBase(
+ name, ent, annotations($1)),
+ opt))
+ {
+ YYERROR;
+ }
}
;
@@ -1722,7 +1754,10 @@ interfaceAttribute:
rtl::Reference<unoidl::detail::SourceProviderInterfaceTypeEntityPad> pad(
getCurrentPad<unoidl::detail::SourceProviderInterfaceTypeEntityPad>(
data));
- pad->attributes.push_back(
+ if (!pad->addDirectMember(@4, yyscanner, data, id)) {
+ YYERROR;
+ }
+ pad->directAttributes.push_back(
unoidl::InterfaceTypeEntity::Attribute(
id, t.getName(), ($2 & unoidl::detail::FLAG_BOUND) != 0,
($2 & unoidl::detail::FLAG_READONLY) != 0,
@@ -1757,8 +1792,8 @@ attributeAccessDecl:
rtl::Reference<unoidl::detail::SourceProviderInterfaceTypeEntityPad>
pad(getCurrentPad<unoidl::detail::SourceProviderInterfaceTypeEntityPad>(
data));
- assert(!pad->attributes.empty());
- pad->attributes.back().getExceptions = *$2;
+ assert(!pad->directAttributes.empty());
+ pad->directAttributes.back().getExceptions = *$2;
delete $2;
$$ = unoidl::detail::ACCESS_DECL_GET;
}
@@ -1768,14 +1803,15 @@ attributeAccessDecl:
rtl::Reference<unoidl::detail::SourceProviderInterfaceTypeEntityPad>
pad(getCurrentPad<unoidl::detail::SourceProviderInterfaceTypeEntityPad>(
data));
- assert(!pad->attributes.empty());
- pad->attributes.back().setExceptions = *$2;
+ assert(!pad->directAttributes.empty());
+ pad->directAttributes.back().setExceptions = *$2;
delete $2;
- if (pad->attributes.back().readOnly) {
+ if (pad->directAttributes.back().readOnly) {
error(
@1, yyscanner,
("interface type " + data->currentName
- + " direct read-only attribute " + pad->attributes.back().name
+ + " direct read-only attribute "
+ + pad->directAttributes.back().name
+ " cannot have set access declaration"));
YYERROR;
}
@@ -1800,7 +1836,10 @@ interfaceMethod:
rtl::Reference<unoidl::detail::SourceProviderInterfaceTypeEntityPad> pad(
getCurrentPad<unoidl::detail::SourceProviderInterfaceTypeEntityPad>(
data));
- pad->methods.push_back(
+ if (!pad->addDirectMember(@3, yyscanner, data, id)) {
+ YYERROR;
+ }
+ pad->directMethods.push_back(
unoidl::InterfaceTypeEntity::Method(
id, t.getName(),
std::vector<unoidl::InterfaceTypeEntity::Method::Parameter>(),
@@ -1814,8 +1853,8 @@ interfaceMethod:
rtl::Reference<unoidl::detail::SourceProviderInterfaceTypeEntityPad>
pad(getCurrentPad<unoidl::detail::SourceProviderInterfaceTypeEntityPad>(
data));
- assert(!pad->methods.empty());
- pad->methods.back().exceptions = *$8;
+ assert(!pad->directMethods.empty());
+ pad->directMethods.back().exceptions = *$8;
delete $8;
}
}
@@ -1841,34 +1880,34 @@ methodParam:
rtl::Reference<unoidl::detail::SourceProviderInterfaceTypeEntityPad>
pad(getCurrentPad<unoidl::detail::SourceProviderInterfaceTypeEntityPad>(
data));
- assert(!pad->methods.empty());
+ assert(!pad->directMethods.empty());
switch (t.type) {
case unoidl::detail::SourceProviderType::TYPE_VOID:
case unoidl::detail::SourceProviderType::TYPE_EXCEPTION:
error(
@4, yyscanner,
("illegal interface type " + data->currentName
- + " direct method " + pad->methods.back().name + " parameter "
- + id + " type"));
+ + " direct method " + pad->directMethods.back().name
+ + " parameter " + id + " type"));
YYERROR;
break;
default:
break;
}
for (std::vector<unoidl::InterfaceTypeEntity::Method::Parameter>::iterator
- i(pad->methods.back().parameters.begin());
- i != pad->methods.back().parameters.end(); ++i)
+ i(pad->directMethods.back().parameters.begin());
+ i != pad->directMethods.back().parameters.end(); ++i)
{
if (id == i->name) {
error(
@5, yyscanner,
("interface type " + data->currentName + " direct method "
- + pad->methods.back().name + " parameter " + id
+ + pad->directMethods.back().name + " parameter " + id
+ " has same identifier as another parameter"));
YYERROR;
}
}
- pad->methods.back().parameters.push_back(
+ pad->directMethods.back().parameters.push_back(
unoidl::InterfaceTypeEntity::Method::Parameter(id, t.getName(), $2));
}
;
@@ -2280,7 +2319,9 @@ singleInterfaceBasedServiceDefn:
convertToCurrentName(data, $4);
OUString base(convertName($5));
unoidl::detail::SourceProviderEntity const * p;
- if (findEntity(@5, yyscanner, data, false, &base, &p, 0) == FOUND_ERROR) {
+ if (findEntity(@5, yyscanner, data, false, &base, &p, 0, 0)
+ == FOUND_ERROR)
+ {
YYERROR;
}
bool ifcBase = false;
@@ -2607,7 +2648,9 @@ serviceBase:
}
bool opt = ($2 & unoidl::detail::FLAG_OPTIONAL) != 0;
unoidl::detail::SourceProviderEntity const * p;
- if (findEntity(@4, yyscanner, data, false, &name, &p, 0) == FOUND_ERROR) {
+ if (findEntity(@4, yyscanner, data, false, &name, &p, 0, 0)
+ == FOUND_ERROR)
+ {
YYERROR;
}
if (p == 0 || !p->entity.is()
@@ -2653,7 +2696,9 @@ serviceInterfaceBase:
}
bool opt = ($2 & unoidl::detail::FLAG_OPTIONAL) != 0;
unoidl::detail::SourceProviderEntity const * p;
- if (findEntity(@4, yyscanner, data, false, &name, &p, 0) == FOUND_ERROR) {
+ if (findEntity(@4, yyscanner, data, false, &name, &p, 0, 0)
+ == FOUND_ERROR)
+ {
YYERROR;
}
bool ifcBase = false;
@@ -2794,7 +2839,9 @@ interfaceBasedSingletonDefn:
OUString name(convertToFullName(data, $4));
OUString base(convertName($5));
unoidl::detail::SourceProviderEntity const * p;
- if (findEntity(@5, yyscanner, data, false, &base, &p, 0) == FOUND_ERROR) {
+ if (findEntity(@5, yyscanner, data, false, &base, &p, 0, 0)
+ == FOUND_ERROR)
+ {
YYERROR;
}
bool ifcBase = false;
@@ -2860,7 +2907,9 @@ serviceBasedSingletonDefn:
OUString name(convertToFullName(data, $4));
OUString base(convertName($7));
unoidl::detail::SourceProviderEntity const * p;
- if (findEntity(@7, yyscanner, data, false, &base, &p, 0) == FOUND_ERROR) {
+ if (findEntity(@7, yyscanner, data, false, &base, &p, 0, 0)
+ == FOUND_ERROR)
+ {
YYERROR;
}
if (p == 0
@@ -2922,7 +2971,9 @@ exceptions:
unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
OUString name(convertName($3));
unoidl::detail::SourceProviderEntity const * p;
- if (findEntity(@3, yyscanner, data, false, &name, &p, 0) == FOUND_ERROR) {
+ if (findEntity(@3, yyscanner, data, false, &name, &p, 0, 0)
+ == FOUND_ERROR)
+ {
delete $1; /* see commented-out %destructor above */
YYERROR;
}
@@ -2960,7 +3011,9 @@ exceptions:
unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
OUString name(convertName($1));
unoidl::detail::SourceProviderEntity const * p;
- if (findEntity(@1, yyscanner, data, false, &name, &p, 0) == FOUND_ERROR) {
+ if (findEntity(@1, yyscanner, data, false, &name, &p, 0, 0)
+ == FOUND_ERROR)
+ {
YYERROR;
}
if (p == 0
@@ -3479,7 +3532,7 @@ primaryExpr:
} else {
OUString scope(name.copy(0, i));
unoidl::detail::SourceProviderEntity const * ent;
- if (findEntity(@1, yyscanner, data, false, &scope, &ent, 0)
+ if (findEntity(@1, yyscanner, data, false, &scope, &ent, 0, 0)
== FOUND_ERROR)
{
YYERROR;
@@ -3720,7 +3773,7 @@ type:
if (!done) {
unoidl::detail::SourceProviderEntity const * ent;
unoidl::detail::SourceProviderType t;
- switch (findEntity(@1, yyscanner, data, false, &name, &ent, &t)) {
+ switch (findEntity(@1, yyscanner, data, false, &name, &ent, 0, &t)) {
case FOUND_ERROR:
YYERROR;
break;
@@ -3874,7 +3927,8 @@ type:
std::vector<unoidl::detail::SourceProviderType> args(*$3);
delete $3;
unoidl::detail::SourceProviderEntity const * ent;
- if (findEntity(@1, yyscanner, data, false, &name, &ent, 0) == FOUND_ERROR)
+ if (findEntity(@1, yyscanner, data, false, &name, &ent, 0, 0)
+ == FOUND_ERROR)
{
YYERROR;
}
@@ -4041,6 +4095,377 @@ bool SourceProviderType::equals(SourceProviderType const & other) const {
return true;
}
+bool SourceProviderInterfaceTypeEntityPad::addDirectBase(
+ YYLTYPE location, yyscan_t yyscanner, SourceProviderScannerData * data,
+ DirectBase const & base, bool optional)
+{
+ std::set<OUString> seen;
+ if (!(checkBaseClashes(
+ location, yyscanner, data, base.name, base.entity, true, optional,
+ optional, &seen)
+ && addBase(
+ location, yyscanner, data, base.name, base.name, base.entity,
+ true, optional)))
+ {
+ return false;
+ }
+ if (optional) {
+ addOptionalBaseMembers(
+ location, yyscanner, data, base.name, base.entity);
+ }
+ //TODO: check that opt base != XInterface
+ (optional ? directOptionalBases : directMandatoryBases).push_back(base);
+ return true;
+}
+
+bool SourceProviderInterfaceTypeEntityPad::addDirectMember(
+ YYLTYPE location, yyscan_t yyscanner, SourceProviderScannerData * data,
+ OUString const & name)
+{
+ assert(data != 0);
+ if (!checkMemberClashes(location, yyscanner, data, "", name, true)) {
+ return false;
+ }
+ allMembers.insert(
+ std::map<OUString, Member>::value_type(
+ name, Member(data->currentName)));
+ return true;
+}
+
+bool SourceProviderInterfaceTypeEntityPad::checkBaseClashes(
+ YYLTYPE location, yyscan_t yyscanner, SourceProviderScannerData * data,
+ OUString const & name,
+ rtl::Reference<unoidl::InterfaceTypeEntity> const & entity, bool direct,
+ bool optional, bool outerOptional, std::set<OUString> * seen) const
+{
+ assert(data != 0);
+ assert(entity.is());
+ assert(seen != 0);
+ if (direct || optional || seen->insert(name).second) {
+ std::map<OUString, BaseKind>::const_iterator i(allBases.find(name));
+ if (i != allBases.end()) {
+ switch (i->second) {
+ case BASE_INDIRECT_OPTIONAL:
+ if (direct && optional) {
+ error(
+ location, yyscanner,
+ ("interface type " + data->currentName
+ + " duplicate base " + name));
+ return false;
+ }
+ break;
+ case BASE_DIRECT_OPTIONAL:
+ if (direct || !outerOptional) {
+ error(
+ location, yyscanner,
+ ("interface type " + data->currentName
+ + " duplicate base " + name));
+ return false;
+ }
+ return true;
+ case BASE_INDIRECT_MANDATORY:
+ if (direct) {
+ error(
+ location, yyscanner,
+ ("interface type " + data->currentName
+ + " duplicate base " + name));
+ return false;
+ }
+ return true;
+ case BASE_DIRECT_MANDATORY:
+ if (direct || (!optional && !outerOptional)) {
+ error(
+ location, yyscanner,
+ ("interface type " + data->currentName
+ + " duplicate base " + name));
+ return false;
+ }
+ return true;
+ }
+ }
+ if (direct || !optional) {
+ for (std::vector<unoidl::AnnotatedReference>::const_iterator j(
+ entity->getDirectMandatoryBases().begin());
+ j != entity->getDirectMandatoryBases().end(); ++j)
+ {
+ OUString n("." + j->name);
+ unoidl::detail::SourceProviderEntity const * p;
+ if (findEntity(location, yyscanner, data, true, &n, &p, 0, 0)
+ == FOUND_ERROR)
+ {
+ return false;
+ }
+ if (p == 0 || !p->entity.is()
+ || (p->entity->getSort()
+ != unoidl::Entity::SORT_INTERFACE_TYPE))
+ {
+ error(
+ location, yyscanner,
+ ("inconsistent type manager: interface type "
+ + data->currentName + " base " + n
+ + " does not resolve to an existing interface type"));
+ return false;
+ }
+ if (!checkBaseClashes(
+ location, yyscanner, data, n,
+ static_cast<unoidl::InterfaceTypeEntity *>(
+ p->entity.get()),
+ false, false, outerOptional, seen))
+ {
+ return false;
+ }
+ }
+ for (std::vector<unoidl::AnnotatedReference>::const_iterator j(
+ entity->getDirectOptionalBases().begin());
+ j != entity->getDirectOptionalBases().end(); ++j)
+ {
+ OUString n("." + j->name);
+ unoidl::detail::SourceProviderEntity const * p;
+ if (findEntity(location, yyscanner, data, true, &n, &p, 0, 0)
+ == FOUND_ERROR)
+ {
+ return false;
+ }
+ if (p == 0 || !p->entity.is()
+ || (p->entity->getSort()
+ != unoidl::Entity::SORT_INTERFACE_TYPE))
+ {
+ error(
+ location, yyscanner,
+ ("inconsistent type manager: interface type "
+ + data->currentName + " base " + n
+ + " does not resolve to an existing interface type"));
+ return false;
+ }
+ if (!checkBaseClashes(
+ location, yyscanner, data, n,
+ static_cast<unoidl::InterfaceTypeEntity *>(
+ p->entity.get()),
+ false, true, outerOptional, seen))
+ {
+ return false;
+ }
+ }
+ for (std::vector<unoidl::InterfaceTypeEntity::Attribute>::const_iterator
+ j(entity->getDirectAttributes().begin());
+ j != entity->getDirectAttributes().end(); ++j)
+ {
+ if (!checkMemberClashes(
+ location, yyscanner, data, name, j->name,
+ !outerOptional))
+ {
+ return false;
+ }
+ }
+ for (std::vector<unoidl::InterfaceTypeEntity::Method>::const_iterator
+ j(entity->getDirectMethods().begin());
+ j != entity->getDirectMethods().end(); ++j)
+ {
+ if (!checkMemberClashes(
+ location, yyscanner, data, name, j->name,
+ !outerOptional))
+ {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool SourceProviderInterfaceTypeEntityPad::checkMemberClashes(
+ YYLTYPE location, yyscan_t yyscanner, SourceProviderScannerData * data,
+ OUString const & interfaceName, OUString const & memberName,
+ bool checkOptional) const
+{
+ std::map<OUString, Member>::const_iterator i(allMembers.find(memberName));
+ if (i != allMembers.end()) {
+ if (!i->second.mandatory.isEmpty()) {
+ // For a direct member, interfaceName will be empty, so this will
+ // catch two direct members with the same name:
+ if (i->second.mandatory != interfaceName) {
+ error(
+ location, yyscanner,
+ ("interface type " + data->currentName
+ + " duplicate member " + memberName));
+ return false;
+ }
+ } else if (checkOptional) {
+ for (std::set<OUString>::const_iterator j(
+ i->second.optional.begin());
+ j != i->second.optional.end(); ++j)
+ {
+ if (*j != interfaceName) {
+ error(
+ location, yyscanner,
+ ("interface type " + data->currentName
+ + " duplicate member " + memberName));
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool SourceProviderInterfaceTypeEntityPad::addBase(
+ YYLTYPE location, yyscan_t yyscanner, SourceProviderScannerData * data,
+ OUString const & directBaseName, OUString const & name,
+ rtl::Reference<unoidl::InterfaceTypeEntity> const & entity, bool direct,
+ bool optional)
+{
+ assert(data != 0);
+ assert(entity.is());
+ BaseKind kind = optional
+ ? direct ? BASE_DIRECT_OPTIONAL : BASE_INDIRECT_OPTIONAL
+ : direct ? BASE_DIRECT_MANDATORY : BASE_INDIRECT_MANDATORY;
+ std::pair<std::map<OUString, BaseKind>::iterator, bool> p(
+ allBases.insert(
+ std::map<OUString, BaseKind>::value_type(name, kind)));
+ bool seen = !p.second && p.first->second >= BASE_INDIRECT_MANDATORY;
+ if (!p.second && kind > p.first->second) {
+ p.first->second = kind;
+ }
+ if (!optional && !seen) {
+ for (std::vector<unoidl::AnnotatedReference>::const_iterator i(
+ entity->getDirectMandatoryBases().begin());
+ i != entity->getDirectMandatoryBases().end(); ++i)
+ {
+ OUString n("." + i->name);
+ unoidl::detail::SourceProviderEntity const * q;
+ if (findEntity(location, yyscanner, data, true, &n, &q, 0, 0)
+ == FOUND_ERROR)
+ {
+ return false;
+ }
+ if (q == 0 || !q->entity.is()
+ || q->entity->getSort() != unoidl::Entity::SORT_INTERFACE_TYPE)
+ {
+ error(
+ location, yyscanner,
+ ("inconsistent type manager: interface type "
+ + data->currentName + " base " + n
+ + " does not resolve to an existing interface type"));
+ return false;
+ }
+ if (!addBase(
+ location, yyscanner, data, directBaseName, n,
+ static_cast<unoidl::InterfaceTypeEntity *>(q->entity.get()),
+ false, false))
+ {
+ return false;
+ }
+ }
+ for (std::vector<unoidl::AnnotatedReference>::const_iterator i(
+ entity->getDirectOptionalBases().begin());
+ i != entity->getDirectOptionalBases().end(); ++i)
+ {
+ OUString n("." + i->name);
+ unoidl::detail::SourceProviderEntity const * q;
+ if (findEntity(location, yyscanner, data, true, &n, &q, 0, 0)
+ == FOUND_ERROR)
+ {
+ return false;
+ }
+ if (q == 0 || !q->entity.is()
+ || q->entity->getSort() != unoidl::Entity::SORT_INTERFACE_TYPE)
+ {
+ error(
+ location, yyscanner,
+ ("inconsistent type manager: interface type "
+ + data->currentName + " base " + n
+ + " does not resolve to an existing interface type"));
+ return false;
+ }
+ if (!addBase(
+ location, yyscanner, data, directBaseName, n,
+ static_cast<unoidl::InterfaceTypeEntity *>(q->entity.get()),
+ false, true))
+ {
+ return false;
+ }
+ }
+ for (std::vector<unoidl::InterfaceTypeEntity::Attribute>::const_iterator
+ i(entity->getDirectAttributes().begin());
+ i != entity->getDirectAttributes().end(); ++i)
+ {
+ allMembers.insert(
+ std::map<OUString, Member>::value_type(i->name, Member(name)));
+ }
+ for (std::vector<unoidl::InterfaceTypeEntity::Method>::const_iterator i(
+ entity->getDirectMethods().begin());
+ i != entity->getDirectMethods().end(); ++i)
+ {
+ allMembers.insert(
+ std::map<OUString, Member>::value_type(i->name, Member(name)));
+ }
+ }
+ return true;
+}
+
+bool SourceProviderInterfaceTypeEntityPad::addOptionalBaseMembers(
+ YYLTYPE location, yyscan_t yyscanner, SourceProviderScannerData * data,
+ OUString const & name,
+ rtl::Reference<unoidl::InterfaceTypeEntity> const & entity)
+{
+ assert(entity.is());
+ for (std::vector<unoidl::AnnotatedReference>::const_iterator i(
+ entity->getDirectMandatoryBases().begin());
+ i != entity->getDirectMandatoryBases().end(); ++i)
+ {
+ OUString n("." + i->name);
+ unoidl::detail::SourceProviderEntity const * p;
+ if (findEntity(location, yyscanner, data, true, &n, &p, 0, 0)
+ == FOUND_ERROR)
+ {
+ return false;
+ }
+ if (p == 0 || !p->entity.is()
+ || p->entity->getSort() != unoidl::Entity::SORT_INTERFACE_TYPE)
+ {
+ error(
+ location, yyscanner,
+ ("inconsistent type manager: interface type "
+ + data->currentName + " base " + n
+ + " does not resolve to an existing interface type"));
+ return false;
+ }
+ if (!addOptionalBaseMembers(
+ location, yyscanner, data, n,
+ static_cast<unoidl::InterfaceTypeEntity *>(p->entity.get())))
+ {
+ return false;
+ }
+ }
+ for (std::vector<unoidl::InterfaceTypeEntity::Attribute>::const_iterator i(
+ entity->getDirectAttributes().begin());
+ i != entity->getDirectAttributes().end(); ++i)
+ {
+ Member & m(
+ allMembers.insert(
+ std::map<OUString, Member>::value_type(
+ i->name, Member("")))
+ .first->second);
+ if (m.mandatory.isEmpty()) {
+ m.optional.insert(name);
+ }
+ }
+ for (std::vector<unoidl::InterfaceTypeEntity::Method>::const_iterator i(
+ entity->getDirectMethods().begin());
+ i != entity->getDirectMethods().end(); ++i)
+ {
+ Member & m(
+ allMembers.insert(
+ std::map<OUString, Member>::value_type(
+ i->name, Member("")))
+ .first->second);
+ if (m.mandatory.isEmpty()) {
+ m.optional.insert(name);
+ }
+ }
+ return true;
+}
+
bool parse(OUString const & uri, SourceProviderScannerData * data) {
assert(data != 0);
oslFileHandle handle;
diff --git a/unoidl/source/sourceprovider-scanner.hxx b/unoidl/source/sourceprovider-scanner.hxx
index 5edd984efe51..14ac15421f08 100644
--- a/unoidl/source/sourceprovider-scanner.hxx
+++ b/unoidl/source/sourceprovider-scanner.hxx
@@ -14,6 +14,7 @@
#include <cassert>
#include <map>
+#include <set>
#include <vector>
#include "rtl/ref.hxx"
@@ -27,6 +28,8 @@
namespace unoidl { namespace detail {
+struct SourceProviderScannerData;
+
class SourceProviderEntityPad: public salhelper::SimpleReferenceObject {
public:
bool isPublished() const { return published_; }
@@ -103,41 +106,76 @@ private:
class SourceProviderInterfaceTypeEntityPad: public SourceProviderEntityPad {
public:
- struct Base {
- Base(
+ struct DirectBase {
+ DirectBase(
OUString const & theName,
rtl::Reference<unoidl::InterfaceTypeEntity> const & theEntity,
std::vector<OUString> const & theAnnotations):
name(theName), entity(theEntity), annotations(theAnnotations)
- {}
+ { assert(theEntity.is()); }
OUString name;
rtl::Reference<unoidl::InterfaceTypeEntity> entity;
std::vector<OUString> annotations;
};
- SourceProviderInterfaceTypeEntityPad(
- bool published, OUString singleBaseName,
- rtl::Reference<unoidl::InterfaceTypeEntity> const & singleBaseEntity):
- SourceProviderEntityPad(published),
- singleBase(!singleBaseName.isEmpty())
- {
- assert(singleBaseName.isEmpty() != (bool) singleBaseEntity.is());
- if (singleBase) {
- mandatoryBases.push_back(
- Base(
- singleBaseName, singleBaseEntity, std::vector<OUString>()));
- }
- }
+ enum BaseKind {
+ BASE_INDIRECT_OPTIONAL, BASE_DIRECT_OPTIONAL, BASE_INDIRECT_MANDATORY,
+ BASE_DIRECT_MANDATORY
+ };
+
+ struct Member {
+ OUString mandatory;
+ std::set<OUString> optional;
+
+ explicit Member(OUString theMandatory): mandatory(theMandatory) {}
+ };
+
+ SourceProviderInterfaceTypeEntityPad(bool published, bool theSingleBase):
+ SourceProviderEntityPad(published), singleBase(theSingleBase)
+ {}
+
+ bool addDirectBase(
+ YYLTYPE location, yyscan_t yyscanner, SourceProviderScannerData * data,
+ DirectBase const & base, bool optional);
+
+ bool addDirectMember(
+ YYLTYPE location, yyscan_t yyscanner, SourceProviderScannerData * data,
+ OUString const & name);
bool singleBase;
- std::vector<Base> mandatoryBases;
- std::vector<Base> optionalBases;
- std::vector<unoidl::InterfaceTypeEntity::Attribute> attributes;
- std::vector<unoidl::InterfaceTypeEntity::Method> methods;
+ std::vector<DirectBase> directMandatoryBases;
+ std::vector<DirectBase> directOptionalBases;
+ std::vector<unoidl::InterfaceTypeEntity::Attribute> directAttributes;
+ std::vector<unoidl::InterfaceTypeEntity::Method> directMethods;
+ std::map<OUString, BaseKind> allBases;
+ std::map<OUString, Member> allMembers;
private:
virtual ~SourceProviderInterfaceTypeEntityPad() throw () {}
+
+ bool checkBaseClashes(
+ YYLTYPE location, yyscan_t yyscanner, SourceProviderScannerData * data,
+ OUString const & name,
+ rtl::Reference<unoidl::InterfaceTypeEntity> const & entity,
+ bool direct, bool optional, bool outerOptional,
+ std::set<OUString> * seen) const;
+
+ bool checkMemberClashes(
+ YYLTYPE location, yyscan_t yyscanner, SourceProviderScannerData * data,
+ OUString const & interfaceName, OUString const & memberName,
+ bool checkOptional) const;
+
+ bool addBase(
+ YYLTYPE location, yyscan_t yyscanner, SourceProviderScannerData * data,
+ OUString const & directBaseName, OUString const & name,
+ rtl::Reference<unoidl::InterfaceTypeEntity> const & entity, bool direct,
+ bool optional);
+
+ bool addOptionalBaseMembers(
+ YYLTYPE location, yyscan_t yyscanner, SourceProviderScannerData * data,
+ OUString const & name,
+ rtl::Reference<unoidl::InterfaceTypeEntity> const & entity);
};
class SourceProviderConstantGroupEntityPad: public SourceProviderEntityPad {