+ Objective-C category support (old and new ABI, both external and

implemented in Pascal). See
    http://wiki.freepascal.org/FPC_PasCocoa#Category_declaration for syntax
    details

git-svn-id: trunk@14196 -
This commit is contained in:
Jonas Maebe 2009-11-16 00:12:08 +00:00
parent 9e87f42b16
commit f8754d8fab
27 changed files with 1330 additions and 525 deletions

11
.gitattributes vendored
View File

@ -8963,6 +8963,13 @@ tests/test/tobjc20.pp svneol=native#text/plain
tests/test/tobjc21.pp svneol=native#text/plain tests/test/tobjc21.pp svneol=native#text/plain
tests/test/tobjc22.pp svneol=native#text/plain tests/test/tobjc22.pp svneol=native#text/plain
tests/test/tobjc23.pp svneol=native#text/plain tests/test/tobjc23.pp svneol=native#text/plain
tests/test/tobjc24.pp svneol=native#text/plain
tests/test/tobjc25.pp svneol=native#text/plain
tests/test/tobjc26.pp svneol=native#text/plain
tests/test/tobjc26a.pp svneol=native#text/plain
tests/test/tobjc27a.pp svneol=native#text/plain
tests/test/tobjc27b.pp svneol=native#text/plain
tests/test/tobjc28.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
@ -9300,6 +9307,10 @@ tests/test/units/sysutils/tfloattostr.pp svneol=native#text/plain
tests/test/units/sysutils/tlocale.pp svneol=native#text/plain tests/test/units/sysutils/tlocale.pp svneol=native#text/plain
tests/test/units/sysutils/tsscanf.pp svneol=native#text/plain tests/test/units/sysutils/tsscanf.pp svneol=native#text/plain
tests/test/units/sysutils/tstrtobool.pp svneol=native#text/plain tests/test/units/sysutils/tstrtobool.pp svneol=native#text/plain
tests/test/uobjc24.pp svneol=native#text/plain
tests/test/uobjc26.pp svneol=native#text/plain
tests/test/uobjc27a.pp svneol=native#text/plain
tests/test/uobjc27b.pp svneol=native#text/plain
tests/test/uobjc7.pp svneol=native#text/plain tests/test/uobjc7.pp svneol=native#text/plain
tests/test/uobjcl1.pp svneol=native#text/plain tests/test/uobjcl1.pp svneol=native#text/plain
tests/test/uprec6.pp svneol=native#text/plain tests/test/uprec6.pp svneol=native#text/plain

View File

@ -366,7 +366,7 @@ scan_w_multiple_main_name_overrides=02086_W_Overriding name of "main" procedure
# #
# Parser # Parser
# #
# 03275 is the last used one # 03280 is the last used one
# #
% \section{Parser messages} % \section{Parser messages}
% This section lists all parser messages. The parser takes care of the % This section lists all parser messages. The parser takes care of the
@ -913,11 +913,11 @@ parser_e_no_con_des_in_interfaces=03171_E_Con- and destructors aren't allowed in
% be used to create a new interface. % be used to create a new interface.
parser_e_no_access_specifier_in_interfaces=03172_E_Access specifiers can't be used in INTERFACEs and OBJCPROTOCOLs parser_e_no_access_specifier_in_interfaces=03172_E_Access specifiers can't be used in INTERFACEs and OBJCPROTOCOLs
% The access specifiers \var{public}, \var{private}, \var{protected} and % The access specifiers \var{public}, \var{private}, \var{protected} and
% \var{published} can't be used in interfaces and Objective-C protocols because all methods % \var{published} can't be used in interfaces, Objective-C protocols and categories because all methods
% of an interface/protocol must be public. % of an interface/protocol/category must be public.
parser_e_no_vars_in_interfaces=03173_E_An interface or Objective-C protocol cannot contain fields parser_e_no_vars_in_interfaces=03173_E_An interface or Objective-C protocol or category cannot contain fields
% Declarations of fields are not allowed in interfaces and Objective-C protocols. An interface/protocol % Declarations of fields are not allowed in interfaces and Objective-C protocols and categories.
% can contain only methods and properties with method read/write specifiers. % An interface/protocol/category can contain only methods and properties with method read/write specifiers.
parser_e_no_local_proc_external=03174_E_Can't declare local procedure as EXTERNAL parser_e_no_local_proc_external=03174_E_Can't declare local procedure as EXTERNAL
% Declaring local procedures as external is not possible. Local procedures % Declaring local procedures as external is not possible. Local procedures
% get hidden parameters that will make the chance of errors very high. % get hidden parameters that will make the chance of errors very high.
@ -992,7 +992,7 @@ parser_e_illegal_calling_convention=03195_W_Calling convention directive ignored
% Some calling conventions are supported only by certain CPUs. I.e. most non-i386 ports support % Some calling conventions are supported only by certain CPUs. I.e. most non-i386 ports support
% only the standard ABI calling convention of the CPU. % only the standard ABI calling convention of the CPU.
parser_e_no_object_reintroduce=03196_E_REINTRODUCE can't be used in objects parser_e_no_object_reintroduce=03196_E_REINTRODUCE can't be used in objects
% \var{reintroduce} is not supported for objects. % \var{reintroduce} is not supported for objects, Objective-C classes and Objective-C protocols.
parser_e_paraloc_only_one_para=03197_E_Each argument must have its own location parser_e_paraloc_only_one_para=03197_E_Each argument must have its own location
% If locations for arguments are specified explicitly as it is required by % If locations for arguments are specified explicitly as it is required by
% some syscall conventions, each argument must have its own location. Things % some syscall conventions, each argument must have its own location. Things
@ -1245,13 +1245,13 @@ parser_e_no_objc_published=03271_E_Objective-C classes cannot have published sec
parser_f_need_objc=03272_F_This module requires an Objective-C mode switch to be compiled parser_f_need_objc=03272_F_This module requires an Objective-C mode switch to be compiled
% This error indicates the use of Objective-C language features without an Objective-C mode switch % This error indicates the use of Objective-C language features without an Objective-C mode switch
% active. Enable one via the -M command line switch, or the {\$modeswitch x} directive. % active. Enable one via the -M command line switch, or the {\$modeswitch x} directive.
parser_e_must_use_override_objc=03273_E_Inherited methods can only be overridden in Objective-C, add ``override''. parser_e_must_use_override_objc=03273_E_Inherited methods can only be overridden in Objective-C, add "override".
parser_h_should_use_override_objc=03274_H_Inherited methods can only be overridden in Objective-C, add ``override''. parser_h_should_use_override_objc=03274_H_Inherited methods can only be overridden in Objective-C, add "override".
% It is not possible to ``reintroduce'' methods in Objective-C like in Object Pascal. Methods with the same % It is not possible to \var{reintroduce} methods in Objective-C like in Object Pascal. Methods with the same
% name always map to the same virtual method entry. In order to make this clear in the source code, % name always map to the same virtual method entry. In order to make this clear in the source code,
% the compiler always requires the ``override'' directive to be specified when implementing overriding % the compiler always requires the \var{override} directive to be specified when implementing overriding
% Objective-C methods in Pascal. If the implementation is external, this rule is relaxed because Objective-C % Objective-C methods in Pascal. If the implementation is external, this rule is relaxed because Objective-C
% does not have any ``override''-style keyword (since it's the default and only behaviour in that language), % does not have any \var{override}-style keyword (since it's the default and only behaviour in that language),
% which makes it hard for automated header conversion tools to include it everywhere. % which makes it hard for automated header conversion tools to include it everywhere.
parser_e_objc_message_name_changed=03275_E_Message name "$1" in inherited class is different from message name "$2" in current class. parser_e_objc_message_name_changed=03275_E_Message name "$1" in inherited class is different from message name "$2" in current class.
% An overriding Objective-C method cannot have a different message name than an inherited method. The reason % An overriding Objective-C method cannot have a different message name than an inherited method. The reason
@ -1260,11 +1260,24 @@ parser_e_objc_message_name_changed=03275_E_Message name "$1" in inherited class
parser_e_no_objc_unique=03276_E_It is not yet possible to make unique copies of Objective-C types parser_e_no_objc_unique=03276_E_It is not yet possible to make unique copies of Objective-C types
% Duplicating an Objective-C type using \var{type x = type y;} is not yet supported. You may be able to % Duplicating an Objective-C type using \var{type x = type y;} is not yet supported. You may be able to
% obtain the desired effect using \var{type x = objcclass(y) end;} instead. % obtain the desired effect using \var{type x = objcclass(y) end;} instead.
parser_e_no_category_as_types=03277_E_Objective-C categories cannot be used as types
% It is not possible to declare a variable as an instance of an Objective-C category. A
% category adds methods to the scope of an existing class, but does not define a type by itself.
parser_e_no_category_override=03278_E_Categories do not override, but replace methods. Use "reintroduce" instead.
parser_e_must_use_reintroduce_objc=03279_E_Replaced methods can only be reintroduced in Objective-C, add "reintroduce".
parser_h_should_use_reintroduce_objc=03280_H_Replaced methods can only be reintroduced in Objective-C, add "reintroduce".
% A category replaces an existing method in an Objective-C class, rather than that it overrides it.
% Calling an inherited method from an category method will call that method in
% the extended class' parent, not in the extended class itself. The
% replaced method in the original class is basically lost, and can no longer be
% called or referred to. This behaviour corresponds somewhat more closely to
% \var{reintroduce} than to \var{override} (although in case of \var{reintroduce}
% in Object Pascal, hidden methods are still reachable via inherited).
% \end{description} % \end{description}
# #
# Type Checking # Type Checking
# #
# 04093 is the last used one # 04094 is the last used one
# #
% \section{Type checking errors} % \section{Type checking errors}
% This section lists all errors that can occur when type checking is % This section lists all errors that can occur when type checking is
@ -1578,7 +1591,9 @@ type_e_objc_type_unsupported=04092_E_The type "$1" is not supported for interact
% interfaces) cannot be used as fields of Objective-C classes, cannot be % interfaces) cannot be used as fields of Objective-C classes, cannot be
% directly passed to Objective-C methods, and cannot be encoded using \var{objc_encode}. % directly passed to Objective-C methods, and cannot be encoded using \var{objc_encode}.
type_e_class_or_objcclass_type_expected=04093_E_Class or objcclass type expected, but got "$1" type_e_class_or_objcclass_type_expected=04093_E_Class or objcclass type expected, but got "$1"
% It is only possible to create class reference types of \var{class} and % It is only possible to create class reference types of \var{class} and \var{objcclass}
type_e_objcclass_type_expected=04094_E_Objcclass type expected
% The compiler expected an Objc
% \var{objcclass} types % \var{objcclass} types
% %
% \end{description} % \end{description}

View File

@ -364,6 +364,10 @@ const
parser_h_should_use_override_objc=03274; parser_h_should_use_override_objc=03274;
parser_e_objc_message_name_changed=03275; parser_e_objc_message_name_changed=03275;
parser_e_no_objc_unique=03276; parser_e_no_objc_unique=03276;
parser_e_no_category_as_types=03277;
parser_e_no_category_override=03278;
parser_e_must_use_reintroduce_objc=03279;
parser_h_should_use_reintroduce_objc=03280;
type_e_mismatch=04000; type_e_mismatch=04000;
type_e_incompatible_types=04001; type_e_incompatible_types=04001;
type_e_not_equal_types=04002; type_e_not_equal_types=04002;
@ -448,6 +452,7 @@ const
type_e_protocol_type_expected=04091; type_e_protocol_type_expected=04091;
type_e_objc_type_unsupported=04092; type_e_objc_type_unsupported=04092;
type_e_class_or_objcclass_type_expected=04093; type_e_class_or_objcclass_type_expected=04093;
type_e_objcclass_type_expected=04094;
sym_e_id_not_found=05000; sym_e_id_not_found=05000;
sym_f_internal_error_in_symtablestack=05001; sym_f_internal_error_in_symtablestack=05001;
sym_e_duplicate_id=05002; sym_e_duplicate_id=05002;
@ -827,9 +832,9 @@ const
option_info=11024; option_info=11024;
option_help_pages=11025; option_help_pages=11025;
MsgTxtSize = 54197; MsgTxtSize = 54546;
MsgIdxMax : array[1..20] of longint=( MsgIdxMax : array[1..20] of longint=(
24,87,277,94,71,51,108,22,202,62, 24,87,281,95,71,51,108,22,202,62,
48,20,1,1,1,1,1,1,1,1 48,20,1,1,1,1,1,1,1,1
); );

File diff suppressed because it is too large Load Diff

View File

@ -281,8 +281,12 @@ implementation
if (po_virtualmethod in vmtpd.procoptions) and if (po_virtualmethod in vmtpd.procoptions) and
( (
not(po_virtualmethod in pd.procoptions) or not(po_virtualmethod in pd.procoptions) or
{ new one has not override } (
(is_class_or_interface_or_objc(_class) and not(po_overridingmethod in pd.procoptions)) { new one does not have reintroduce in case of an objccategory }
(is_objccategory(_class) and not(po_reintroduce in pd.procoptions)) or
{ new one does not have override in case of objpas/objc class/intf/proto }
(is_class_or_interface_or_objc(_class) and not is_objccategory(_class) and not(po_overridingmethod in pd.procoptions))
)
) then ) then
begin begin
if ( if (
@ -305,12 +309,18 @@ implementation
because requiring override everywhere may make because requiring override everywhere may make
automated header translation tools too complex. } automated header translation tools too complex. }
if not(oo_is_external in _class.objectoptions) then if not(oo_is_external in _class.objectoptions) then
MessagePos1(pd.fileinfo,parser_e_must_use_override_objc,pd.fullprocname(false)) if not is_objccategory(_class) then
MessagePos1(pd.fileinfo,parser_e_must_use_override_objc,pd.fullprocname(false))
else
MessagePos1(pd.fileinfo,parser_e_must_use_reintroduce_objc,pd.fullprocname(false))
{ there may be a lot of these in auto-translated { there may be a lot of these in auto-translated
heaeders, so only calculate the fullprocname if heaeders, so only calculate the fullprocname if
the hint will be shown } the hint will be shown }
else if CheckVerbosity(V_Hint) then else if CheckVerbosity(V_Hint) then
MessagePos1(pd.fileinfo,parser_h_should_use_override_objc,pd.fullprocname(false)); if not is_objccategory(_class) then
MessagePos1(pd.fileinfo,parser_h_should_use_override_objc,pd.fullprocname(false))
else
MessagePos1(pd.fileinfo,parser_h_should_use_reintroduce_objc,pd.fullprocname(false));
{ no new entry, but copy the message name if any from { no new entry, but copy the message name if any from
the procdef in the parent class } the procdef in the parent class }
check_msg_str(vmtpd,pd); check_msg_str(vmtpd,pd);

View File

@ -56,13 +56,16 @@ implementation
tobjcrttiwriter = class tobjcrttiwriter = class
protected protected
fabi: tobjcabi; fabi: tobjcabi;
classdefs: tfpobjectlist; classdefs,
classsyms: tfpobjectlist; catdefs: tfpobjectlist;
classsyms,
catsyms: tfpobjectlist;
procedure gen_objc_methods(list: tasmlist; objccls: tobjectdef; out methodslabel: tasmlabel; classmethods, iscategory: Boolean); procedure gen_objc_methods(list: tasmlist; objccls: tobjectdef; out methodslabel: tasmlabel; classmethods, iscategory: Boolean);
procedure gen_objc_protocol_list(list:TAsmList; protolist: TFPObjectList; out protolistsym: TAsmLabel); procedure gen_objc_protocol_list(list:TAsmList; protolist: TFPObjectList; out protolistsym: TAsmLabel);
procedure gen_objc_cat_methods(list:TAsmList; items: TFPObjectList; section: tasmsectiontype;const sectname: string; out listsym: TAsmLabel); procedure gen_objc_cat_methods(list:TAsmList; items: TFPObjectList; section: tasmsectiontype;const sectname: string; out listsym: TAsmLabel);
procedure gen_objc_protocol(list:TAsmList; protocol: tobjectdef; out protocollabel: TAsmSymbol);virtual;abstract; procedure gen_objc_protocol(list:TAsmList; protocol: tobjectdef; out protocollabel: TAsmSymbol);virtual;abstract;
procedure gen_objc_category_sections(list:TAsmList; objccat: tobjectdef; out catlabel: TAsmSymbol);virtual;abstract;
procedure gen_objc_classes_sections(list:TAsmList; objclss: tobjectdef; out classlabel: TAsmSymbol);virtual;abstract; procedure gen_objc_classes_sections(list:TAsmList; objclss: tobjectdef; out classlabel: TAsmSymbol);virtual;abstract;
procedure gen_objc_info_sections(list: tasmlist);virtual;abstract; procedure gen_objc_info_sections(list: tasmlist);virtual;abstract;
public public
@ -78,6 +81,7 @@ implementation
protected protected
procedure gen_objc_ivars(list: TAsmList; objccls: tobjectdef; out ivarslabel: TAsmLabel); procedure gen_objc_ivars(list: TAsmList; objccls: tobjectdef; out ivarslabel: TAsmLabel);
procedure gen_objc_protocol(list:TAsmList; protocol: tobjectdef; out protocollabel: TAsmSymbol);override; procedure gen_objc_protocol(list:TAsmList; protocol: tobjectdef; out protocollabel: TAsmSymbol);override;
procedure gen_objc_category_sections(list:TAsmList; objccat: tobjectdef; out catlabel: TAsmSymbol);override;
procedure gen_objc_classes_sections(list:TAsmList; objclss: tobjectdef; out classlabel: TAsmSymbol);override; procedure gen_objc_classes_sections(list:TAsmList; objclss: tobjectdef; out classlabel: TAsmSymbol);override;
procedure gen_objc_info_sections(list: tasmlist);override; procedure gen_objc_info_sections(list: tasmlist);override;
public public
@ -96,6 +100,7 @@ implementation
procedure gen_objc_ivars(list: TAsmList; objccls: tobjectdef; out ivarslabel: TAsmLabel); procedure gen_objc_ivars(list: TAsmList; objccls: tobjectdef; out ivarslabel: TAsmLabel);
procedure gen_objc_protocol(list:TAsmList; protocol: tobjectdef; out protocollabel: TAsmSymbol);override; procedure gen_objc_protocol(list:TAsmList; protocol: tobjectdef; out protocollabel: TAsmSymbol);override;
procedure gen_objc_category_sections(list:TAsmList; objccat: tobjectdef; out catlabel: TAsmSymbol);override;
procedure gen_objc_classes_sections(list:TAsmList; objclss: tobjectdef; out classlabel: TAsmSymbol);override; procedure gen_objc_classes_sections(list:TAsmList; objclss: tobjectdef; out classlabel: TAsmSymbol);override;
procedure gen_objc_info_sections(list: tasmlist);override; procedure gen_objc_info_sections(list: tasmlist);override;
public public
@ -277,7 +282,7 @@ procedure tobjcrttiwriter.gen_objc_methods(list: tasmlist; objccls: tobjectdef;
for i:=0 to objccls.vmtentries.count-1 do for i:=0 to objccls.vmtentries.count-1 do
begin begin
def:=pvmtentry(objccls.vmtentries[i])^.procdef; def:=pvmtentry(objccls.vmtentries[i])^.procdef;
if Assigned(def.procstarttai) and if (def.owner.defowner=objccls) and
(classmethods = (po_classmethod in def.procoptions)) then (classmethods = (po_classmethod in def.procoptions)) then
begin begin
defs[mcnt].def:=def; defs[mcnt].def:=def;
@ -290,9 +295,9 @@ procedure tobjcrttiwriter.gen_objc_methods(list: tasmlist; objccls: tobjectdef;
exit; exit;
if iscategory then if iscategory then
new_section(list,clsSectType[classmethods],clsSectName[classmethods],sizeof(ptrint)) new_section(list,catSectType[classmethods],catSectName[classmethods],sizeof(ptrint))
else else
new_section(list,catSectType[classmethods],catSectName[classmethods],sizeof(ptrint)); new_section(list,clsSectType[classmethods],clsSectName[classmethods],sizeof(ptrint));
current_asmdata.getlabel(methodslabel,alt_data); current_asmdata.getlabel(methodslabel,alt_data);
list.Concat(tai_label.Create(methodslabel)); list.Concat(tai_label.Create(methodslabel));
@ -441,9 +446,18 @@ procedure tobjcrttiwriter.gen_objc_rtti_sections(list:TAsmList; st:TSymtable);
if is_objcclass(def) and if is_objcclass(def) and
not(oo_is_external in tobjectdef(def).objectoptions) then not(oo_is_external in tobjectdef(def).objectoptions) then
begin begin
gen_objc_classes_sections(list,tobjectdef(def),sym); if not(oo_is_classhelper in tobjectdef(def).objectoptions) then
classsyms.add(sym); begin
classdefs.add(def); gen_objc_classes_sections(list,tobjectdef(def),sym);
classsyms.add(sym);
classdefs.add(def);
end
else
begin
gen_objc_category_sections(list,tobjectdef(def),sym);
catsyms.add(sym);
catdefs.add(def);
end
end; end;
end; end;
end; end;
@ -454,6 +468,8 @@ constructor tobjcrttiwriter.create(_abi: tobjcabi);
fabi:=_abi; fabi:=_abi;
classdefs:=tfpobjectlist.create(false); classdefs:=tfpobjectlist.create(false);
classsyms:=tfpobjectlist.create(false); classsyms:=tfpobjectlist.create(false);
catdefs:=tfpobjectlist.create(false);
catsyms:=tfpobjectlist.create(false);
end; end;
@ -461,6 +477,8 @@ destructor tobjcrttiwriter.destroy;
begin begin
classdefs.free; classdefs.free;
classsyms.free; classsyms.free;
catdefs.free;
catsyms.free;
inherited destroy; inherited destroy;
end; end;
@ -584,6 +602,61 @@ procedure tobjcrttiwriter_fragile.gen_objc_protocol(list:TAsmList; protocol: tob
end; end;
(*
From Clang:
struct _objc_category {
char *category_name;
char *class_name;
struct _objc_method_list *instance_methods;
struct _objc_method_list *class_methods;
struct _objc_protocol_list *protocols;
uint32_t size; // <rdar://4585769>
struct _objc_property_list *instance_properties;
};
*)
{ Generate rtti for an Objective-C class and its meta-class. }
procedure tobjcrttiwriter_fragile.gen_objc_category_sections(list:TAsmList; objccat: tobjectdef; out catlabel: TAsmSymbol);
var
instmthdlist,
clsmthdlist,
protolistsym : TAsmLabel;
catstrsym,
clsstrsym,
catsym : TAsmSymbol;
begin
{ the category name }
catstrsym:=objcreatestringpoolentry(objccat.objextname^,sp_objcclassnames,sec_objc_class_names);
{ the name of the class it extends }
clsstrsym:=objcreatestringpoolentry(objccat.childof.objextname^,sp_objcclassnames,sec_objc_class_names);
{ generate the methods lists }
gen_objc_methods(list,objccat,instmthdlist,false,true);
gen_objc_methods(list,objccat,clsmthdlist,true,true);
{ generate implemented protocols list }
gen_objc_protocol_list(list,objccat.ImplementedInterfaces,protolistsym);
{ category declaration section }
new_section(list,sec_objc_category,'_OBJC_CATEGORY',sizeof(pint));
catsym:=current_asmdata.DefineAsmSymbol(objccat.rtti_mangledname(objcclassrtti),AB_LOCAL,AT_DATA);
list.Concat(tai_symbol.Create(catsym,0));
list.Concat(Tai_const.Create_sym(catstrsym));
list.Concat(Tai_const.Create_sym(clsstrsym));
ConcatSymOrNil(list,instmthdlist);
ConcatSymOrNil(list,clsmthdlist);
ConcatSymOrNil(list,protolistsym);
{ size of this structure }
list.Concat(Tai_const.Create_32bit(28));
{ properties, not yet supported }
list.Concat(Tai_const.Create_32bit(0));
catlabel:=catsym;
end;
(* (*
From Clang: From Clang:
@ -604,6 +677,8 @@ From Clang:
}; };
*) *)
{ Generate rtti for an Objective-C class and its meta-class. } { Generate rtti for an Objective-C class and its meta-class. }
procedure tobjcrttiwriter_fragile.gen_objc_classes_sections(list:TAsmList; objclss: tobjectdef; out classlabel: TAsmSymbol); procedure tobjcrttiwriter_fragile.gen_objc_classes_sections(list:TAsmList; objclss: tobjectdef; out classlabel: TAsmSymbol);
const const
@ -705,7 +780,7 @@ procedure tobjcrttiwriter_fragile.gen_objc_classes_sections(list:TAsmList; objcl
clssym:=current_asmdata.DefineAsmSymbol(objclss.rtti_mangledname(objcclassrtti),AB_LOCAL,AT_DATA); clssym:=current_asmdata.DefineAsmSymbol(objclss.rtti_mangledname(objcclassrtti),AB_LOCAL,AT_DATA);
list.Concat(tai_symbol.Create(clssym,0)); list.Concat(tai_symbol.Create(clssym,0));
{ for class declaration: the is points to the meta-class declaration } { for class declaration: the isa points to the meta-class declaration }
list.Concat(Tai_const.Create_sym(metasym)); list.Concat(Tai_const.Create_sym(metasym));
{ pointer to the super_class name if any, nil otherwise } { pointer to the super_class name if any, nil otherwise }
if assigned(superStrSym) then if assigned(superStrSym) then
@ -752,7 +827,8 @@ procedure tobjcrttiwriter_fragile.gen_objc_info_sections(list: tasmlist);
parent: tobjectdef; parent: tobjectdef;
superclasses: tfpobjectlist; superclasses: tfpobjectlist;
begin begin
if (classsyms.count<>0) then if (classsyms.count<>0) or
(catsyms.count<>0) then
begin begin
new_section(list,sec_objc_symbols,'_OBJC_SYMBOLS',sizeof(pint)); new_section(list,sec_objc_symbols,'_OBJC_SYMBOLS',sizeof(pint));
sym := current_asmdata.DefineAsmSymbol(target_asm.labelprefix+'_OBJC_SYMBOLS_$',AB_LOCAL,AT_DATA); sym := current_asmdata.DefineAsmSymbol(target_asm.labelprefix+'_OBJC_SYMBOLS_$',AB_LOCAL,AT_DATA);
@ -766,11 +842,13 @@ procedure tobjcrttiwriter_fragile.gen_objc_info_sections(list: tasmlist);
{ From Clang: number of defined classes } { From Clang: number of defined classes }
list.Concat(Tai_const.Create_16bit(classsyms.count)); list.Concat(Tai_const.Create_16bit(classsyms.count));
{ From Clang: number of defined categories } { From Clang: number of defined categories }
list.Concat(Tai_const.Create_16bit(0)); list.Concat(Tai_const.Create_16bit(catsyms.count));
{ first all classes } { first all classes }
for i:=0 to classsyms.count-1 do for i:=0 to classsyms.count-1 do
list.Concat(Tai_const.Create_sym(tasmsymbol(classsyms[i]))); list.Concat(Tai_const.Create_sym(tasmsymbol(classsyms[i])));
{ then all categories } { then all categories }
for i:=0 to catsyms.count-1 do
list.Concat(Tai_const.Create_sym(tasmsymbol(catsyms[i])));
end end
else else
sym:=nil; sym:=nil;
@ -801,10 +879,25 @@ procedure tobjcrttiwriter_fragile.gen_objc_info_sections(list: tasmlist);
superclasses.add(parent); superclasses.add(parent);
end; end;
end; end;
for i:=0 to catdefs.count-1 do
begin
parent:=tobjectdef(catdefs[i]).childof;
{ warning: linear search, performance hazard if large number of subclasses }
if assigned(parent) and
(superclasses.indexof(parent)=-1) then
begin
list.concat(tai_directive.create(asd_lazy_reference,'.objc_class_name_'+parent.objextname^));
superclasses.add(parent);
end;
end;
superclasses.free; superclasses.free;
{ reference symbols for all classes defined in this unit } { reference symbols for all classes and categories defined in this unit }
for i:=0 to classdefs.count-1 do for i:=0 to classdefs.count-1 do
list.concat(tai_symbol.Createname_global_value('.objc_class_name_'+tobjectdef(classdefs[i]).objextname^,AT_DATA,0,0)); list.concat(tai_symbol.Createname_global_value('.objc_class_name_'+tobjectdef(classdefs[i]).objextname^,AT_DATA,0,0));
for i:=0 to catdefs.count-1 do
list.concat(tai_symbol.Createname_global_value('.objc_category_name_'+
tobjectdef(catdefs[i]).childof.objextname^+'_'+
tobjectdef(catdefs[i]).objextname^,AT_DATA,0,0));
end; end;
@ -1043,6 +1136,55 @@ procedure tobjcrttiwriter_nonfragile.gen_objc_protocol(list: tasmlist; protocol:
list.Concat(tai_directive.Create(asd_weak_definition,listsym.name)); list.Concat(tai_directive.Create(asd_weak_definition,listsym.name));
end; end;
(*
From Clang:
/// struct _category_t {
/// const char * const name;
/// struct _class_t *const cls;
/// const struct _method_list_t * const instance_methods;
/// const struct _method_list_t * const class_methods;
/// const struct _protocol_list_t * const protocols;
/// const struct _prop_list_t * const properties;
/// }
*)
procedure tobjcrttiwriter_nonfragile.gen_objc_category_sections(list:TAsmList; objccat: tobjectdef; out catlabel: TAsmSymbol);
var
instmthdlist,
clsmthdlist,
protolistsym : TAsmLabel;
catstrsym,
clssym,
catsym : TAsmSymbol;
begin
{ the category name }
catstrsym:=objcreatestringpoolentry(objccat.objextname^,sp_objcclassnames,sec_objc_class_names);
{ the class it extends }
clssym:=current_asmdata.RefAsmSymbol(objccat.childof.rtti_mangledname(objcclassrtti));
{ generate the methods lists }
gen_objc_methods(list,objccat,instmthdlist,false,true);
gen_objc_methods(list,objccat,clsmthdlist,true,true);
{ generate implemented protocols list }
gen_objc_protocol_list(list,objccat.ImplementedInterfaces,protolistsym);
{ category declaration section }
new_section(list,sec_objc_const,'_OBJC_CATEGORY',sizeof(pint));
catsym:=current_asmdata.DefineAsmSymbol(objccat.rtti_mangledname(objcclassrtti),AB_LOCAL,AT_DATA);
list.Concat(tai_symbol.Create(catsym,0));
list.Concat(Tai_const.Create_sym(catstrsym));
list.Concat(Tai_const.Create_sym(clssym));
ConcatSymOrNil(list,instmthdlist);
ConcatSymOrNil(list,clsmthdlist);
ConcatSymOrNil(list,protolistsym);
{ properties, not yet supported }
list.Concat(Tai_const.Create_pint(0));
catlabel:=catsym;
end;
(* (*
From Clang: From Clang:
@ -1363,45 +1505,58 @@ procedure tobjcrttiwriter_nonfragile.addclasslist(list: tasmlist; section: tasms
procedure tobjcrttiwriter_nonfragile.gen_objc_info_sections(list: tasmlist); procedure tobjcrttiwriter_nonfragile.gen_objc_info_sections(list: tasmlist);
function collectnonlazyclasses(classes: tfpobjectlist): tfpobjectlist;
var
symentry : tsym;
procdef : tprocdef;
i,j : longint;
begin
{ non-lazy classes are all classes that define a class method with the
selector called "load" (simply inheriting this class method is not enough,
they have to implement it themselves)
-- TODO: this currently only works if the Pascal identifier is also 'load'! }
result:=tfpobjectlist.create(false);
for i:=0 to classes.count-1 do
begin
symentry:=tsym(tobjectsymtable(tobjectdef(classes[i]).symtable).find('LOAD'));
if assigned(symentry) and
(symentry.typ=procsym) then
begin
for j:=0 to tprocsym(symentry).ProcdefList.count do
begin
procdef:=tprocdef(tprocsym(symentry).ProcdefList[0]);
if ((po_classmethod in procdef.procoptions) and
(procdef.messageinf.str^='load')) then
begin
result.add(classes[i]);
break;
end;
end;
end;
end;
end;
var var
i,j : longint; nonlazyclasses,
symentry : tsym; nonlazycategories : tfpobjectlist;
procdef : tprocdef;
nonlazyclasses : tfpobjectlist;
begin begin
if (classsyms.count=0) then if (classdefs.count=0) and
(catdefs.count=0) then
exit; exit;
{ non-lazy classes are all classes that define a class method with the nonlazyclasses:=collectnonlazyclasses(classdefs);
selector called "load" (simply inheriting this class method is not enough, nonlazycategories:=collectnonlazyclasses(catdefs);
they have to implement it themselves)
-- TODO: this currently only works if the Pascal identifier is also 'load'! }
nonlazyclasses:=tfpobjectlist.create(false);
for i:=0 to classdefs.count-1 do
begin
symentry:=tsym(tobjectsymtable(tobjectdef(classdefs[i]).symtable).find('LOAD'));
if assigned(symentry) and
(symentry.typ=procsym) then
begin
for j:=0 to tprocsym(symentry).ProcdefList.count do
begin
procdef:=tprocdef(tprocsym(symentry).ProcdefList[0]);
if ((po_classmethod in procdef.procoptions) and
(procdef.messageinf.str^='load')) then
begin
nonlazyclasses.add(classdefs[i]);
break;
end;
end;
end;
end;
{ this list has to include all classes, also the non-lazy ones } { this list has to include all classes, also the non-lazy ones }
addclasslist(list,sec_objc_classlist,target_asm.labelprefix+'_OBJC_LABEL_CLASS_$',classdefs); addclasslist(list,sec_objc_classlist,target_asm.labelprefix+'_OBJC_LABEL_CLASS_$',classdefs);
addclasslist(list,sec_objc_nlclasslist,target_asm.labelprefix+'_OBJC_LABEL_NONLAZY_CLASS_$',nonlazyclasses); addclasslist(list,sec_objc_nlclasslist,target_asm.labelprefix+'_OBJC_LABEL_NONLAZY_CLASS_$',nonlazyclasses);
{ TODO: category and non-lazy category lists } { category and non-lazy category lists }
addclasslist(list,sec_objc_catlist,target_asm.labelprefix+'_OBJC_LABEL_CATEGORY_$',catdefs);
addclasslist(list,sec_objc_nlcatlist,target_asm.labelprefix+'_OBJC_LABEL_NONLAZY_CATEGORY_$',nonlazycategories);
nonlazyclasses.free;
nonlazycategories.free;
{ the non-fragile abi doesn't have any module info, nor lazy references { the non-fragile abi doesn't have any module info, nor lazy references
to used classes or to parent classes } to used classes or to parent classes }
end; end;
@ -1431,7 +1586,7 @@ procedure MaybeGenerateObjectiveCImageInfo(globalst, localst: tsymtable);
current_asmdata.asmlists[al_objc_data].concat(Tai_symbol.Createname(target_asm.labelprefix+'_OBJC_IMAGE_INFO',AT_LABEL,sizeof(pint))); current_asmdata.asmlists[al_objc_data].concat(Tai_symbol.Createname(target_asm.labelprefix+'_OBJC_IMAGE_INFO',AT_LABEL,sizeof(pint)));
current_asmdata.asmlists[al_objc_data].concat(Tai_const.Create_64bit(0)); current_asmdata.asmlists[al_objc_data].concat(Tai_const.Create_64bit(0));
{ generate rtti for all obj-c classes, protocols and categories (todo) { generate rtti for all obj-c classes, protocols and categories
defined in this module. } defined in this module. }
if not(target_info.system in system_objc_nfabi) then if not(target_info.system in system_objc_nfabi) then
objcrttiwriter:=tobjcrttiwriter_fragile.create objcrttiwriter:=tobjcrttiwriter_fragile.create

View File

@ -117,11 +117,22 @@ end;
objcsuperclassnode objcsuperclassnode
*******************************************************************} *******************************************************************}
function objcloadbasefield(n: tnode; const fieldname: string): tnode;
var
vs : tsym;
begin
result:=ctypeconvnode.create_internal(cderefnode.create(ctypeconvnode.create_internal(n,voidpointertype)),objc_objecttype);
vs:=tsym(tabstractrecorddef(objc_objecttype).symtable.Find(fieldname));
if not assigned(vs) or
(vs.typ<>fieldvarsym) then
internalerror(200911301);
result:=csubscriptnode.create(vs,result);
end;
function objcsuperclassnode(def: tdef): tnode; function objcsuperclassnode(def: tdef): tnode;
var var
para : tcallparanode; para : tcallparanode;
class_type : tdef;
vs : tsym;
begin begin
{ only valid for Objective-C classes and classrefs } { only valid for Objective-C classes and classrefs }
if not is_objcclass(def) and if not is_objcclass(def) and
@ -131,11 +142,30 @@ end;
requires extra node types. Maybe later. } requires extra node types. Maybe later. }
if is_objcclassref(def) then if is_objcclassref(def) then
begin begin
para:=ccallparanode.create(cstringconstnode.createstr(tobjectdef(tclassrefdef(def).pointeddef).objextname^),nil); if (oo_is_classhelper in tobjectdef(tclassrefdef(def).pointeddef).objectoptions) then
result:=ccallnode.createinternfromunit('OBJC','OBJC_GETMETACLASS',para); begin
{ in case we are in a category method, we need the metaclass of the
superclass class extended by this category (= metaclass of superclass of superclass) }
result:=cloadvmtaddrnode.create(ctypenode.create(tobjectdef(tclassrefdef(def).pointeddef).childof.childof));
result:=objcloadbasefield(result,'ISA');
typecheckpass(result);
{ we're done }
exit;
end
else
begin
{ otherwise we need the superclass of the metaclass }
para:=ccallparanode.create(cstringconstnode.createstr(tobjectdef(tclassrefdef(def).pointeddef).objextname^),nil);
result:=ccallnode.createinternfromunit('OBJC','OBJC_GETMETACLASS',para);
end
end end
else else
result:=cloadvmtaddrnode.create(ctypenode.create(def)); begin
if not(oo_is_classhelper in tobjectdef(def).objectoptions) then
result:=cloadvmtaddrnode.create(ctypenode.create(def))
else
result:=cloadvmtaddrnode.create(ctypenode.create(tobjectdef(def).childof))
end;
{$if defined(onlymacosx10_6) or defined(arm) } {$if defined(onlymacosx10_6) or defined(arm) }
{ For the non-fragile ABI, the superclass send2 method itself loads the { For the non-fragile ABI, the superclass send2 method itself loads the
@ -145,15 +175,7 @@ end;
(but also on all iPhone SDK revisions we support) } (but also on all iPhone SDK revisions we support) }
if not(target_info.system in system_objc_nfabi) then if not(target_info.system in system_objc_nfabi) then
{$endif onlymacosx10_6 or arm} {$endif onlymacosx10_6 or arm}
begin result:=objcloadbasefield(result,'SUPERCLASS');
class_type:=search_named_unit_globaltype('OBJC','OBJC_OBJECT').typedef;
result:=ctypeconvnode.create_internal(cderefnode.create(ctypeconvnode.create_internal(result,voidpointertype)),class_type);
vs:=tsym(tabstractrecorddef(class_type).symtable.Find('SUPERCLASS'));
if not assigned(vs) or
(vs.typ<>fieldvarsym) then
internalerror(200909301);
result:=csubscriptnode.create(vs,result);
end;
typecheckpass(result); typecheckpass(result);
end; end;

View File

@ -440,7 +440,8 @@ implementation
(token=_INTERFACE) or (token=_INTERFACE) or
(token=_DISPINTERFACE) or (token=_DISPINTERFACE) or
(token=_OBJCCLASS) or (token=_OBJCCLASS) or
(token=_OBJCPROTOCOL)) and (token=_OBJCPROTOCOL) or
(token=_OBJCCATEGORY)) and
(assigned(ttypesym(sym).typedef)) and (assigned(ttypesym(sym).typedef)) and
is_class_or_interface_or_dispinterface_or_objc(ttypesym(sym).typedef) and is_class_or_interface_or_dispinterface_or_objc(ttypesym(sym).typedef) and
(oo_is_forward in tobjectdef(ttypesym(sym).typedef).objectoptions) then (oo_is_forward in tobjectdef(ttypesym(sym).typedef).objectoptions) then
@ -455,7 +456,8 @@ implementation
objecttype:=odt_interfacecorba; objecttype:=odt_interfacecorba;
_DISPINTERFACE : _DISPINTERFACE :
objecttype:=odt_dispinterface; objecttype:=odt_dispinterface;
_OBJCCLASS : _OBJCCLASS,
_OBJCCATEGORY :
objecttype:=odt_objcclass; objecttype:=odt_objcclass;
_OBJCPROTOCOL : _OBJCPROTOCOL :
objecttype:=odt_objcprotocol; objecttype:=odt_objcprotocol;

View File

@ -313,15 +313,20 @@ implementation
hasparentdefined:=false; hasparentdefined:=false;
{ reads the parent class } { reads the parent class }
if try_to_consume(_LKLAMMER) then if (token=_LKLAMMER) or
is_objccategory(current_objectdef) then
begin begin
consume(_LKLAMMER);
{ use single_type instead of id_type for specialize support } { use single_type instead of id_type for specialize support }
single_type(hdef,false,false); single_type(hdef,false,false);
if (not assigned(hdef)) or if (not assigned(hdef)) or
(hdef.typ<>objectdef) then (hdef.typ<>objectdef) then
begin begin
if assigned(hdef) then if assigned(hdef) then
Message1(type_e_class_type_expected,hdef.typename); Message1(type_e_class_type_expected,hdef.typename)
else if is_objccategory(current_objectdef) then
{ a category must specify the class to extend }
Message(type_e_objcclass_type_expected);
end end
else else
begin begin
@ -358,13 +363,20 @@ implementation
if not(is_cppclass(childof)) then if not(is_cppclass(childof)) then
Message(parser_e_mix_of_classes_and_objects); Message(parser_e_mix_of_classes_and_objects);
odt_objcclass: odt_objcclass:
if not(is_objcclass(childof)) then if not(is_objcclass(childof) or
is_objccategory(childof)) then
begin begin
if is_objcprotocol(childof) then if is_objcprotocol(childof) then
begin begin
intfchildof:=childof; if not(oo_is_classhelper in current_objectdef.objectoptions) then
childof:=nil; begin
CGMessage(parser_h_no_objc_parent); intfchildof:=childof;
childof:=nil;
CGMessage(parser_h_no_objc_parent);
end
else
{ a category must specify the class to extend }
CGMessage(type_e_objcclass_type_expected);
end end
else else
Message(parser_e_mix_of_classes_and_objects); Message(parser_e_mix_of_classes_and_objects);
@ -562,7 +574,7 @@ implementation
_PRIVATE : _PRIVATE :
begin begin
if is_interface(current_objectdef) or if is_interface(current_objectdef) or
is_objcprotocol(current_objectdef) then is_objc_protocol_or_category(current_objectdef) then
Message(parser_e_no_access_specifier_in_interfaces); Message(parser_e_no_access_specifier_in_interfaces);
consume(_PRIVATE); consume(_PRIVATE);
current_objectdef.symtable.currentvisibility:=vis_private; current_objectdef.symtable.currentvisibility:=vis_private;
@ -572,7 +584,7 @@ implementation
_PROTECTED : _PROTECTED :
begin begin
if is_interface(current_objectdef) or if is_interface(current_objectdef) or
is_objcprotocol(current_objectdef) then is_objc_protocol_or_category(current_objectdef) then
Message(parser_e_no_access_specifier_in_interfaces); Message(parser_e_no_access_specifier_in_interfaces);
consume(_PROTECTED); consume(_PROTECTED);
current_objectdef.symtable.currentvisibility:=vis_protected; current_objectdef.symtable.currentvisibility:=vis_protected;
@ -582,7 +594,7 @@ implementation
_PUBLIC : _PUBLIC :
begin begin
if is_interface(current_objectdef) or if is_interface(current_objectdef) or
is_objcprotocol(current_objectdef) then is_objc_protocol_or_category(current_objectdef) then
Message(parser_e_no_access_specifier_in_interfaces); Message(parser_e_no_access_specifier_in_interfaces);
consume(_PUBLIC); consume(_PUBLIC);
current_objectdef.symtable.currentvisibility:=vis_public; current_objectdef.symtable.currentvisibility:=vis_public;
@ -593,8 +605,7 @@ implementation
{ we've to check for a pushlished section in non- } { we've to check for a pushlished section in non- }
{ publishable classes later, if a real declaration } { publishable classes later, if a real declaration }
{ this is the way, delphi does it } { this is the way, delphi does it }
if is_interface(current_objectdef) or if is_interface(current_objectdef) then
is_objcprotocol(current_objectdef) then
Message(parser_e_no_access_specifier_in_interfaces); Message(parser_e_no_access_specifier_in_interfaces);
{ Objective-C classes do not support "published", { Objective-C classes do not support "published",
as basically everything is published. } as basically everything is published. }
@ -607,7 +618,7 @@ implementation
_STRICT : _STRICT :
begin begin
if is_interface(current_objectdef) or if is_interface(current_objectdef) or
is_objcprotocol(current_objectdef) then is_objc_protocol_or_category(current_objectdef) then
Message(parser_e_no_access_specifier_in_interfaces); Message(parser_e_no_access_specifier_in_interfaces);
consume(_STRICT); consume(_STRICT);
if token=_ID then if token=_ID then
@ -638,7 +649,7 @@ implementation
if object_member_blocktype=bt_general then if object_member_blocktype=bt_general then
begin begin
if is_interface(current_objectdef) or if is_interface(current_objectdef) or
is_objcprotocol(current_objectdef) then is_objc_protocol_or_category(current_objectdef) then
Message(parser_e_no_vars_in_interfaces); Message(parser_e_no_vars_in_interfaces);
if (current_objectdef.symtable.currentvisibility=vis_published) and if (current_objectdef.symtable.currentvisibility=vis_published) and
@ -871,6 +882,13 @@ implementation
end end
else else
begin begin
{ change objccategories into objcclass helpers }
if (objecttype=odt_objccategory) then
begin
current_objectdef.objecttype:=odt_objcclass;
include(current_objectdef.objectoptions,oo_is_classhelper);
end;
{ parse list of options (abstract / sealed) } { parse list of options (abstract / sealed) }
parse_object_options; parse_object_options;

View File

@ -1413,7 +1413,9 @@ begin
if pd.typ<>procdef then if pd.typ<>procdef then
internalerror(2003042611); internalerror(2003042611);
if not(is_class_or_interface_or_objc(tprocdef(pd)._class)) then if not(is_class_or_interface_or_objc(tprocdef(pd)._class)) then
Message(parser_e_no_object_override); Message(parser_e_no_object_override)
else if is_objccategory(tprocdef(pd)._class) then
Message(parser_e_no_category_override);
end; end;
procedure pd_overload(pd:tabstractprocdef); procedure pd_overload(pd:tabstractprocdef);
@ -1483,7 +1485,8 @@ procedure pd_reintroduce(pd:tabstractprocdef);
begin begin
if pd.typ<>procdef then if pd.typ<>procdef then
internalerror(200401211); internalerror(200401211);
if not(is_class_or_interface_or_object(tprocdef(pd)._class)) then if not(is_class_or_interface_or_object(tprocdef(pd)._class)) and
not(is_objccategory(tprocdef(pd)._class)) then
Message(parser_e_no_object_reintroduce); Message(parser_e_no_object_reintroduce);
end; end;
@ -2036,7 +2039,7 @@ const
mutexclpo : [po_external] mutexclpo : [po_external]
),( ),(
idtok:_REINTRODUCE; idtok:_REINTRODUCE;
pd_flags : [pd_interface,pd_object,pd_notobjintf]; pd_flags : [pd_interface,pd_object,pd_notobjintf,pd_objcclass];
handler : @pd_reintroduce; handler : @pd_reintroduce;
pocall : pocall_none; pocall : pocall_none;
pooption : [po_reintroduce]; pooption : [po_reintroduce];

View File

@ -493,7 +493,12 @@ implementation
begin begin
Message(parser_e_no_generics_as_types); Message(parser_e_no_generics_as_types);
def:=generrordef; def:=generrordef;
end; end
else if is_objccategory(def) then
begin
Message(parser_e_no_category_as_types);
def:=generrordef
end
end; end;
end; end;
@ -622,7 +627,12 @@ implementation
begin begin
Message(parser_e_no_generics_as_types); Message(parser_e_no_generics_as_types);
def:=generrordef; def:=generrordef;
end; end
else if is_objccategory(def) then
begin
Message(parser_e_no_category_as_types);
def:=generrordef
end
end; end;
end end
else else
@ -1023,6 +1033,14 @@ implementation
consume(token); consume(token);
def:=object_dec(odt_objcprotocol,name,genericdef,genericlist,nil); def:=object_dec(odt_objcprotocol,name,genericdef,genericlist,nil);
end; end;
_OBJCCATEGORY :
begin
if not(m_objectivec1 in current_settings.modeswitches) then
Message(parser_f_need_objc);
consume(token);
def:=object_dec(odt_objccategory,name,genericdef,genericlist,nil);
end;
_OBJECT : _OBJECT :
begin begin
consume(token); consume(token);

View File

@ -117,6 +117,9 @@ const
paranr_syscall_legacy = high(word)-2; paranr_syscall_legacy = high(word)-2;
paranr_result_leftright = high(word)-1; paranr_result_leftright = high(word)-1;
{ prefix for names of class helper procsyms added to regular symtables }
class_helper_prefix = 'CH$';
type type
{ keep this in sync with TIntfFlag in rtl/objpas/typinfo.pp } { keep this in sync with TIntfFlag in rtl/objpas/typinfo.pp }
@ -302,7 +305,8 @@ type
odt_cppclass, odt_cppclass,
odt_dispinterface, odt_dispinterface,
odt_objcclass, odt_objcclass,
odt_objcprotocol odt_objcprotocol,
odt_objccategory { note that these are changed into odt_class afterwards }
); );
{ Variations in interfaces implementation } { Variations in interfaces implementation }
@ -335,7 +339,8 @@ type
oo_has_enumerator_movenext, oo_has_enumerator_movenext,
oo_has_enumerator_current, oo_has_enumerator_current,
oo_is_external, { the class is externally implemented (objcclass, cppclass) } oo_is_external, { the class is externally implemented (objcclass, cppclass) }
oo_is_anonymous { the class is only formally defined in this module (objcclass x = class; external;) } oo_is_anonymous, { the class is only formally defined in this module (objcclass x = class; external;) }
oo_is_classhelper { objcclasses that represent categories, and Delpi-style class helpers, are marked like this }
); );
tobjectoptions=set of tobjectoption; tobjectoptions=set of tobjectoption;

View File

@ -685,6 +685,7 @@ interface
objc_superclasstype, objc_superclasstype,
objc_idtype, objc_idtype,
objc_seltype : tpointerdef; objc_seltype : tpointerdef;
objc_objecttype : trecorddef;
{ base type of @protocol(protocolname) Objective-C statements } { base type of @protocol(protocolname) Objective-C statements }
objc_protocoltype : tobjectdef; objc_protocoltype : tobjectdef;
@ -739,7 +740,9 @@ interface
function is_objcclass(def: tdef): boolean; function is_objcclass(def: tdef): boolean;
function is_objcclassref(def: tdef): boolean; function is_objcclassref(def: tdef): boolean;
function is_objcprotocol(def: tdef): boolean; function is_objcprotocol(def: tdef): boolean;
function is_objccategory(def: tdef): boolean;
function is_objc_class_or_protocol(def: tdef): boolean; function is_objc_class_or_protocol(def: tdef): boolean;
function is_objc_protocol_or_category(def: tdef): boolean;
function is_class_or_interface(def: tdef): boolean; function is_class_or_interface(def: tdef): boolean;
function is_class_or_interface_or_objc(def: tdef): boolean; function is_class_or_interface_or_objc(def: tdef): boolean;
function is_class_or_interface_or_object(def: tdef): boolean; function is_class_or_interface_or_object(def: tdef): boolean;
@ -3582,12 +3585,19 @@ implementation
function tprocdef.objcmangledname : string; function tprocdef.objcmangledname : string;
var
manglednamelen: longint;
iscatmethod : boolean;
begin begin
if not (po_msgstr in procoptions) then if not (po_msgstr in procoptions) then
internalerror(2009030901); internalerror(2009030901);
{ we may very well need longer strings to handle these... } { we may very well need longer strings to handle these... }
if ((255-length(tobjectdef(procsym.owner.defowner).objextname^) manglednamelen:=length(tobjectdef(procsym.owner.defowner).objextname^)+
-length('+"[ ]"')-length(messageinf.str^)) < 0) then length('+"[ ]"')+length(messageinf.str^);
iscatmethod:=oo_is_classhelper in tobjectdef(procsym.owner.defowner).objectoptions;
if (iscatmethod) then
inc(manglednamelen,length(tobjectdef(procsym.owner.defowner).childof.objextname^)+length('()'));
if manglednamelen>255 then
Message1(parser_e_objc_message_name_too_long,messageinf.str^); Message1(parser_e_objc_message_name_too_long,messageinf.str^);
if not(po_classmethod in procoptions) then if not(po_classmethod in procoptions) then
result:='"-[' result:='"-['
@ -3596,9 +3606,12 @@ implementation
{ quotes are necessary because the +/- otherwise confuse the assembler { quotes are necessary because the +/- otherwise confuse the assembler
into expecting a number into expecting a number
} }
result:= if iscatmethod then
result+tobjectdef(procsym.owner.defowner).objextname^+' '+ result:=result+tobjectdef(procsym.owner.defowner).childof.objextname^+'(';
messageinf.str^+']"'; result:=result+tobjectdef(procsym.owner.defowner).objextname^;
if iscatmethod then
result:=result+')';
result:=result+' '+messageinf.str^+']"';
end; end;
@ -4082,6 +4095,36 @@ implementation
end; end;
procedure create_class_helper_for_procdef(def: tobject; arg: pointer);
var
pd: tprocdef absolute def;
st: tsymtable;
psym: tsym;
nname: TIDString;
begin
if (tdef(def).typ<>procdef) then
exit;
{ pd.owner = objcclass symtable -> defowner = objcclassdef ->
owner = symtable in which objcclassdef is defined
}
st:=pd.owner.defowner.owner;
nname:=class_helper_prefix+tprocsym(pd.procsym).name;
{ check for an existing procsym with our special name }
psym:=tsym(st.find(nname));
if not assigned(psym) then
begin
psym:=tprocsym.create(nname);
{ avoid warning about this symbol being unused }
psym.IncRefCount;
st.insert(psym,true);
end
else if (psym.typ<>procsym) then
internalerror(2009111501);
{ add ourselves to this special procsym }
tprocsym(psym).procdeflist.add(def);
end;
procedure tobjectdef.buildderefimpl; procedure tobjectdef.buildderefimpl;
begin begin
inherited buildderefimpl; inherited buildderefimpl;
@ -4095,6 +4138,10 @@ implementation
inherited derefimpl; inherited derefimpl;
if not (df_copied_def in defoptions) then if not (df_copied_def in defoptions) then
tstoredsymtable(symtable).derefimpl; tstoredsymtable(symtable).derefimpl;
{ the procdefs are not owned by the class helper procsyms, so they
are not stored/restored either -> re-add them here }
if (oo_is_classhelper in objectoptions) then
symtable.DefList.ForEachCall(@create_class_helper_for_procdef,nil);
end; end;
@ -4385,9 +4432,15 @@ implementation
begin begin
case rt of case rt of
objcclassrtti: objcclassrtti:
result:=result+'_OBJC_CLASS_'; if not(oo_is_classhelper in objectoptions) then
result:=result+'_OBJC_CLASS_'
else
result:=result+'_OBJC_CATEGORY_';
objcmetartti: objcmetartti:
result:=result+'_OBJC_METACLASS_'; if not(oo_is_classhelper in objectoptions) then
result:=result+'_OBJC_METACLASS_'
else
internalerror(2009111511);
else else
internalerror(2009092302); internalerror(2009092302);
end; end;
@ -4401,9 +4454,15 @@ implementation
case objecttype of case objecttype of
odt_objcclass: odt_objcclass:
begin begin
if (oo_is_classhelper in objectoptions) and
(rt<>objcclassrtti) then
internalerror(2009111512);
case rt of case rt of
objcclassrtti: objcclassrtti:
result:='_OBJC_CLASS_$_'; if not(oo_is_classhelper in objectoptions) then
result:='_OBJC_CLASS_$_'
else
result:='_OBJC_$_CATEGORY_';
objcmetartti: objcmetartti:
result:='_OBJC_METACLASS_$_'; result:='_OBJC_METACLASS_$_';
objcclassrortti: objcclassrortti:
@ -4656,35 +4715,43 @@ implementation
begin begin
if (def.typ=procdef) then if (def.typ=procdef) then
begin begin
{ add all messages also under a dummy name to the symtable in
which the objcclass/protocol/category is declared, so they can
be called via id.<name>
}
create_class_helper_for_procdef(pd,nil);
{ we have to wait until now to set the mangled name because it { we have to wait until now to set the mangled name because it
depends on the (possibly external) class name, which is defined depends on the (possibly external) class name, which is defined
at the very end. } at the very end. }
if (po_msgstr in pd.procoptions) then if not(po_msgstr in pd.procoptions) then
begin begin
{ Mangled name is already set in case this is a copy of CGMessagePos(pd.fileinfo,parser_e_objc_requires_msgstr);
another type. } { recover to avoid internalerror later on }
if not(po_has_mangledname in pd.procoptions) then include(pd.procoptions,po_msgstr);
begin pd.messageinf.str:=stringdup('MissingDeclaration');
{ check whether the number of formal parameters is correct } end;
paracount:=0; { Mangled name is already set in case this is a copy of
for i:=1 to length(pd.messageinf.str^) do another type. }
if pd.messageinf.str^[i]=':' then if not(po_has_mangledname in pd.procoptions) then
inc(paracount); begin
for i:=0 to pd.paras.count-1 do { check whether the number of formal parameters is correct }
if not(vo_is_hidden_para in tparavarsym(pd.paras[i]).varoptions) and paracount:=0;
not is_array_of_const(tparavarsym(pd.paras[i]).vardef) then for i:=1 to length(pd.messageinf.str^) do
dec(paracount); if pd.messageinf.str^[i]=':' then
if (paracount<>0) then inc(paracount);
MessagePos(pd.fileinfo,sym_e_objc_para_mismatch); for i:=0 to pd.paras.count-1 do
if not(vo_is_hidden_para in tparavarsym(pd.paras[i]).varoptions) and
not is_array_of_const(tparavarsym(pd.paras[i]).vardef) then
dec(paracount);
if (paracount<>0) then
MessagePos(pd.fileinfo,sym_e_objc_para_mismatch);
pd.setmangledname(pd.objcmangledname); pd.setmangledname(pd.objcmangledname);
end
else
{ all checks already done }
exit;
end end
else else
MessagePos(pd.fileinfo,parser_e_objc_requires_msgstr); { all checks already done }
exit;
if not(oo_is_external in pd._class.objectoptions) then if not(oo_is_external in pd._class.objectoptions) then
begin begin
if (po_varargs in pd.procoptions) then if (po_varargs in pd.procoptions) then
@ -5065,6 +5132,18 @@ implementation
end; end;
function is_objccategory(def: tdef): boolean;
begin
result:=
assigned(def) and
(def.typ=objectdef) and
{ if used as a forward type }
((tobjectdef(def).objecttype=odt_objccategory) or
{ if used as after it has been resolved }
((tobjectdef(def).objecttype=odt_objcclass) and
(oo_is_classhelper in tobjectdef(def).objectoptions)));
end;
function is_objc_class_or_protocol(def: tdef): boolean; function is_objc_class_or_protocol(def: tdef): boolean;
begin begin
result:= result:=
@ -5074,6 +5153,17 @@ implementation
end; end;
function is_objc_protocol_or_category(def: tdef): boolean;
begin
result:=
assigned(def) and
(def.typ=objectdef) and
((tobjectdef(def).objecttype = odt_objcprotocol) or
((tobjectdef(def).objecttype = odt_objcclass) and
(oo_is_classhelper in tobjectdef(def).objectoptions)));
end;
function is_class_or_interface(def: tdef): boolean; function is_class_or_interface(def: tdef): boolean;
begin begin
result:= result:=
@ -5125,6 +5215,7 @@ implementation
objc_superclasstype:=tpointerdef(search_named_unit_globaltype('OBJC','POBJC_SUPER').typedef); objc_superclasstype:=tpointerdef(search_named_unit_globaltype('OBJC','POBJC_SUPER').typedef);
objc_idtype:=tpointerdef(search_named_unit_globaltype('OBJC','ID').typedef); objc_idtype:=tpointerdef(search_named_unit_globaltype('OBJC','ID').typedef);
objc_seltype:=tpointerdef(search_named_unit_globaltype('OBJC','SEL').typedef); objc_seltype:=tpointerdef(search_named_unit_globaltype('OBJC','SEL').typedef);
objc_objecttype:=trecorddef(search_named_unit_globaltype('OBJC','OBJC_OBJECT').typedef);
end; end;

View File

@ -204,6 +204,7 @@ interface
function search_class_member(pd : tobjectdef;const s : string):tsym; function search_class_member(pd : tobjectdef;const s : string):tsym;
function search_assignment_operator(from_def,to_def:Tdef):Tprocdef; function search_assignment_operator(from_def,to_def:Tdef):Tprocdef;
function search_enumerator_operator(type_def:Tdef):Tprocdef; function search_enumerator_operator(type_def:Tdef):Tprocdef;
function search_class_helper(pd : tobjectdef;const s : string; out srsym: tsym; out srsymtable: tsymtable):boolean;
{Looks for macro s (must be given in upper case) in the macrosymbolstack, } {Looks for macro s (must be given in upper case) in the macrosymbolstack, }
{and returns it if found. Returns nil otherwise.} {and returns it if found. Returns nil otherwise.}
function search_macro(const s : string):tsym; function search_macro(const s : string):tsym;
@ -1674,6 +1675,16 @@ implementation
exit; exit;
end; end;
end; end;
{ also search for class helpers }
if (srsymtable.symtabletype=objectsymtable) and
is_objcclass(tdef(srsymtable.defowner)) then
begin
if search_class_helper(tobjectdef(srsymtable.defowner),s,srsym,srsymtable) then
begin
result:=true;
exit;
end;
end;
stackitem:=stackitem^.next; stackitem:=stackitem^.next;
end; end;
srsym:=nil; srsym:=nil;
@ -1810,7 +1821,9 @@ implementation
function searchsym_in_class(classh,contextclassh:tobjectdef;const s : TIDString;out srsym:tsym;out srsymtable:TSymtable):boolean; function searchsym_in_class(classh,contextclassh:tobjectdef;const s : TIDString;out srsym:tsym;out srsymtable:TSymtable):boolean;
var var
hashedid : THashedIDString; hashedid : THashedIDString;
orgclass : tobjectdef;
begin begin
orgclass:=classh;
{ The contextclassh is used for visibility. The classh must be equal to { The contextclassh is used for visibility. The classh must be equal to
or be a parent of contextclassh. E.g. for inherited searches the classh is the or be a parent of contextclassh. E.g. for inherited searches the classh is the
parent. } parent. }
@ -1832,8 +1845,13 @@ implementation
end; end;
classh:=classh.childof; classh:=classh.childof;
end; end;
srsym:=nil; if is_objcclass(orgclass) then
srsymtable:=nil; result:=search_class_helper(orgclass,s,srsym,srsymtable)
else
begin
srsym:=nil;
srsymtable:=nil;
end;
end; end;
@ -1993,8 +2011,6 @@ implementation
function search_named_unit_globaltype(const unitname, typename: TIDString): ttypesym; function search_named_unit_globaltype(const unitname, typename: TIDString): ttypesym;
var var
contextobjdef : tobjectdef;
stackitem : psymtablestackitem;
srsymtable: tsymtable; srsymtable: tsymtable;
sym: tsym; sym: tsym;
begin begin
@ -2012,14 +2028,71 @@ implementation
end; end;
function search_class_helper(pd : tobjectdef;const s : string; out srsym: tsym; out srsymtable: tsymtable):boolean;
var
hashedid : THashedIDString;
stackitem : psymtablestackitem;
i : longint;
begin
hashedid.id:=class_helper_prefix+s;
stackitem:=symtablestack.stack;
while assigned(stackitem) do
begin
srsymtable:=stackitem^.symtable;
srsym:=tsym(srsymtable.FindWithHash(hashedid));
if assigned(srsym) then
begin
if not(srsymtable.symtabletype in [globalsymtable,staticsymtable]) or
not(srsym.owner.symtabletype in [globalsymtable,staticsymtable]) or
(srsym.typ<>procsym) then
internalerror(2009111505);
{ check whether this procsym includes a helper for this particular class }
for i:=0 to tprocsym(srsym).procdeflist.count-1 do
begin
{ does pd inherit from (or is the same as) the class
that this method's category extended?
}
if pd.is_related(tobjectdef(tprocdef(tprocsym(srsym).procdeflist[i]).owner.defowner).childof) then
begin
{ no need to keep looking. There might be other
categories that extend this, a parent or child
class with a method with the same name (either
overriding this one, or overridden by this one),
but that doesn't matter as far as the basic
procsym is concerned.
}
srsym:=tprocdef(tprocsym(srsym).procdeflist[i]).procsym;
srsymtable:=srsym.owner;
{ we need to know if a procedure references symbols
in the static symtable, because then it can't be
inlined from outside this unit }
if assigned(current_procinfo) and
(srsym.owner.symtabletype=staticsymtable) then
include(current_procinfo.flags,pi_uses_static_symtable);
addsymref(srsym);
result:=true;
exit;
end;
end;
end;
stackitem:=stackitem^.next;
end;
srsym:=nil;
srsymtable:=nil;
result:=false;
end;
function search_class_member(pd : tobjectdef;const s : string):tsym; function search_class_member(pd : tobjectdef;const s : string):tsym;
{ searches n in symtable of pd and all anchestors } { searches n in symtable of pd and all anchestors }
var var
hashedid : THashedIDString; hashedid : THashedIDString;
srsym : tsym; srsym : tsym;
orgpd : tobjectdef;
srsymtable : tsymtable;
begin begin
hashedid.id:=s; hashedid.id:=s;
orgpd:=pd;
while assigned(pd) do while assigned(pd) do
begin begin
srsym:=tsym(pd.symtable.FindWithHash(hashedid)); srsym:=tsym(pd.symtable.FindWithHash(hashedid));
@ -2030,9 +2103,15 @@ implementation
end; end;
pd:=pd.childof; pd:=pd.childof;
end; end;
search_class_member:=nil;
{ not found, now look for class helpers }
if is_objcclass(pd) then
search_class_helper(orgpd,s,result,srsymtable)
else
result:=nil;
end; end;
function search_macro(const s : string):tsym; function search_macro(const s : string):tsym;
var var
stackitem : psymtablestackitem; stackitem : psymtablestackitem;

View File

@ -250,6 +250,7 @@ type
_EXPERIMENTAL, _EXPERIMENTAL,
_FINALIZATION, _FINALIZATION,
_NOSTACKFRAME, _NOSTACKFRAME,
_OBJCCATEGORY,
_OBJCPROTOCOL, _OBJCPROTOCOL,
_WEAKEXTERNAL, _WEAKEXTERNAL,
_DISPINTERFACE, _DISPINTERFACE,
@ -510,6 +511,7 @@ const
(str:'EXPERIMENTAL' ;special:false;keyword:m_all;op:NOTOKEN), (str:'EXPERIMENTAL' ;special:false;keyword:m_all;op:NOTOKEN),
(str:'FINALIZATION' ;special:false;keyword:m_initfinal;op:NOTOKEN), (str:'FINALIZATION' ;special:false;keyword:m_initfinal;op:NOTOKEN),
(str:'NOSTACKFRAME' ;special:false;keyword:m_none;op:NOTOKEN), (str:'NOSTACKFRAME' ;special:false;keyword:m_none;op:NOTOKEN),
(str:'OBJCCATEGORY' ;special:false;keyword:m_objectivec1;op:NOTOKEN), { Objective-C category }
(str:'OBJCPROTOCOL' ;special:false;keyword:m_objectivec1;op:NOTOKEN), { Objective-C protocol } (str:'OBJCPROTOCOL' ;special:false;keyword:m_objectivec1;op:NOTOKEN), { Objective-C protocol }
(str:'WEAKEXTERNAL' ;special:false;keyword:m_none;op:NOTOKEN), (str:'WEAKEXTERNAL' ;special:false;keyword:m_none;op:NOTOKEN),
(str:'DISPINTERFACE' ;special:false;keyword:m_class;op:NOTOKEN), (str:'DISPINTERFACE' ;special:false;keyword:m_class;op:NOTOKEN),

View File

@ -1390,7 +1390,8 @@ type
oo_has_enumerator_movenext, oo_has_enumerator_movenext,
oo_has_enumerator_current, oo_has_enumerator_current,
oo_is_external, { the class is externally implemented (objcclass, cppclass) } oo_is_external, { the class is externally implemented (objcclass, cppclass) }
oo_is_anonymous { the class is only formally defined in this module (objcclass x = class; external;) } oo_is_anonymous, { the class is only formally defined in this module (objcclass x = class; external;) }
oo_is_classhelper { objcclasses that represent categories, and Delpi-style class helpers, are marked like this }
); );
tobjectoptions=set of tobjectoption; tobjectoptions=set of tobjectoption;
tsymopt=record tsymopt=record
@ -1418,7 +1419,8 @@ const
(mask:oo_has_enumerator_movenext; str:'HasEnumeratorMoveNext'), (mask:oo_has_enumerator_movenext; str:'HasEnumeratorMoveNext'),
(mask:oo_has_enumerator_current; str:'HasEnumeratorCurrent'), (mask:oo_has_enumerator_current; str:'HasEnumeratorCurrent'),
(mask:oo_is_external; str:'External'), (mask:oo_is_external; str:'External'),
(mask:oo_is_anonymous; str:'Anonymous')); (mask:oo_is_anonymous; str:'Anonymous'),
(mask:oo_is_classhelper; str:'Class Helper/Category'));
var var
symoptions : tobjectoptions; symoptions : tobjectoptions;
i : longint; i : longint;

16
tests/test/tobjc24.pp Normal file
View File

@ -0,0 +1,16 @@
{ %fail }
{ %target=darwin }
{ %cpu=powerpc,powerpc64,i386,x86_64,arm }
{$modeswitch objectivec1}
uses
uobjc24;
var
a: ta;
begin
{ category is in implementation -> should not be visible here }
ta.implementationcategorymethod;
end.

122
tests/test/tobjc25.pp Normal file
View File

@ -0,0 +1,122 @@
{ %target=darwin }
{ %cpu=powerpc,powerpc64,i386,x86_64,arm }
{$mode objfpc}
{$modeswitch objectivec1}
type
tbaseclass = objccategory(NSObject)
function tabaseproc(cp: longint): double; message 'tabaseproc:';
class function taclassproc: longint; message 'taclassproc';
end;
ta = objcclass(NSObject)
a: longint;
procedure taproc; message 'taproc';
function tabaseproc(cp: longint): double; message 'tabaseproc:'; //override; -- override doesn't work, the compiler doesn't treat the category as part of NSObject
class function taclassproc: longint; message 'taclassproc'; //override; -- idem
end;
ca = objccategory(ta)
procedure categorymethod; message 'categorymethod';
function tabaseproc(cp: longint): double; reintroduce;
end;
da = objccategory(ta)
procedure anothercategorymethod; message 'anothercategorymethod';
class function taclassproc: longint; reintroduce;
end;
class function tbaseclass.taclassproc: longint;
begin
writeln('tbaseclass.taclassproc');
result:=654321;
end;
function tbaseclass.tabaseproc(cp: longint): double;
begin
writeln('tbaseclass.tabaseproc');
if (cp<>98765) then
halt(12);
result:=1234.875;
end;
procedure ta.taproc;
begin
a:=0;
categorymethod;
if (a<>1) then
halt(1);
anothercategorymethod;
if (a<>2) then
halt(2);
if taclassproc<>123456 then
halt(5);
end;
function ta.tabaseproc(cp: longint): double;
begin
{ should be replaced/hidden by ca.tabaseproc }
halt(9);
result:=-1.0;
end;
class function ta.taclassproc: longint;
begin
{ should be replaced/hidden by da.taclassproc }
halt(3);
result:=0;
end;
procedure ca.categorymethod;
begin
a:=1;
if tabaseproc(555) <> 1.0 then
halt(16);
end;
function ca.tabaseproc(cp: longint): double;
begin
writeln('start ca.tabaseproc');
if (cp<>555) then
halt(13);
if inherited tabaseproc(98765)<>1234.875 then
halt(11);
writeln('end ca.tabaseproc');
result:=1.0;
end;
procedure da.anothercategorymethod;
begin
a:=2;
if tabaseproc(555)<>1.0 then
halt(15);
end;
class function da.taclassproc: longint;
begin
writeln('start da.taclassproc, calling inherited');
if inherited taclassproc<>654321 then
halt(4);
writeln('end da.taclassproc');
result:=123456;
end;
var
a: ta;
begin
a:=ta(ta.alloc).init;
a.taproc;
a.a:=0;
a.categorymethod;
if (a.a<>1) then
halt(6);
a.anothercategorymethod;
if (a.a<>2) then
halt(7);
if a.taclassproc<>123456 then
halt(8);
if (a.tabaseproc(555)<>1.0) then
halt(14);
a.release;
end.

18
tests/test/tobjc26.pp Normal file
View File

@ -0,0 +1,18 @@
{ %fail }
{ %target=darwin }
{ %cpu=powerpc,powerpc64,i386,x86_64,arm }
{$modeswitch objectivec1}
uses
uobjc26;
var
a: ta;
begin
a:=ta(ta.alloc).init;
// should not be visible
a.implementationcategorymethod;
a.release
end.

16
tests/test/tobjc26a.pp Normal file
View File

@ -0,0 +1,16 @@
{ %target=darwin }
{ %cpu=powerpc,powerpc64,i386,x86_64,arm }
{$modeswitch objectivec1}
uses
uobjc26;
var
a: ta;
begin
a:=ta(ta.alloc).init;
a.taproc;
a.release
end.

26
tests/test/tobjc27a.pp Normal file
View File

@ -0,0 +1,26 @@
{ %target=darwin }
{ %cpu=powerpc,powerpc64,i386,x86_64,arm }
{ %recompile }
{$modeswitch objectivec1}
uses
uobjc27a,uobjc27b;
var
a: ta;
c: tachild;
begin
a:=ta(ta.alloc).init;
if a.da_categorymethod<>2 then
halt(1);
a.release;
c:=tachild(tachild.alloc).init;
if c.da_categorymethod<>2 then
halt(2);
if c.eachild_categorymethod<>3 then
halt(3);
c.release;
end.

17
tests/test/tobjc27b.pp Normal file
View File

@ -0,0 +1,17 @@
{ %target=darwin }
{ %cpu=powerpc,powerpc64,i386,x86_64,arm }
{ %fail }
{$modeswitch objectivec1}
uses
uobjc27a;
var
a: ta;
begin
{ da_category method is declared in uobjc27a, which is used in the
implementation of uobjc27b -> should not be visible here }
a.da_categorymethod;
end.

25
tests/test/tobjc28.pp Normal file
View File

@ -0,0 +1,25 @@
{ %target=darwin }
{ %cpu=powerpc,powerpc64,i386,x86_64,arm }
{ %fail }
{$modeswitch objectivec1}
type
ta = objcclass(NSObject)
end;
ca = objccategory(ta)
procedure categorymethod; message 'categorymethod';
end;
procedure ca.categorymethod;
begin
end;
var
a: NSObject;
begin
a:=ta(ta.alloc).init;
{ should fail because the category is for ta, not for nsobject }
a.categorymethod;
end.

22
tests/test/uobjc24.pp Normal file
View File

@ -0,0 +1,22 @@
{$modeswitch objectivec1}
unit uobjc24;
interface
type
ta = objcclass(NSObject)
end;
implementation
type
ca = objccategory(ta)
procedure implementationcategorymethod;
end;
procedure ca.implementationcategorymethod;
begin
end;
end.

33
tests/test/uobjc26.pp Normal file
View File

@ -0,0 +1,33 @@
{$modeswitch objectivec1}
unit uobjc26;
interface
type
ta = objcclass(NSObject)
l: longint;
procedure taproc; message 'taproc';
end;
implementation
type
ca = objccategory(ta)
procedure implementationcategorymethod; message 'implementationcategorymethod';
end;
procedure ca.implementationcategorymethod;
begin
l:=1;
end;
procedure ta.taproc;
begin
l:=0;
implementationcategorymethod;
if l<>1 then
halt(1);
end;
end.

27
tests/test/uobjc27a.pp Normal file
View File

@ -0,0 +1,27 @@
{$mode objfpc}
{$modeswitch objectivec1}
unit uobjc27a;
interface
type
ta = objcclass(NSObject)
end;
type
ca = objccategory(ta)
function ca_categorymethod: longint; message 'ca_categorymethod';
end;
implementation
uses
uobjc27b;
function ca.ca_categorymethod: longint;
begin
result:=da_categorymethod-1;
end;
end.

35
tests/test/uobjc27b.pp Normal file
View File

@ -0,0 +1,35 @@
{$mode objfpc}
{$modeswitch objectivec1}
unit uobjc27b;
interface
uses uobjc27a;
type
tachild = objcclass(ta)
end;
type
eachild = objccategory(tachild)
function eachild_categorymethod: longint; message 'eachild_categorymethod';
end;
da = objccategory(ta)
function da_categorymethod: longint; message 'da_categorymethod';
end;
implementation
function eachild.eachild_categorymethod: longint;
begin
result:=ca_categorymethod+2;
end;
function da.da_categorymethod: longint;
begin
result:=2;
end;
end.