2
0
Эх сурвалжийг харах

* support for raising the visibility of inherited properties on the JVM
target (generate new getters/setters with increased visibility that
call the inherited ones, if necessary)

git-svn-id: trunk@27940 -

Jonas Maebe 11 жил өмнө
parent
commit
2075dc5a53

+ 2 - 0
.gitattributes

@@ -10906,6 +10906,8 @@ tests/test/jvm/tprop.pp svneol=native#text/plain
 tests/test/jvm/tprop2.pp svneol=native#text/plain
 tests/test/jvm/tprop2.pp svneol=native#text/plain
 tests/test/jvm/tprop3.pp svneol=native#text/plain
 tests/test/jvm/tprop3.pp svneol=native#text/plain
 tests/test/jvm/tprop4.pp svneol=native#text/plain
 tests/test/jvm/tprop4.pp svneol=native#text/plain
+tests/test/jvm/tprop5.pp svneol=native#text/plain
+tests/test/jvm/tprop5a.pp svneol=native#text/plain
 tests/test/jvm/tptrdynarr.pp svneol=native#text/plain
 tests/test/jvm/tptrdynarr.pp svneol=native#text/plain
 tests/test/jvm/tpvar.pp svneol=native#text/plain
 tests/test/jvm/tpvar.pp svneol=native#text/plain
 tests/test/jvm/tpvardelphi.pp svneol=native#text/plain
 tests/test/jvm/tpvardelphi.pp svneol=native#text/plain

+ 81 - 16
compiler/jvm/symcpu.pas

@@ -187,8 +187,10 @@ type
       visibility, then we have to create a getter and/or setter with that same
       visibility, then we have to create a getter and/or setter with that same
       higher visibility to make sure that using the property does not result
       higher visibility to make sure that using the property does not result
       in JVM verification errors }
       in JVM verification errors }
-    procedure create_getter_or_setter_for_property(orgaccesspd: tprocdef; getter: boolean);
+    function create_getter_or_setter_for_property(orgaccesspd: tprocdef; getter: boolean): tprocdef;
     procedure finalize_getter_or_setter_for_sym(getset: tpropaccesslisttypes; sym: tsym; fielddef: tdef; accessordef: tprocdef); override;
     procedure finalize_getter_or_setter_for_sym(getset: tpropaccesslisttypes; sym: tsym; fielddef: tdef; accessordef: tprocdef); override;
+    procedure register_override(overriddenprop: tpropertysym); override;
+    procedure maybe_create_overridden_getter_or_setter(getset: tpropaccesslisttypes);
   end;
   end;
   tcpupropertysymclass = class of tcpupropertysym;
   tcpupropertysymclass = class of tcpupropertysym;
 
 
@@ -222,7 +224,7 @@ implementation
                                tcpuproptertysym
                                tcpuproptertysym
   ****************************************************************************}
   ****************************************************************************}
 
 
-  procedure tcpupropertysym.create_getter_or_setter_for_property(orgaccesspd: tprocdef; getter: boolean);
+  function tcpupropertysym.create_getter_or_setter_for_property(orgaccesspd: tprocdef; getter: boolean): tprocdef;
     var
     var
       obj: tabstractrecorddef;
       obj: tabstractrecorddef;
       ps: tprocsym;
       ps: tprocsym;
@@ -309,6 +311,7 @@ implementation
                             parentpd.visibility:=visibility;
                             parentpd.visibility:=visibility;
                             include(parentpd.procoptions,po_auto_raised_visibility);
                             include(parentpd.procoptions,po_auto_raised_visibility);
                           end;
                           end;
+                        result:=parentpd;
                         { we are done, no need to create a wrapper }
                         { we are done, no need to create a wrapper }
                         exit
                         exit
                       end
                       end
@@ -319,7 +322,8 @@ implementation
                         if po_virtualmethod in parentpd.procoptions then
                         if po_virtualmethod in parentpd.procoptions then
                           begin
                           begin
                             procoptions:=procoptions+[po_virtualmethod,po_overridingmethod];
                             procoptions:=procoptions+[po_virtualmethod,po_overridingmethod];
-                            Message2(parser_w_overriding_property_getter_setter,accessorname,FullTypeName(tdef(parentpd.owner.defowner),nil));
+                            if not(parentpd.synthetickind in [tsk_field_getter,tsk_field_setter]) then
+                              Message2(parser_w_overriding_property_getter_setter,accessorname,FullTypeName(tdef(parentpd.owner.defowner),nil));
                           end;
                           end;
                         { otherwise we can't do anything, and
                         { otherwise we can't do anything, and
                           proc_add_definition will give an error }
                           proc_add_definition will give an error }
@@ -340,6 +344,7 @@ implementation
                     finish_copied_procdef(pd,parentpd.procsym.realname,obj.symtable,obj);
                     finish_copied_procdef(pd,parentpd.procsym.realname,obj.symtable,obj);
                     exclude(pd.procoptions,po_external);
                     exclude(pd.procoptions,po_external);
                     pd.synthetickind:=tsk_anon_inherited;
                     pd.synthetickind:=tsk_anon_inherited;
+                    result:=pd;
                     exit;
                     exit;
                   end;
                   end;
               end;
               end;
@@ -394,6 +399,7 @@ implementation
         pd.procoptions:=pd.procoptions+procoptions;
         pd.procoptions:=pd.procoptions+procoptions;
         { visibility }
         { visibility }
         pd.visibility:=visibility;
         pd.visibility:=visibility;
+        result:=pd;
 
 
         { new procsym? }
         { new procsym? }
         if not assigned(sym) or
         if not assigned(sym) or
@@ -407,8 +413,6 @@ implementation
         { associate procsym with procdef}
         { associate procsym with procdef}
         pd.procsym:=ps;
         pd.procsym:=ps;
 
 
-
-
         { function/procedure }
         { function/procedure }
         accessorparapd:=nil;
         accessorparapd:=nil;
         if getter then
         if getter then
@@ -496,7 +500,7 @@ implementation
 
 
   procedure tcpupropertysym.finalize_getter_or_setter_for_sym(getset: tpropaccesslisttypes; sym: tsym; fielddef: tdef; accessordef: tprocdef);
   procedure tcpupropertysym.finalize_getter_or_setter_for_sym(getset: tpropaccesslisttypes; sym: tsym; fielddef: tdef; accessordef: tprocdef);
     var
     var
-      orgaccesspd: tprocdef;
+      orgaccesspd, newaccesspd: tprocdef;
       pprefix: pstring;
       pprefix: pstring;
       wrongvisibility: boolean;
       wrongvisibility: boolean;
     begin
     begin
@@ -505,24 +509,19 @@ implementation
         pprefix:=@prop_auto_getter_prefix
         pprefix:=@prop_auto_getter_prefix
       else
       else
         pprefix:=@prop_auto_setter_prefix;
         pprefix:=@prop_auto_setter_prefix;
+      newaccesspd:=nil;
       case sym.typ of
       case sym.typ of
         procsym:
         procsym:
           begin
           begin
             orgaccesspd:=tprocdef(propaccesslist[getset].procdef);
             orgaccesspd:=tprocdef(propaccesslist[getset].procdef);
             wrongvisibility:=tprocdef(propaccesslist[getset].procdef).visibility<visibility;
             wrongvisibility:=tprocdef(propaccesslist[getset].procdef).visibility<visibility;
-            if (pprefix^<>'') and
-               (wrongvisibility or
-                (sym.RealName<>pprefix^+RealName)) then
-              create_getter_or_setter_for_property(orgaccesspd,getset=palt_read)
             { if the visibility of the accessor is lower than
             { if the visibility of the accessor is lower than
               the visibility of the property, wrap it so that
               the visibility of the property, wrap it so that
               we can call it from all contexts in which the
               we can call it from all contexts in which the
               property is visible }
               property is visible }
-            else if wrongvisibility then
-             begin
-               propaccesslist[getset].procdef:=jvm_wrap_method_with_vis(tprocdef(propaccesslist[palt_read].procdef),visibility);
-               propaccesslist[getset].firstsym^.sym:=tprocdef(propaccesslist[getset].procdef).procsym;
-             end;
+            if wrongvisibility or
+               (sym.RealName<>pprefix^+RealName) then
+              newaccesspd:=create_getter_or_setter_for_property(orgaccesspd,getset=palt_read)
           end;
           end;
         fieldvarsym:
         fieldvarsym:
           begin
           begin
@@ -532,11 +531,77 @@ implementation
               which the property is visibile }
               which the property is visibile }
             if (pprefix^<>'') or
             if (pprefix^<>'') or
                (tfieldvarsym(sym).visibility<visibility) then
                (tfieldvarsym(sym).visibility<visibility) then
-              create_getter_or_setter_for_property(nil,getset=palt_read);
+              newaccesspd:=create_getter_or_setter_for_property(nil,getset=palt_read);
           end;
           end;
         else
         else
           internalerror(2014061101);
           internalerror(2014061101);
       end;
       end;
+      { update the getter/setter used for this property (already done in case
+        a new method was created from scratch, but not if we overrode a
+        getter/setter generated for the inherited property) }
+      if assigned(newaccesspd) then
+        begin
+          if propaccesslist[getset].firstsym^.sym.typ<>procsym then
+            internalerror(2014061201);
+          propaccesslist[getset].procdef:=newaccesspd;
+          propaccesslist[getset].firstsym^.sym:=newaccesspd.procsym;
+        end;
+    end;
+
+
+  procedure tcpupropertysym.register_override(overriddenprop: tpropertysym);
+    var
+      sym: tsym;
+    begin
+      inherited;
+      { new property has higher visibility than previous one -> maybe override
+        the getters/setters }
+      if (overriddenprop.visibility<visibility) then
+        begin
+          maybe_create_overridden_getter_or_setter(palt_read);
+          maybe_create_overridden_getter_or_setter(palt_write);
+        end;
+    end;
+
+
+  procedure tcpupropertysym.maybe_create_overridden_getter_or_setter(getset: tpropaccesslisttypes);
+    var
+      sym: tsym;
+      fielddef: tdef;
+      accessordef: tprocdef;
+      psym: tpropertysym;
+    begin
+      { find the last defined getter/setter/field accessed by an inherited
+        property }
+      psym:=overriddenpropsym;
+      while not assigned(psym.propaccesslist[getset].firstsym) do
+        begin
+          psym:=psym.overriddenpropsym;
+          { if there is simply no getter/setter for this property, we're done }
+          if not assigned(psym) then
+            exit;
+        end;
+      sym:=psym.propaccesslist[getset].firstsym^.sym;
+      case sym.typ of
+        procsym:
+          begin
+            accessordef:=tprocdef(psym.propaccesslist[getset].procdef);
+            if accessordef.visibility>=visibility then
+              exit;
+            fielddef:=nil;
+          end;
+        fieldvarsym:
+          begin
+            if sym.visibility>=visibility then
+              exit;
+            accessordef:=nil;
+            fielddef:=tfieldvarsym(sym).vardef;
+          end;
+        else
+          internalerror(2014061102);
+      end;
+      propaccesslist[getset]:=psym.propaccesslist[getset].getcopy;
+      finalize_getter_or_setter_for_sym(getset,sym,propdef,accessordef);
     end;
     end;
 
 
 
 

+ 22 - 0
compiler/symtype.pas

@@ -162,6 +162,7 @@ interface
         constructor create;
         constructor create;
         destructor  destroy;override;
         destructor  destroy;override;
         function  empty:boolean;
         function  empty:boolean;
+        function getcopy: tpropaccesslist;
         procedure addsym(slt:tsltype;p:tsym);
         procedure addsym(slt:tsltype;p:tsym);
         procedure addconst(slt:tsltype;v:TConstExprInt;d:tdef);
         procedure addconst(slt:tsltype;v:TConstExprInt;d:tdef);
         procedure addtype(slt:tsltype;d:tdef);
         procedure addtype(slt:tsltype;d:tdef);
@@ -462,6 +463,27 @@ implementation
         empty:=(firstsym=nil);
         empty:=(firstsym=nil);
       end;
       end;
 
 
+    function tpropaccesslist.getcopy: tpropaccesslist;
+      var
+        hp, dest : ppropaccesslistitem;
+      begin
+        result:=tpropaccesslist.create;
+        result.procdef:=procdef;
+        hp:=firstsym;
+        while assigned(hp) do
+          begin
+            new(dest);
+            dest^:=hp^;
+            dest^.next:=nil;
+            if not assigned(result.firstsym) then
+              result.firstsym:=dest;
+            if assigned(result.lastsym) then
+              result.lastsym^.next:=dest;
+            result.lastsym:=dest;
+            hp:=hp^.next;
+          end;
+      end;
+
 
 
     procedure tpropaccesslist.clear;
     procedure tpropaccesslist.clear;
       var
       var

+ 4 - 0
tests/test/jvm/testall.bat

@@ -294,3 +294,7 @@ ppcjvm -O2 -g -B  -CTinitlocals tptrdynarr
 if %errorlevel% neq 0 exit /b %errorlevel%
 if %errorlevel% neq 0 exit /b %errorlevel%
 java -Dfile.encoding=UTF-8 -cp ..\..\..\rtl\units\jvm-java;. tptrdynarr
 java -Dfile.encoding=UTF-8 -cp ..\..\..\rtl\units\jvm-java;. tptrdynarr
 if %errorlevel% neq 0 exit /b %errorlevel%
 if %errorlevel% neq 0 exit /b %errorlevel%
+ppcjvm -O2 -g -B -Sa tprop5a
+java -Dfile.encoding=UTF-8 -cp ..\..\..\rtl\units\jvm-java;. tprop5a
+ppcjvm -O2 -g -B -Sa tprop5a -CTautosetterprefix=Set -CTautogetterprefix=Get
+java -Dfile.encoding=UTF-8 -cp ..\..\..\rtl\units\jvm-java;. tprop5a

+ 4 - 0
tests/test/jvm/testall.sh

@@ -174,3 +174,7 @@ fi
 set -e
 set -e
 $PPC -O2 -g -B -Sa tptrdynarr
 $PPC -O2 -g -B -Sa tptrdynarr
 java -Dfile.encoding=UTF-8 -cp ../../../rtl/units/$RTLDIR:. tptrdynarr
 java -Dfile.encoding=UTF-8 -cp ../../../rtl/units/$RTLDIR:. tptrdynarr
+$PPC -O2 -g -B -Sa tprop5a
+java -Dfile.encoding=UTF-8 -cp ../../../rtl/units/$RTLDIR:. tprop5a
+$PPC -O2 -g -B -Sa tprop5a -CTautosetterprefix=Set -CTautogetterprefix=Get
+java -Dfile.encoding=UTF-8 -cp ../../../rtl/units/$RTLDIR:. tprop5a

+ 33 - 0
tests/test/jvm/tprop5.pp

@@ -0,0 +1,33 @@
+{$mode delphi}
+{$modeswitch unicodestrings}
+{$namespace org.freepascal.test}
+
+Unit tprop5;
+
+interface
+
+uses
+ jdk15;
+
+type
+ TBaseClass = class
+ private
+   FLevel : integer;
+   procedure SetLevel(value: integer); virtual;
+ protected
+   property Level: Integer read FLevel write SetLevel;
+ end;
+
+ TDerivedClass = class(TBaseClass)
+ public
+   property Level;
+ end;
+
+implementation
+
+procedure TBaseClass.SetLevel(Value: integer);
+begin
+ FLevel := Value;
+end;
+
+end.

+ 11 - 0
tests/test/jvm/tprop5a.pp

@@ -0,0 +1,11 @@
+program tprop5a;
+
+uses
+  tprop5;
+var
+  d: tderivedclass;
+begin
+  d:=tderivedclass.create;
+  d.level:=5;
+  halt(d.level-5);
+end.