[Libreoffice-commits] core.git: Branch 'libreoffice-4-2' - idlc/test unoidl/CustomTarget_unoidl-write_test.mk unoidl/Module_unoidl.mk unoidl/source

Stephan Bergmann sbergman at redhat.com
Mon Nov 25 08:28:10 PST 2013


 idlc/test/parser/methodoverload.tests    |   62 +++
 unoidl/CustomTarget_unoidl-write_test.mk |   91 +++++
 unoidl/Module_unoidl.mk                  |    1 
 unoidl/source/sourceprovider-parser.y    |  551 +++++++++++++++++++++++++++----
 unoidl/source/sourceprovider-scanner.hxx |   78 +++-
 5 files changed, 700 insertions(+), 83 deletions(-)

New commits:
commit f16aa10d1a0f8ae69fdd617f054e6bfe2a063517
Author: Stephan Bergmann <sbergman at redhat.com>
Date:   Mon Nov 25 17:25:08 2013 +0100

    Fix unoidl sourceprovider interface base and member checks
    
    ...and enable tests shared with idlc
    
    Change-Id: I422b16c9b2636835d276cc2085cb640073894c97
    (cherry picked from commit 454f3f72c5d7a6f92debb4e4756e330397d507e6)

diff --git a/idlc/test/parser/methodoverload.tests b/idlc/test/parser/methodoverload.tests
index b6ce276..9a07a4b 100644
--- a/idlc/test/parser/methodoverload.tests
+++ b/idlc/test/parser/methodoverload.tests
@@ -113,3 +113,65 @@ interface Derived {
 	[optional] interface Base1;
 	[optional] interface Base2;
 };
+
+
+EXPECT FAILURE "methodoverload.tests 10":
+interface I {
+    [attribute] long a;
+    [attribute] short a;
+};
+
+
+EXPECT FAILURE "methodoverload.tests 11":
+interface I1 {
+    [attribute] long a;
+};
+interface I2 {
+    [attribute] short a;
+    interface I1;
+};
+
+
+EXPECT FAILURE "methodoverload.tests 12":
+interface I {
+    [attribute] long a;
+    void a();
+};
+
+
+EXPECT FAILURE "methodoverload.tests 13":
+interface I1 {
+    [attribute] long a;
+}
+interface I2 {
+    void a();
+    interface I1;
+};
+
+
+EXPECT FAILURE "methodoverload.tests 14":
+interface I1 {
+    void a();
+}
+interface I2 {
+    [attribute] long a;
+    interface I1;
+};
+
+
+EXPECT SUCCESS "methodoverload.tests 15":
+interface I {
+    [attribute] long a;
+    void geta();
+    void seta();
+};
+
+
+EXPECT SUCCESS "methodoverload.tests 16":
+interface I1 {
+    [attribute] long a;
+};
+interface I2: I1 {
+    void geta();
+    void seta();
+};
diff --git a/unoidl/CustomTarget_unoidl-write_test.mk b/unoidl/CustomTarget_unoidl-write_test.mk
new file mode 100644
index 0000000..22c25b0
--- /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 e377ba8..0136485 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 e377ac4..f7f022f 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 5edd984..14ac154 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 {


More information about the Libreoffice-commits mailing list