Pārlūkot izejas kodu

* let search_class_helper() only return class helper methods; it could
also return regular objcclass methods before, because these are also
registered under class helper procsyms for future id.anymethod support
* give an error when calling an inherited method from an objccategory
method, if that is not declared in the parent of the extended class
(since calling inherited in an objccategory method is the same as
calling inherited in a method of the extended class; if a method is
replaced, calling inherited will *not* call the original method
from the original class)

git-svn-id: trunk@14213 -

Jonas Maebe 15 gadi atpakaļ
vecāks
revīzija
b495fbb991

+ 3 - 0
.gitattributes

@@ -8970,6 +8970,9 @@ tests/test/tobjc26a.pp svneol=native#text/plain
 tests/test/tobjc27a.pp svneol=native#text/plain
 tests/test/tobjc27a.pp svneol=native#text/plain
 tests/test/tobjc27b.pp svneol=native#text/plain
 tests/test/tobjc27b.pp svneol=native#text/plain
 tests/test/tobjc28.pp svneol=native#text/plain
 tests/test/tobjc28.pp svneol=native#text/plain
+tests/test/tobjc29.pp svneol=native#text/plain
+tests/test/tobjc29a.pp svneol=native#text/plain
+tests/test/tobjc29b.pp svneol=native#text/plain
 tests/test/tobjc3.pp svneol=native#text/plain
 tests/test/tobjc3.pp svneol=native#text/plain
 tests/test/tobjc4.pp svneol=native#text/plain
 tests/test/tobjc4.pp svneol=native#text/plain
 tests/test/tobjc4a.pp svneol=native#text/plain
 tests/test/tobjc4a.pp svneol=native#text/plain

+ 6 - 0
compiler/pexpr.pas

@@ -2232,6 +2232,12 @@ implementation
                     assigned(current_objectdef) then
                     assigned(current_objectdef) then
                   begin
                   begin
                     hclassdef:=current_objectdef.childof;
                     hclassdef:=current_objectdef.childof;
+                    { Objective-C categories *replace* methods in the class
+                      they extend, or add methods to it. So calling an
+                      inherited method always calls the method inherited from
+                      the parent of the extended class }
+                    if is_objccategory(current_objectdef) then
+                      hclassdef:=hclassdef.childof;
                     { if inherited; only then we need the method with
                     { if inherited; only then we need the method with
                       the same name }
                       the same name }
                     if token in endtokens then
                     if token in endtokens then

+ 7 - 1
compiler/symtable.pas

@@ -2033,6 +2033,7 @@ implementation
         hashedid   : THashedIDString;
         hashedid   : THashedIDString;
         stackitem  : psymtablestackitem;
         stackitem  : psymtablestackitem;
         i          : longint;
         i          : longint;
+        defowner   : tobjectdef;
       begin
       begin
         hashedid.id:=class_helper_prefix+s;
         hashedid.id:=class_helper_prefix+s;
         stackitem:=symtablestack.stack;
         stackitem:=symtablestack.stack;
@@ -2051,8 +2052,13 @@ implementation
                   begin
                   begin
                     { does pd inherit from (or is the same as) the class
                     { does pd inherit from (or is the same as) the class
                       that this method's category extended?
                       that this method's category extended?
+
+                      Warning: this list contains both category and objcclass methods
+                       (for id.randommethod), so only check category methods here
                     }
                     }
-                    if pd.is_related(tobjectdef(tprocdef(tprocsym(srsym).procdeflist[i]).owner.defowner).childof) then
+                    defowner:=tobjectdef(tprocdef(tprocsym(srsym).procdeflist[i]).owner.defowner);
+                    if (oo_is_classhelper in defowner.objectoptions) and
+                       pd.is_related(defowner.childof) then
                       begin
                       begin
                         { no need to keep looking. There might be other
                         { no need to keep looking. There might be other
                           categories that extend this, a parent or child
                           categories that extend this, a parent or child

+ 45 - 0
tests/test/tobjc29.pp

@@ -0,0 +1,45 @@
+{ %target=darwin }
+{ %cpu=powerpc,powerpc64,i386,x86_64,arm }
+
+{$mode objfpc}
+{$modeswitch objectivec1}
+
+type
+  ta = objcclass(NSObject)
+    function tabaseproc(cp: longint): double; message 'tabaseproc:';
+  end;
+
+  ca = objccategory(ta)
+    function tabaseproc(cp: longint): double; reintroduce;
+  end;
+
+  nsobjectta = objccategory(NSObject)
+    function tabaseproc(cp: longint): double; message 'tabaseproc:';
+  end;
+
+function ta.tabaseproc(cp: longint): double;
+begin
+  result:=cp;
+  halt(1);
+end;
+
+function ca.tabaseproc(cp: longint): double;
+begin
+  result:=inherited tabaseproc(cp+1);
+end;
+
+function nsobjectta.tabaseproc(cp: longint): double;
+begin
+  if (cp<>4321) then
+    halt(1);
+  result:=123.625;
+end;
+
+var
+  a: ta;
+begin
+  a:=ta(ta.alloc).init;
+  if a.tabaseproc(4320)<>123.625 then
+    halt(2);
+  a.release;
+end.

+ 35 - 0
tests/test/tobjc29a.pp

@@ -0,0 +1,35 @@
+{ %target=darwin }
+{ %cpu=powerpc,powerpc64,i386,x86_64,arm }
+{ %fail }
+
+{$mode objfpc}
+{$modeswitch objectivec1}
+
+type
+  ta = objcclass(NSObject)
+    function tabaseproc(cp: longint): double; message 'tabaseproc:';
+  end;
+
+  ca = objccategory(ta)
+    function tabaseproc(cp: longint): double; reintroduce;
+  end;
+
+function ta.tabaseproc(cp: longint): double;
+begin
+  result:=cp;
+  halt(1);
+end;
+
+function ca.tabaseproc(cp: longint): double;
+begin
+  result:=inherited tabaseproc(cp+1);
+end;
+
+var
+  a: ta;
+begin
+  a:=ta(ta.alloc).init;
+  if a.tabaseproc(4320)<>123.625 then
+    halt(2);
+  a.release;
+end.

+ 47 - 0
tests/test/tobjc29b.pp

@@ -0,0 +1,47 @@
+{ %target=darwin }
+{ %cpu=powerpc,powerpc64,i386,x86_64,arm }
+{ %fail }
+
+{$mode objfpc}
+{$modeswitch objectivec1}
+
+type
+  ta = objcclass(NSObject)
+    function tabaseproc(cp: longint): double; message 'tabaseproc:';
+  end;
+
+  ca = objccategory(ta)
+    { should fail because of wrong message name }
+    function tabaseproc(cp: longint): double; message 'adifferentname:'; reintroduce;
+  end;
+
+  nsobjectta = objccategory(NSObject)
+    function tabaseproc(cp: longint): double; message 'tabaseproc:';
+  end;
+
+function ta.tabaseproc(cp: longint): double;
+begin
+  result:=cp;
+  halt(1);
+end;
+
+function ca.tabaseproc(cp: longint): double;
+begin
+  result:=inherited tabaseproc(cp+1);
+end;
+
+function nsobjectta.tabaseproc(cp: longint): double;
+begin
+  if (cp<>4321) then
+    halt(1);
+  result:=123.625;
+end;
+
+var
+  a: ta;
+begin
+  a:=ta(ta.alloc).init;
+  if a.tabaseproc(4320)<>123.625 then
+    halt(2);
+  a.release;
+end.