Repository: lucy-clownfish
Updated Branches:
  refs/heads/master 8bfda8334 -> 5e2478048


Don't allow to subclass final classes

Fixes CLOWNFISH-45.


Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/5e247804
Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/5e247804
Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/5e247804

Branch: refs/heads/master
Commit: 5e2478048ffc5062dc0a191087e6dfb1e5b87f57
Parents: 5c7144b
Author: Nick Wellnhofer <wellnho...@aevum.de>
Authored: Fri Jul 24 14:50:36 2015 +0200
Committer: Nick Wellnhofer <wellnho...@aevum.de>
Committed: Mon Jul 27 18:26:18 2015 +0200

----------------------------------------------------------------------
 compiler/src/CFCBindCore.c       |  1 +
 compiler/src/CFCBindSpecs.c      | 12 ++++++++++--
 runtime/core/Clownfish/Class.c   |  7 +++++++
 runtime/perl/t/binding/019-obj.t |  9 ++++++++-
 4 files changed, 26 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5e247804/compiler/src/CFCBindCore.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCBindCore.c b/compiler/src/CFCBindCore.c
index d5f59d7..ce0f9f7 100644
--- a/compiler/src/CFCBindCore.c
+++ b/compiler/src/CFCBindCore.c
@@ -299,6 +299,7 @@ S_write_parcel_h(CFCBindCore *self, CFCParcel *parcel) {
         "\n"
         "/* Flags for internal use. */\n"
         "#define CFISH_fREFCOUNTSPECIAL 0x00000001\n"
+        "#define CFISH_fFINAL           0x00000002\n"
         ;
     const char *cfish_defs_2 =
         "#ifdef CFISH_USE_SHORT_NAMES\n"

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5e247804/compiler/src/CFCBindSpecs.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCBindSpecs.c b/compiler/src/CFCBindSpecs.c
index f3b377d..4db517b 100644
--- a/compiler/src/CFCBindSpecs.c
+++ b/compiler/src/CFCBindSpecs.c
@@ -116,6 +116,10 @@ CFCBindSpecs_get_typedefs() {
         "    size_t *parent_offset;\n"
         "} cfish_InheritedMethSpec;\n"
         "\n"
+        "typedef enum {\n"
+        "    cfish_ClassSpec_FINAL = 1\n"
+        "} cfish_ClassSpecFlags;\n"
+        "\n"
         "typedef struct cfish_ClassSpec {\n"
         "    cfish_Class **klass;\n"
         "    cfish_Class **parent;\n"
@@ -125,6 +129,7 @@ CFCBindSpecs_get_typedefs() {
         "    uint32_t      num_novel_meths;\n"
         "    uint32_t      num_overridden_meths;\n"
         "    uint32_t      num_inherited_meths;\n"
+        "    uint32_t      flags;\n"
         "} cfish_ClassSpec;\n"
         "\n";
 }
@@ -137,6 +142,8 @@ CFCBindSpecs_add_class(CFCBindSpecs *self, CFCClass *klass) 
{
     const char *class_var         = CFCClass_full_class_var(klass);
     const char *ivars_offset_name = CFCClass_full_ivars_offset(klass);
 
+    const char *flags = CFCClass_final(klass) ? "cfish_ClassSpec_FINAL" : "0";
+
     char *ivars_size = S_ivars_size(klass);
 
     char *parent_ptr = NULL;
@@ -200,12 +207,13 @@ CFCBindSpecs_add_class(CFCBindSpecs *self, CFCClass 
*klass) {
         "        &%s, /* ivars_offset_ptr */\n"
         "        %d, /* num_novel */\n"
         "        %d, /* num_overridden */\n"
-        "        %d /* num_inherited */\n"
+        "        %d, /* num_inherited */\n"
+        "        %s /* flags */\n"
         "    }";
     char *class_spec
         = CFCUtil_sprintf(pattern, class_var, parent_ptr, class_name,
                           ivars_size, ivars_offset_name, num_new_novel,
-                          num_new_overridden, num_new_inherited);
+                          num_new_overridden, num_new_inherited, flags);
 
     const char *sep = self->num_specs == 0 ? "" : ",\n";
     self->class_specs = CFCUtil_cat(self->class_specs, sep, class_spec, NULL);

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5e247804/runtime/core/Clownfish/Class.c
----------------------------------------------------------------------
diff --git a/runtime/core/Clownfish/Class.c b/runtime/core/Clownfish/Class.c
index 474e8a2..5f30de2 100644
--- a/runtime/core/Clownfish/Class.c
+++ b/runtime/core/Clownfish/Class.c
@@ -155,6 +155,9 @@ Class_bootstrap(const cfish_ClassSpec *specs, size_t 
num_specs,
            ) {
             klass->flags |= CFISH_fREFCOUNTSPECIAL;
         }
+        if (spec->flags & cfish_ClassSpec_FINAL) {
+            klass->flags |= CFISH_fFINAL;
+        }
 
         if (parent) {
             // Copy parent vtable.
@@ -266,6 +269,10 @@ Class_init_registry() {
 
 static Class*
 S_simple_subclass(Class *parent, String *name) {
+    if (parent->flags & CFISH_fFINAL) {
+        THROW(ERR, "Can't subclass final class %o", Class_Get_Name(parent));
+    }
+
     Class *subclass
         = (Class*)Memory_wrapped_calloc(parent->class_alloc_size, 1);
     Class_Init_Obj(parent->klass, subclass);

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5e247804/runtime/perl/t/binding/019-obj.t
----------------------------------------------------------------------
diff --git a/runtime/perl/t/binding/019-obj.t b/runtime/perl/t/binding/019-obj.t
index 5de41df..545b235 100644
--- a/runtime/perl/t/binding/019-obj.t
+++ b/runtime/perl/t/binding/019-obj.t
@@ -16,7 +16,7 @@
 use strict;
 use warnings;
 
-use Test::More tests => 24;
+use Test::More tests => 25;
 
 package TestObj;
 use base qw( Clownfish::Obj );
@@ -57,6 +57,9 @@ use base qw( Clownfish::Test::AliasTestObj );
     sub perl_alias {"Perl"}
 }
 
+package SubclassFinalTestObj;
+use base qw( Clownfish::Vector );
+
 package main;
 use Storable qw( freeze thaw );
 use Clownfish::Test;
@@ -152,3 +155,7 @@ my $overridden_alias_test = OverriddenAliasTestObj->new;
 is( $overridden_alias_test->call_aliased_from_c, 'Perl',
     'Overriding aliased methods works' );
 
+eval { SubclassFinalTestObj->new; };
+like( $@, qr/Can't subclass final class Clownfish::Vector/,
+      "Final class can't be subclassed" );
+

Reply via email to