diff options
author | Stephan Bergmann <sbergman@redhat.com> | 2013-11-25 17:25:08 +0100 |
---|---|---|
committer | Stephan Bergmann <sbergman@redhat.com> | 2013-11-25 17:26:17 +0100 |
commit | 454f3f72c5d7a6f92debb4e4756e330397d507e6 (patch) | |
tree | 0458a867390cee31e00ebba7d1246b058341de81 /unoidl | |
parent | e00562d9835bd82d74ef0301ea7425ff769915df (diff) |
Fix unoidl sourceprovider interface base and member checks
...and enable tests shared with idlc
Change-Id: I422b16c9b2636835d276cc2085cb640073894c97
Diffstat (limited to 'unoidl')
-rw-r--r-- | unoidl/CustomTarget_unoidl-write_test.mk | 91 | ||||
-rw-r--r-- | unoidl/Module_unoidl.mk | 1 | ||||
-rw-r--r-- | unoidl/source/sourceprovider-parser.y | 551 | ||||
-rw-r--r-- | unoidl/source/sourceprovider-scanner.hxx | 78 |
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 { |