Commit of a completely restructured helper implementation. Instead of changing objectdefs with odt_classhelper to odt_class, they'll have the odt_helper type assigned to and this will be kept. This also implies that the parent of a helper is its true parent while the extended type is set to a field in tobjectdef (extendeddef).

This change became necessary of the following reasons:
- Records don't support inheritance, thus for "record helpers" some creativity would have been necessary to implement them; with the new implementation this is more easily
- the new approach allows for easy checks regarding virtual methods and their overrides which would have been more complicated in the old variant
- if someone feels the need the types of helpers (object, interface) can be added rather easily
- unnecessary things like VMT generation can be disabled now

details:
- msg*: 
* moved some messages from parser to type
* adjusted a message ("class helper" => "helper")
- symdef.pas:
* renamed "helperparent" to "extendeddef" and changed its type from "tobjectdef" to "tabstractrecorddef", so records can be extended as well (somewhen in the near future)
* removed "finish_class_helper" method as it isn't necessary (luckily I haven't yet adjusted the ObjC variant)
* changed name of "is_objectpascal_classhelper" to "is_objectpascal_helper" to reflect that this function applies to all helper types
* tobjectdef.create: ImplementedInterfaces isn't created for odt_helper anymore
* tobjectdef.alignment: for helpers it's the same as for classes although this shouldn't be used anywhere...
* tobjectdef.vmtmethodoffset: set to 0 for helpers to be sure...
* tobjectdef.needs_inittable: not needed for helpers (no fields allowed)
* is_objectpascal_helper: only needs check for "odt_helper" object type
- symconst.pas:
* changed odt_classhelper to more general odt_helper
* added new type "thelpertype" which is used to check that "(record|class) helper" corresponds with the given extended type (as Delphi XE checks this as well this strict solution can be kept for modes Delphi and ObjFPC)
- symtable.pas:
* extended "searchsym_in_class" with the possibility to disable the search for helper methods (needed for inherited) => this implies changing all occurences of "searchsym_in_class" with a "true" except some special locations
* renamed "search_objectpascal_classhelper" to "search_objectpascal_helper"
* searchsym_in_class: 
** when an extended method is defined with "overload" it can be that a same named method of the extended class might be called (sadly this means that this search was unnecessary...)
** contextclassh is the def of the helper in the case of an inherited call inside the helper's implementation
** when methods inside a helper are searched, it must be searched in the extended type first
- ptype.pas:
* single_type is used to parse the parent of a helper as well, so allow a helper if the stoParseClassParent is given (needs check in pdecobj.pas/parse_class_parents for normal classes)
* read_named_type: currently the only case when something <> ht_none is passed to the modified parse_objdec (see below) is when the combination "class helper" is encountered ("record helper" will be another one)
- pinline.pas: adjustment for extended "searchsym_in_class"
- pexpr.pas:
* adjustments regarding "searchsym_in_class" and "is_objectpascal_helper"
* factor/factor_read_id: moved the check for "TSomeClassType.SomeMethod" outside of the "is_class" check
* factor: 
** in case of an inherited we need to search inside the extended type first (Note: this needs to be extended to find methods in the helper parent if no method is found in the extended type)
** we also need to disable the search for helper methods when searching for an inherited method (Note: it might be better to introduce a enum to decide whether a helper method should search before or after the methods of the extended type or even never)
- pdecsub.pas:
* insert_self_and_vmt_para: in a helper the type of Self is of the extended type
* pd_abstract, pd_final: more nice error message
* pd_override, pd_message, pd_reintroduce: adjusted checks because now "is_class" is no longer true for helpers
* proc_direcdata: allowed "abstract" for helpers (only to produce a more nice error message)
* parse_proc_direc: adjustment because of "is_objectpascal_helper"
- pdecobj.pas:
* adjustments regarding "is_objectpascal_helper"
* adjusted object_dec to take the type of the helper (class, record) as a parameter to be able to check whether the correct extended type was given
* struct_property_dec: properties are allowed in helpers
* parse_object_options: nothing to be parsed for helpers (at least I hope so ^^)
* parse_parent_classes: 
** the parent of a helper is now parsed as a normal parent, the extended type is parsed in an extra procedure
** check for "sealed" no longer needed
** added check that the parsed parent of a helper is indeed a helper
** allow to parse the closing ")" of the helper's parent
* parse_extended_class:
** new procedure that parses the type which is extended
** it checks that the extended type is a class for "class helper" and a record for "record helper"
** it checks that a helper extends the same class or a subclass for class helpers
** it checks that a helper extends the same record for record helpers
* parse_object_members:
** "type", "const", "var" is allowed in helpers
** don't exclude flags regarding virtual methods, they are needed for the checks in mode Delphi (this implies that VMT loading must be disabled for helpers)
* object_dec:
** don't change "odt_helper" to "odt_class", but still include the "oo_is_classhelper" flag
** allow the parsing of object options (there are none)
** parse the extended type for helpers
- pdecl.pas
* adjustment because of extension of object_dec
* types_dec: remove the call to finish_classhelper
- objcdef.pas
* objcaddencodedtype, objcdochecktype: add references to helpers as implicit pointers although that should not be used in any way...
- nld.pas
* tloadnode.pass_typecheck: self is a reference to the extended type
- nflw.pas
* create_for_in_loop: adjustment because of changed procedure and inheritance type
- ncgrtti.pas
* TRTTIWriter.write_rtti_data: disable for helpers for now (I need to check what Delphi does here)
- ncgld.pas
* tcgloadnode.pass_generate_code: virtual methods of helpers are treated as normal methods
- ncgcal.pas
* tcgcallnode.pass_generate_code: virtual methods of helpers are treated as normal methods
- ncal.pas
* tcallnode.pass_typecheck: adjust for extension of tcallcandidates constructor
- htypechk.pas
* tcallcandidates declaration: extend some methods to (dis)allow the search for helper methods (needed for inherited)
* tcallcandidates.collect_overloads_in_struct: 
** search first in helpers for methods and stop if none carries the "overload" flag
** move the addition of the procsyms to an extra nested procedure because it's used for helper methods and normal struct methods

git-svn-id: branches/svenbarth/classhelpers@16947 -
This commit is contained in:
svenbarth 2011-02-20 11:41:55 +00:00
parent d12b198c7f
commit 963a4d7b23
20 changed files with 702 additions and 566 deletions

View File

@ -67,12 +67,12 @@ interface
FParaNode : tnode; FParaNode : tnode;
FParaLength : smallint; FParaLength : smallint;
FAllowVariant : boolean; FAllowVariant : boolean;
procedure collect_overloads_in_struct(structdef:tabstractrecorddef;ProcdefOverloadList:TFPObjectList); procedure collect_overloads_in_struct(structdef:tabstractrecorddef;ProcdefOverloadList:TFPObjectList;searchhelpers:boolean);
procedure collect_overloads_in_units(ProcdefOverloadList:TFPObjectList; objcidcall,explicitunit: boolean); procedure collect_overloads_in_units(ProcdefOverloadList:TFPObjectList; objcidcall,explicitunit: boolean);
procedure create_candidate_list(ignorevisibility,allowdefaultparas,objcidcall,explicitunit:boolean); procedure create_candidate_list(ignorevisibility,allowdefaultparas,objcidcall,explicitunit,searchhelpers:boolean);
function proc_add(st:tsymtable;pd:tprocdef;objcidcall: boolean):pcandidate; function proc_add(st:tsymtable;pd:tprocdef;objcidcall: boolean):pcandidate;
public public
constructor create(sym:tprocsym;st:TSymtable;ppn:tnode;ignorevisibility,allowdefaultparas,objcidcall,explicitunit:boolean); constructor create(sym:tprocsym;st:TSymtable;ppn:tnode;ignorevisibility,allowdefaultparas,objcidcall,explicitunit,searchhelpers:boolean);
constructor create_operator(op:ttoken;ppn:tnode); constructor create_operator(op:ttoken;ppn:tnode);
destructor destroy;override; destructor destroy;override;
procedure list(all:boolean); procedure list(all:boolean);
@ -1758,7 +1758,7 @@ implementation
TCallCandidates TCallCandidates
****************************************************************************} ****************************************************************************}
constructor tcallcandidates.create(sym:tprocsym;st:TSymtable;ppn:tnode;ignorevisibility,allowdefaultparas,objcidcall,explicitunit:boolean); constructor tcallcandidates.create(sym:tprocsym;st:TSymtable;ppn:tnode;ignorevisibility,allowdefaultparas,objcidcall,explicitunit,searchhelpers:boolean);
begin begin
if not assigned(sym) then if not assigned(sym) then
internalerror(200411015); internalerror(200411015);
@ -1766,7 +1766,7 @@ implementation
FProcsym:=sym; FProcsym:=sym;
FProcsymtable:=st; FProcsymtable:=st;
FParanode:=ppn; FParanode:=ppn;
create_candidate_list(ignorevisibility,allowdefaultparas,objcidcall,explicitunit); create_candidate_list(ignorevisibility,allowdefaultparas,objcidcall,explicitunit,searchhelpers);
end; end;
@ -1776,7 +1776,7 @@ implementation
FProcsym:=nil; FProcsym:=nil;
FProcsymtable:=nil; FProcsymtable:=nil;
FParanode:=ppn; FParanode:=ppn;
create_candidate_list(false,false,false,false); create_candidate_list(false,false,false,false,false);
end; end;
@ -1795,19 +1795,63 @@ implementation
end; end;
procedure tcallcandidates.collect_overloads_in_struct(structdef:tabstractrecorddef;ProcdefOverloadList:TFPObjectList); procedure tcallcandidates.collect_overloads_in_struct(structdef:tabstractrecorddef;ProcdefOverloadList:TFPObjectList;searchhelpers:boolean);
function processprocsym(srsym:tprocsym):boolean;
var
j : integer;
pd : tprocdef;
begin
{ Store first procsym found }
if not assigned(FProcsym) then
FProcsym:=srsym;
{ add all definitions }
result:=false;
for j:=0 to srsym.ProcdefList.Count-1 do
begin
pd:=tprocdef(srsym.ProcdefList[j]);
if po_overload in pd.procoptions then
result:=true;
ProcdefOverloadList.Add(srsym.ProcdefList[j]);
end;
end;
var var
j : integer;
pd : tprocdef;
srsym : tsym; srsym : tsym;
hashedid : THashedIDString; hashedid : THashedIDString;
hasoverload : boolean; hasoverload : boolean;
helperdef : tobjectdef;
begin begin
if FOperator=NOTOKEN then if FOperator=NOTOKEN then
hashedid.id:=FProcsym.name hashedid.id:=FProcsym.name
else else
hashedid.id:=overloaded_names[FOperator]; hashedid.id:=overloaded_names[FOperator];
hasoverload:=false; hasoverload:=false;
{ first search for potential symbols in the class helpers (this is
disabled in an inherited call if the method is available in the
extended class) }
if is_class(structdef) then
if search_last_objectpascal_helper(tobjectdef(structdef), helperdef) and searchhelpers then
begin
srsym:=nil;
while assigned(helperdef) do
begin
srsym:=tsym(helperdef.symtable.FindWithHash(hashedid));
if assigned(srsym) and
{ Delphi allows hiding a property by a procedure with the same name }
(srsym.typ=procsym) then
begin
hasoverload := processprocsym(tprocsym(srsym));
{ when there is no explicit overload we stop searching }
if not hasoverload then
break;
end;
helperdef:=helperdef.childof;
end;
if not hasoverload and assigned(srsym) then
exit;
end;
{ now search in the class and its parents or the record }
while assigned(structdef) do while assigned(structdef) do
begin begin
srsym:=tprocsym(structdef.symtable.FindWithHash(hashedid)); srsym:=tprocsym(structdef.symtable.FindWithHash(hashedid));
@ -1815,18 +1859,7 @@ implementation
{ Delphi allows hiding a property by a procedure with the same name } { Delphi allows hiding a property by a procedure with the same name }
(srsym.typ=procsym) then (srsym.typ=procsym) then
begin begin
{ Store first procsym found } hasoverload:=processprocsym(tprocsym(srsym));
if not assigned(FProcsym) then
FProcsym:=tprocsym(srsym);
{ add all definitions }
hasoverload:=false;
for j:=0 to tprocsym(srsym).ProcdefList.Count-1 do
begin
pd:=tprocdef(tprocsym(srsym).ProcdefList[j]);
if po_overload in pd.procoptions then
hasoverload:=true;
ProcdefOverloadList.Add(tprocsym(srsym).ProcdefList[j]);
end;
{ when there is no explicit overload we stop searching } { when there is no explicit overload we stop searching }
if not hasoverload then if not hasoverload then
break; break;
@ -1911,7 +1944,7 @@ implementation
end; end;
procedure tcallcandidates.create_candidate_list(ignorevisibility,allowdefaultparas,objcidcall,explicitunit:boolean); procedure tcallcandidates.create_candidate_list(ignorevisibility,allowdefaultparas,objcidcall,explicitunit,searchhelpers:boolean);
var var
j : integer; j : integer;
pd : tprocdef; pd : tprocdef;
@ -1929,7 +1962,7 @@ implementation
if not objcidcall and if not objcidcall and
(FOperator=NOTOKEN) and (FOperator=NOTOKEN) and
(FProcsym.owner.symtabletype in [objectsymtable,recordsymtable]) then (FProcsym.owner.symtabletype in [objectsymtable,recordsymtable]) then
collect_overloads_in_struct(tabstractrecorddef(FProcsym.owner.defowner),ProcdefOverloadList) collect_overloads_in_struct(tabstractrecorddef(FProcsym.owner.defowner),ProcdefOverloadList,searchhelpers)
else else
if (FOperator<>NOTOKEN) then if (FOperator<>NOTOKEN) then
begin begin
@ -1939,7 +1972,7 @@ implementation
while assigned(pt) do while assigned(pt) do
begin begin
if (pt.resultdef.typ=recorddef) then if (pt.resultdef.typ=recorddef) then
collect_overloads_in_struct(tabstractrecorddef(pt.resultdef),ProcdefOverloadList); collect_overloads_in_struct(tabstractrecorddef(pt.resultdef),ProcdefOverloadList,searchhelpers);
pt:=tcallparanode(pt.right); pt:=tcallparanode(pt.right);
end; end;
collect_overloads_in_units(ProcdefOverloadList,objcidcall,explicitunit); collect_overloads_in_units(ProcdefOverloadList,objcidcall,explicitunit);

View File

@ -368,7 +368,7 @@ scanner_w_illegal_warn_identifier=02087_W_Illegal identifier "$1" for $WARN dire
# #
# Parser # Parser
# #
# 03307 is the last used one # 03305 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
@ -917,9 +917,9 @@ parser_e_no_access_specifier_in_interfaces=03172_E_Access specifiers can't be us
% 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, Objective-C protocols and categories because all methods % \var{published} can't be used in interfaces, Objective-C protocols and categories because all methods
% of an interface/protocol/category must be public. % of an interface/protocol/category must be public.
parser_e_no_vars_in_interfaces=03173_E_An interface or class helper or Objective-C protocol or category cannot contain fields parser_e_no_vars_in_interfaces=03173_E_An interface, helper or Objective-C protocol or category cannot contain fields
% Declarations of fields are not allowed in interfaces, class helpers and Objective-C protocols and categories. % Declarations of fields are not allowed in interfaces, helpers and Objective-C protocols and categories.
% An interface/class helper/protocol/category can contain only methods and properties with method read/write specifiers. % An interface/helper/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.
@ -1368,18 +1368,13 @@ parser_e_at_least_one_argument_must_be_of_type=03303_E_Either the result or at l
parser_e_cant_use_type_parameters_here=03304_E_Type parameters may require initialization/finalization - can't be used in variant records parser_e_cant_use_type_parameters_here=03304_E_Type parameters may require initialization/finalization - can't be used in variant records
% Type parameters may be specialized with types which (e.g. \var{ansistring}) need initialization/finalization % Type parameters may be specialized with types which (e.g. \var{ansistring}) need initialization/finalization
% code which is implicitly generated by the compiler. % code which is implicitly generated by the compiler.
parser_e_classhelper_id_expected=03305_E_Class helper identifier expected parser_e_not_allowed_in_classhelper=03305_E_"$1" is not allowed in class helpers
% A class helper can only inherit from another class helper.
parser_e_classhelper_must_extend_subclass=03306_E_Derived class helper must extend a subclass of the class extended by the parent class helper
% When a class helper inherits from another class helper the extended class must
% extend either the same class as the parent class helper or a subclass of it
parser_e_not_allowed_in_classhelper=03307_E_"$1" is not allowed in class helpers
% Some directives and specifiers like "virtual", "dynamic", "published" aren't % Some directives and specifiers like "virtual", "dynamic", "published" aren't
% allowed inside class helpers in mode ObjFPC (they are ignored in mode Delphi). % allowed inside class helpers in mode ObjFPC (they are ignored in mode Delphi).
% \end{description} % \end{description}
# Type Checking # Type Checking
# #
# 04095 is the last used one # 04100 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
@ -1727,6 +1722,16 @@ type_e_type_parameters_are_not_allowed_here=04097_E_Type parameters are not allo
% Type parameters are only allowed for methods of generic classes, records or objects % Type parameters are only allowed for methods of generic classes, records or objects
type_e_generic_declaration_does_not_match=04098_E_Generic declaration of "$1" differs from previous declaration type_e_generic_declaration_does_not_match=04098_E_Generic declaration of "$1" differs from previous declaration
% Generic declaration does not match the previous declaration % Generic declaration does not match the previous declaration
type_e_helper_type_expected=04099_E_Helper type expected
% The compiler expected a \var{class helper} type.
type_e_record_type_expected=04100_E_Record type expected
% The compiler expected a \var{record} type.
type_e_class_helper_must_extend_subclass=04101_E_Derived class helper must extend a subclass of "$1" or the class itself
% If a class helper inherits from another class helper the extended class must
% extend either the same class as the parent class helper or a subclass of it
type_e_record_helper_must_extend_same_record=04102_E_Derived record helper must extend "$1"
% If a record helper inherits from another record helper it must extend the same
% record that the parent record helper extended.
% %
% \end{description} % \end{description}
# #

View File

@ -393,9 +393,7 @@ const
parser_e_no_constructor_in_records=03302; parser_e_no_constructor_in_records=03302;
parser_e_at_least_one_argument_must_be_of_type=03303; parser_e_at_least_one_argument_must_be_of_type=03303;
parser_e_cant_use_type_parameters_here=03304; parser_e_cant_use_type_parameters_here=03304;
parser_e_classhelper_id_expected=03305; parser_e_not_allowed_in_classhelper=03305;
parser_e_classhelper_must_extend_subclass=03306;
parser_e_not_allowed_in_classhelper=03307;
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;
@ -485,6 +483,10 @@ const
type_e_generics_cannot_reference_itself=04096; type_e_generics_cannot_reference_itself=04096;
type_e_type_parameters_are_not_allowed_here=04097; type_e_type_parameters_are_not_allowed_here=04097;
type_e_generic_declaration_does_not_match=04098; type_e_generic_declaration_does_not_match=04098;
type_e_helper_type_expected=04099;
type_e_record_type_expected=04100;
type_e_class_helper_must_extend_subclass=04101;
type_e_record_helper_must_extend_same_record=04102;
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;
@ -885,9 +887,9 @@ const
option_info=11024; option_info=11024;
option_help_pages=11025; option_help_pages=11025;
MsgTxtSize = 58938; MsgTxtSize = 58973;
MsgIdxMax : array[1..20] of longint=( MsgIdxMax : array[1..20] of longint=(
24,88,308,99,84,54,111,22,202,63, 24,88,306,103,84,54,111,22,202,63,
49,20,1,1,1,1,1,1,1,1 49,20,1,1,1,1,1,1,1,1
); );

File diff suppressed because it is too large Load Diff

View File

@ -2693,7 +2693,7 @@ implementation
{ ignore possible private for properties or in delphi mode for anon. inherited (FK) } { ignore possible private for properties or in delphi mode for anon. inherited (FK) }
ignorevisibility:=(nf_isproperty in flags) or ignorevisibility:=(nf_isproperty in flags) or
((m_delphi in current_settings.modeswitches) and (cnf_anon_inherited in callnodeflags)); ((m_delphi in current_settings.modeswitches) and (cnf_anon_inherited in callnodeflags));
candidates:=tcallcandidates.create(symtableprocentry,symtableproc,left,ignorevisibility,not(nf_isproperty in flags),cnf_objc_id_call in callnodeflags,cnf_unit_specified in callnodeflags); candidates:=tcallcandidates.create(symtableprocentry,symtableproc,left,ignorevisibility,not(nf_isproperty in flags),cnf_objc_id_call in callnodeflags,cnf_unit_specified in callnodeflags,callnodeflags*[cnf_anon_inherited,cnf_inherited]=[]);
{ no procedures found? then there is something wrong { no procedures found? then there is something wrong
with the parameter size or the procedures are with the parameter size or the procedures are

View File

@ -708,6 +708,7 @@ implementation
a pointer. We can directly call the correct procdef (PFV) } a pointer. We can directly call the correct procdef (PFV) }
if (name_to_call='') and if (name_to_call='') and
(po_virtualmethod in procdefinition.procoptions) and (po_virtualmethod in procdefinition.procoptions) and
not is_objectpascal_helper(tprocdef(procdefinition).struct) and
assigned(methodpointer) and assigned(methodpointer) and
(methodpointer.nodetype<>typen) and (methodpointer.nodetype<>typen) and
not wpoinfomanager.can_be_devirtualized(methodpointer.resultdef,procdefinition,name_to_call) then not wpoinfomanager.can_be_devirtualized(methodpointer.resultdef,procdefinition,name_to_call) then

View File

@ -496,7 +496,8 @@ implementation
{ virtual method ? } { virtual method ? }
if (po_virtualmethod in procdef.procoptions) and if (po_virtualmethod in procdef.procoptions) and
not(nf_inherited in flags) then not(nf_inherited in flags) and
not is_objectpascal_helper(procdef.struct) then
begin begin
if (not assigned(current_procinfo) or if (not assigned(current_procinfo) or
wpoinfomanager.symbol_live(current_procinfo.procdef.mangledname)) then wpoinfomanager.symbol_live(current_procinfo.procdef.mangledname)) then

View File

@ -920,7 +920,9 @@ implementation
recorddef_rtti(trecorddef(def)); recorddef_rtti(trecorddef(def));
end; end;
objectdef : objectdef :
objectdef_rtti(tobjectdef(def)); // TODO : check whether Delphi generates RTTI for helpers
if not is_objectpascal_helper(def) then
objectdef_rtti(tobjectdef(def));
else else
unknown_rtti(tstoreddef(def)); unknown_rtti(tstoreddef(def));
end; end;

View File

@ -866,10 +866,10 @@ implementation
{ first search using the class helper hierarchy if it's a { first search using the class helper hierarchy if it's a
class } class }
if (expr.resultdef.typ=objectdef) and if (expr.resultdef.typ=objectdef) and
search_last_objectpascal_classhelper(tobjectdef(expr.resultdef),classhelper) then search_last_objectpascal_helper(tobjectdef(expr.resultdef),classhelper) then
repeat repeat
pd:=classhelper.search_enumerator_get; pd:=classhelper.search_enumerator_get;
classhelper:=classhelper.helperparent; classhelper:=classhelper.childof;
until (pd<>nil) or (classhelper=nil); until (pd<>nil) or (classhelper=nil);
{ we didn't found a class helper, so search in the { we didn't found a class helper, so search in the
class/record/object itself } class/record/object itself }

View File

@ -302,6 +302,8 @@ implementation
if vo_is_self in tabstractvarsym(symtableentry).varoptions then if vo_is_self in tabstractvarsym(symtableentry).varoptions then
begin begin
resultdef:=tprocdef(symtableentry.owner.defowner).struct; resultdef:=tprocdef(symtableentry.owner.defowner).struct;
if is_objectpascal_helper(resultdef) then
resultdef:=tobjectdef(resultdef).extendeddef;
if (po_classmethod in tprocdef(symtableentry.owner.defowner).procoptions) or if (po_classmethod in tprocdef(symtableentry.owner.defowner).procoptions) or
(po_staticmethod in tprocdef(symtableentry.owner.defowner).procoptions) then (po_staticmethod in tprocdef(symtableentry.owner.defowner).procoptions) then
resultdef:=tclassrefdef.create(resultdef) resultdef:=tclassrefdef.create(resultdef)

View File

@ -374,13 +374,14 @@ implementation
encodedstr:=encodedstr+'^?'; encodedstr:=encodedstr+'^?';
objectdef : objectdef :
case tobjectdef(def).objecttype of case tobjectdef(def).objecttype of
odt_helper,
odt_class, odt_class,
odt_object, odt_object,
odt_cppclass: odt_cppclass:
begin begin
newstate:=recordinfostate; newstate:=recordinfostate;
{ implicit pointer for classes } { implicit pointer for classes }
if (tobjectdef(def).objecttype=odt_class) then if (tobjectdef(def).objecttype in [odt_class,odt_helper]) then
begin begin
encodedstr:=encodedstr+'^'; encodedstr:=encodedstr+'^';
{ make all classes opaque, so even if they contain a { make all classes opaque, so even if they contain a
@ -593,13 +594,14 @@ implementation
; ;
objectdef : objectdef :
case tobjectdef(def).objecttype of case tobjectdef(def).objecttype of
odt_helper,
odt_class, odt_class,
odt_object, odt_object,
odt_cppclass: odt_cppclass:
begin begin
newstate:=recordinfostate; newstate:=recordinfostate;
{ implicit pointer for classes } { implicit pointer for classes }
if (tobjectdef(def).objecttype=odt_class) then if (tobjectdef(def).objecttype in [odt_class,odt_helper]) then
begin begin
{ make all classes opaque, so even if they contain a { make all classes opaque, so even if they contain a
reference-counted field there is no problem. Since a reference-counted field there is no problem. Since a

View File

@ -500,7 +500,7 @@ implementation
end; end;
consume(token); consume(token);
{ we can ignore the result, the definition is modified } { we can ignore the result, the definition is modified }
object_dec(objecttype,orgtypename,nil,nil,tobjectdef(ttypesym(sym).typedef)); object_dec(objecttype,orgtypename,nil,nil,tobjectdef(ttypesym(sym).typedef),ht_none);
newtype:=ttypesym(sym); newtype:=ttypesym(sym);
hdef:=newtype.typedef; hdef:=newtype.typedef;
end end
@ -630,9 +630,6 @@ implementation
if is_cppclass(hdef) then if is_cppclass(hdef) then
tobjectdef(hdef).finish_cpp_data; tobjectdef(hdef).finish_cpp_data;
if is_objectpascal_classhelper(hdef) then
tobjectdef(hdef).finish_classhelper;
end; end;
recorddef : recorddef :
begin begin

View File

@ -30,7 +30,7 @@ interface
globtype,symconst,symtype,symdef; globtype,symconst,symtype,symdef;
{ parses a object declaration } { parses a object declaration }
function object_dec(objecttype:tobjecttyp;const n:tidstring;genericdef:tstoreddef;genericlist:TFPObjectList;fd : tobjectdef) : tobjectdef; function object_dec(objecttype:tobjecttyp;const n:tidstring;genericdef:tstoreddef;genericlist:TFPObjectList;fd : tobjectdef;helpertype:thelpertype) : tobjectdef;
function class_constructor_head:tprocdef; function class_constructor_head:tprocdef;
function class_destructor_head:tprocdef; function class_destructor_head:tprocdef;
@ -118,8 +118,8 @@ implementation
var var
p : tpropertysym; p : tpropertysym;
begin begin
{ check for a class or record } { check for a class, record or helper }
if not((is_class_or_interface_or_dispinterface(current_structdef) or is_record(current_structdef)) or if not((is_class_or_interface_or_dispinterface(current_structdef) or is_record(current_structdef) or is_objectpascal_helper(current_structdef)) or
(not(m_tp7 in current_settings.modeswitches) and (is_object(current_structdef)))) then (not(m_tp7 in current_settings.modeswitches) and (is_object(current_structdef)))) then
Message(parser_e_syntax_error); Message(parser_e_syntax_error);
consume(_PROPERTY); consume(_PROPERTY);
@ -422,6 +422,7 @@ implementation
get_cpp_class_external_status(current_objectdef); get_cpp_class_external_status(current_objectdef);
odt_objcclass,odt_objcprotocol,odt_objccategory: odt_objcclass,odt_objcprotocol,odt_objccategory:
get_objc_class_or_protocol_external_status(current_objectdef); get_objc_class_or_protocol_external_status(current_objectdef);
odt_helper: ; // nothing
end; end;
end; end;
@ -436,31 +437,11 @@ implementation
intfchildof:=nil; intfchildof:=nil;
hasparentdefined:=false; hasparentdefined:=false;
{ the "parent" of a class helper is not really treated as its parent;
it's only used to extend the searched scope }
if is_objectpascal_classhelper(current_structdef) then
begin
if try_to_consume(_LKLAMMER) then
begin
{ TODO : check what these flags mean }
single_type(hdef,[stoAllowTypeDef, stoParseClassParent]);
if not is_objectpascal_classhelper(hdef) then
begin
Message(parser_e_classhelper_id_expected);
hdef:=nil;
end;
current_objectdef.helperparent:=tobjectdef(hdef);
consume(_RKLAMMER);
end;
consume(_FOR);
end;
{ reads the parent class } { reads the parent class }
if (token=_LKLAMMER) or if (token=_LKLAMMER) or
is_classhelper(current_structdef) then is_objccategory(current_structdef) then
begin begin
if not is_objectpascal_classhelper(current_structdef) then consume(_LKLAMMER);
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,[stoAllowSpecialization, stoParseClassParent]); single_type(hdef,[stoAllowSpecialization, stoParseClassParent]);
if (not assigned(hdef)) or if (not assigned(hdef)) or
@ -470,10 +451,7 @@ implementation
Message1(type_e_class_type_expected,hdef.typename) Message1(type_e_class_type_expected,hdef.typename)
else if is_objccategory(current_structdef) then else if is_objccategory(current_structdef) then
{ a category must specify the class to extend } { a category must specify the class to extend }
Message(type_e_objcclass_type_expected) Message(type_e_objcclass_type_expected);
else if is_objectpascal_classhelper(current_objectdef) then
{ a class helper must specify the class to extend }
Message(type_e_class_type_expected);
end end
else else
begin begin
@ -496,8 +474,7 @@ implementation
Message(parser_e_mix_of_classes_and_objects); Message(parser_e_mix_of_classes_and_objects);
end end
else else
if (oo_is_sealed in childof.objectoptions) and if oo_is_sealed in childof.objectoptions then
not is_objectpascal_classhelper(current_structdef) then
Message1(parser_e_sealed_descendant,childof.typename); Message1(parser_e_sealed_descendant,childof.typename);
odt_interfacecorba, odt_interfacecorba,
odt_interfacecom: odt_interfacecom:
@ -545,6 +522,12 @@ implementation
Message1(parser_e_sealed_descendant,childof.typename); Message1(parser_e_sealed_descendant,childof.typename);
odt_dispinterface: odt_dispinterface:
Message(parser_e_dispinterface_cant_have_parent); Message(parser_e_dispinterface_cant_have_parent);
odt_helper:
if not is_objectpascal_helper(childof) then
begin
Message(type_e_helper_type_expected);
childof:=nil;
end;
end; end;
end; end;
hasparentdefined:=true; hasparentdefined:=true;
@ -584,8 +567,7 @@ implementation
{ remove forward flag, is resolved } { remove forward flag, is resolved }
exclude(current_structdef.objectoptions,oo_is_forward); exclude(current_structdef.objectoptions,oo_is_forward);
if hasparentdefined and if hasparentdefined then
not is_objectpascal_classhelper(current_structdef) then
begin begin
if current_objectdef.objecttype in [odt_class,odt_objcclass,odt_objcprotocol] then if current_objectdef.objecttype in [odt_class,odt_objcclass,odt_objcprotocol] then
begin begin
@ -600,6 +582,62 @@ implementation
end; end;
end; end;
procedure parse_extended_class(helpertype:thelpertype);
var
hdef: tdef;
begin
if not is_objectpascal_helper(current_structdef) then
Internalerror(2011021103);
if helpertype=ht_none then
Internalerror(2011021001);
consume(_FOR);
single_type(hdef,[stoAllowTypeDef,stoParseClassParent]);
if (not assigned(hdef)) or
not (hdef.typ in [objectdef,recorddef]) then
begin
if helpertype=ht_class then
Message1(type_e_class_type_expected,hdef.typename)
else
if helpertype=ht_record then
Message1(type_e_record_type_expected,hdef.typename);
end
else
begin
case helpertype of
ht_class:
begin
if not is_class(hdef) then
Message1(type_e_class_type_expected,hdef.typename);
{ a class helper must extend the same class or a subclass
of the class extended by the parent class helper }
if assigned(current_objectdef.childof) then
begin
if not is_class(current_objectdef.childof.extendeddef) then
Internalerror(2011021101);
if not hdef.is_related(current_objectdef.childof.extendeddef) then
Message1(type_e_class_helper_must_extend_subclass,current_objectdef.childof.extendeddef.typename);
end;
end;
ht_record:
begin
if not is_record(hdef) then
Message1(type_e_record_type_expected,hdef.typename);
{ a record helper must extend the same record as the
parent helper }
if assigned(current_objectdef.childof) then
begin
if not is_record(current_objectdef.childof.extendeddef) then
Internalerror(2011021102);
if hdef<>current_objectdef.childof.extendeddef then
Message1(type_e_record_helper_must_extend_same_record,current_objectdef.childof.extendeddef.typename);
end;
end;
end;
current_objectdef.extendeddef:=tabstractrecorddef(hdef);
end;
end;
procedure parse_guid; procedure parse_guid;
begin begin
@ -675,14 +713,14 @@ implementation
case token of case token of
_TYPE : _TYPE :
begin begin
if not(current_objectdef.objecttype in [odt_class,odt_object]) then if not(current_objectdef.objecttype in [odt_class,odt_object,odt_helper]) then
Message(parser_e_type_var_const_only_in_records_and_classes); Message(parser_e_type_var_const_only_in_records_and_classes);
consume(_TYPE); consume(_TYPE);
object_member_blocktype:=bt_type; object_member_blocktype:=bt_type;
end; end;
_VAR : _VAR :
begin begin
if not(current_objectdef.objecttype in [odt_class,odt_object]) then if not(current_objectdef.objecttype in [odt_class,odt_object,odt_helper]) then
Message(parser_e_type_var_const_only_in_records_and_classes); Message(parser_e_type_var_const_only_in_records_and_classes);
consume(_VAR); consume(_VAR);
fields_allowed:=true; fields_allowed:=true;
@ -692,7 +730,7 @@ implementation
end; end;
_CONST: _CONST:
begin begin
if not(current_objectdef.objecttype in [odt_class,odt_object]) then if not(current_objectdef.objecttype in [odt_class,odt_object,odt_helper]) then
Message(parser_e_type_var_const_only_in_records_and_classes); Message(parser_e_type_var_const_only_in_records_and_classes);
consume(_CONST); consume(_CONST);
object_member_blocktype:=bt_const; object_member_blocktype:=bt_const;
@ -801,7 +839,7 @@ implementation
begin begin
if is_interface(current_structdef) or if is_interface(current_structdef) or
is_objc_protocol_or_category(current_structdef) or is_objc_protocol_or_category(current_structdef) or
is_objectpascal_classhelper(current_structdef) then is_objectpascal_helper(current_structdef) then
Message(parser_e_no_vars_in_interfaces); Message(parser_e_no_vars_in_interfaces);
if (current_structdef.symtable.currentvisibility=vis_published) and if (current_structdef.symtable.currentvisibility=vis_published) and
@ -877,13 +915,6 @@ implementation
if (m_mac in current_settings.modeswitches) then if (m_mac in current_settings.modeswitches) then
include(pd.procoptions,po_virtualmethod); include(pd.procoptions,po_virtualmethod);
{ for class helpers virtual, final, override make no sense,
so they are rejected in mode ObjFPC (in pdecsub) and
ignored in mode Delphi (here)
}
if is_objectpascal_classhelper(current_structdef) then
pd.procoptions:=pd.procoptions-[po_virtualmethod,po_finalmethod,po_overridingmethod];
handle_calling_convention(pd); handle_calling_convention(pd);
{ add definition to procsym } { add definition to procsym }
@ -965,7 +996,7 @@ implementation
Message(parser_e_no_con_des_in_interfaces); Message(parser_e_no_con_des_in_interfaces);
{ (class) destructors are not allowed in class helpers } { (class) destructors are not allowed in class helpers }
if is_objectpascal_classhelper(current_structdef) then if is_objectpascal_helper(current_structdef) then
Message(parser_e_no_destructor_in_records); Message(parser_e_no_destructor_in_records);
if not is_classdef and (current_structdef.symtable.currentvisibility<>vis_public) then if not is_classdef and (current_structdef.symtable.currentvisibility<>vis_public) then
@ -1014,7 +1045,7 @@ implementation
end; end;
function object_dec(objecttype:tobjecttyp;const n:tidstring;genericdef:tstoreddef;genericlist:TFPObjectList;fd : tobjectdef) : tobjectdef; function object_dec(objecttype:tobjecttyp;const n:tidstring;genericdef:tstoreddef;genericlist:TFPObjectList;fd : tobjectdef;helpertype:thelpertype) : tobjectdef;
var var
old_current_structdef: tabstractrecorddef; old_current_structdef: tabstractrecorddef;
old_current_genericdef, old_current_genericdef,
@ -1122,16 +1153,12 @@ implementation
include(current_structdef.objectoptions,oo_is_classhelper); include(current_structdef.objectoptions,oo_is_classhelper);
end; end;
{ change classhelpers into Object Pascal style class helpers } { include the class helper flag for Object Pascal helpers }
if (objecttype=odt_classhelper) then if (objecttype=odt_helper) then
begin include(current_objectdef.objectoptions,oo_is_classhelper);
current_objectdef.objecttype:=odt_class;
include(current_objectdef.objectoptions,oo_is_classhelper);
end;
{ parse list of options (abstract / sealed) } { parse list of options (abstract / sealed) }
if not(objecttype in [odt_objcclass,odt_objcprotocol,odt_objccategory]) and if not(objecttype in [odt_objcclass,odt_objcprotocol,odt_objccategory]) then
not is_objectpascal_classhelper(current_objectdef) then
parse_object_options; parse_object_options;
symtablestack.push(current_structdef.symtable); symtablestack.push(current_structdef.symtable);
@ -1141,6 +1168,10 @@ implementation
{ parse list of parent classes } { parse list of parent classes }
parse_parent_classes; parse_parent_classes;
{ parse extended type for helpers }
if is_objectpascal_helper(current_structdef) then
parse_extended_class(helpertype);
{ parse optional GUID for interfaces } { parse optional GUID for interfaces }
parse_guid; parse_guid;

View File

@ -245,6 +245,7 @@ implementation
storepos : tfileposinfo; storepos : tfileposinfo;
vs : tparavarsym; vs : tparavarsym;
hdef : tdef; hdef : tdef;
selfdef : tabstractrecorddef;
vsp : tvarspez; vsp : tvarspez;
aliasvs : tabsolutevarsym; aliasvs : tabsolutevarsym;
sl : tpropaccesslist; sl : tpropaccesslist;
@ -302,18 +303,24 @@ implementation
pd.parast.insert(vs); pd.parast.insert(vs);
end; end;
{ for helpers the type of Self is equivalent to the extended
type or equal to an instance of it }
if is_objectpascal_helper(tprocdef(pd).struct) then
selfdef:=tobjectdef(tprocdef(pd).struct).extendeddef
else
selfdef:=tprocdef(pd).struct;
{ Generate self variable, for classes we need { Generate self variable, for classes we need
to use the generic voidpointer to be compatible with to use the generic voidpointer to be compatible with
methodpointers } methodpointers }
vsp:=vs_value; vsp:=vs_value;
if (po_staticmethod in pd.procoptions) or if (po_staticmethod in pd.procoptions) or
(po_classmethod in pd.procoptions) then (po_classmethod in pd.procoptions) then
hdef:=tclassrefdef.create(tprocdef(pd).struct) hdef:=tclassrefdef.create(selfdef)
else else
begin begin
if is_object(tprocdef(pd).struct) or is_record(tprocdef(pd).struct) then if is_object(selfdef) or is_record(selfdef) then
vsp:=vs_var; vsp:=vs_var;
hdef:=tprocdef(pd).struct; hdef:=selfdef;
end; end;
vs:=tparavarsym.create('$self',paranr_self,vsp,hdef,[vo_is_self,vo_is_hidden_para]); vs:=tparavarsym.create('$self',paranr_self,vsp,hdef,[vo_is_self,vo_is_hidden_para]);
pd.parast.insert(vs); pd.parast.insert(vs);
@ -1621,6 +1628,9 @@ procedure pd_abstract(pd:tabstractprocdef);
begin begin
if pd.typ<>procdef then if pd.typ<>procdef then
internalerror(200304269); internalerror(200304269);
if is_objectpascal_helper(tprocdef(pd).struct) and
(m_objfpc in current_settings.modeswitches) then
Message1(parser_e_not_allowed_in_classhelper, arraytokeninfo[_ABSTRACT].str);
if assigned(tprocdef(pd).struct) and if assigned(tprocdef(pd).struct) and
(oo_is_sealed in tprocdef(pd).struct.objectoptions) then (oo_is_sealed in tprocdef(pd).struct.objectoptions) then
Message(parser_e_sealed_class_cannot_have_abstract_methods) Message(parser_e_sealed_class_cannot_have_abstract_methods)
@ -1637,6 +1647,9 @@ procedure pd_final(pd:tabstractprocdef);
begin begin
if pd.typ<>procdef then if pd.typ<>procdef then
internalerror(200910170); internalerror(200910170);
if is_objectpascal_helper(tprocdef(pd).struct) and
(m_objfpc in current_settings.modeswitches) then
Message1(parser_e_not_allowed_in_classhelper, arraytokeninfo[_FINAL].str);
if (po_virtualmethod in pd.procoptions) then if (po_virtualmethod in pd.procoptions) then
include(pd.procoptions,po_finalmethod) include(pd.procoptions,po_finalmethod)
else else
@ -1682,7 +1695,7 @@ begin
if (pd.proctypeoption=potype_constructor) and if (pd.proctypeoption=potype_constructor) and
is_object(tprocdef(pd).struct) then is_object(tprocdef(pd).struct) then
Message(parser_e_constructor_cannot_be_not_virtual); Message(parser_e_constructor_cannot_be_not_virtual);
if is_objectpascal_classhelper(tprocdef(pd).struct) and if is_objectpascal_helper(tprocdef(pd).struct) and
(m_objfpc in current_settings.modeswitches) then (m_objfpc in current_settings.modeswitches) then
Message1(parser_e_not_allowed_in_classhelper, arraytokeninfo[_VIRTUAL].str); Message1(parser_e_not_allowed_in_classhelper, arraytokeninfo[_VIRTUAL].str);
{$ifdef WITHDMT} {$ifdef WITHDMT}
@ -1734,9 +1747,11 @@ procedure pd_override(pd:tabstractprocdef);
begin begin
if pd.typ<>procdef then if pd.typ<>procdef then
internalerror(2003042611); internalerror(2003042611);
if is_objectpascal_classhelper(tprocdef(pd).struct) and if is_objectpascal_helper(tprocdef(pd).struct) then
(m_objfpc in current_settings.modeswitches) then begin
Message1(parser_e_not_allowed_in_classhelper, arraytokeninfo[_OVERRIDE].str) if m_objfpc in current_settings.modeswitches then
Message1(parser_e_not_allowed_in_classhelper, arraytokeninfo[_OVERRIDE].str)
end
else if not(is_class_or_interface_or_objc(tprocdef(pd).struct)) then else if not(is_class_or_interface_or_objc(tprocdef(pd).struct)) then
Message(parser_e_no_object_override) Message(parser_e_no_object_override)
else if is_objccategory(tprocdef(pd).struct) then else if is_objccategory(tprocdef(pd).struct) then
@ -1761,12 +1776,15 @@ var
begin begin
if pd.typ<>procdef then if pd.typ<>procdef then
internalerror(2003042613); internalerror(2003042613);
if not is_class(tprocdef(pd).struct) and if is_objectpascal_helper(tprocdef(pd).struct) then
not is_objc_class_or_protocol(tprocdef(pd).struct) then begin
Message(parser_e_msg_only_for_classes); if m_objfpc in current_settings.modeswitches then
if is_objectpascal_classhelper(tprocdef(pd).struct) and Message1(parser_e_not_allowed_in_classhelper, arraytokeninfo[_MESSAGE].str);
(m_objfpc in current_settings.modeswitches) then end
Message1(parser_e_not_allowed_in_classhelper, arraytokeninfo[_MESSAGE].str); else
if not is_class(tprocdef(pd).struct) and
not is_objc_class_or_protocol(tprocdef(pd).struct) then
Message(parser_e_msg_only_for_classes);
if ([po_msgstr,po_msgint]*pd.procoptions)<>[] then if ([po_msgstr,po_msgint]*pd.procoptions)<>[] then
Message(parser_e_multiple_messages); Message(parser_e_multiple_messages);
{ check parameter type } { check parameter type }
@ -1795,7 +1813,8 @@ begin
end end
else else
if is_constintnode(pt) and if is_constintnode(pt) and
is_class(tprocdef(pd).struct) then (is_class(tprocdef(pd).struct) or
is_objectpascal_helper(tprocdef(pd).struct)) then
begin begin
include(pd.procoptions,po_msgint); include(pd.procoptions,po_msgint);
if (Tordconstnode(pt).value<int64(low(Tprocdef(pd).messageinf.i))) or if (Tordconstnode(pt).value<int64(low(Tprocdef(pd).messageinf.i))) or
@ -1819,12 +1838,15 @@ 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).struct)) and if is_objectpascal_helper(tprocdef(pd).struct) then
not(is_objccategory(tprocdef(pd).struct)) then begin
Message(parser_e_no_object_reintroduce); if m_objfpc in current_settings.modeswitches then
if is_objectpascal_classhelper(tprocdef(pd).struct) and Message1(parser_e_not_allowed_in_classhelper, arraytokeninfo[_REINTRODUCE].str);
(m_objfpc in current_settings.modeswitches) then end
Message1(parser_e_not_allowed_in_classhelper, arraytokeninfo[_REINTRODUCE].str); else
if not(is_class_or_interface_or_object(tprocdef(pd).struct)) and
not(is_objccategory(tprocdef(pd).struct)) then
Message(parser_e_no_object_reintroduce);
end; end;
@ -2104,7 +2126,7 @@ const
( (
( (
idtok:_ABSTRACT; idtok:_ABSTRACT;
pd_flags : [pd_interface,pd_object,pd_notobjintf,pd_notrecord,pd_nothelper]; pd_flags : [pd_interface,pd_object,pd_notobjintf,pd_notrecord];
handler : @pd_abstract; handler : @pd_abstract;
pocall : pocall_none; pocall : pocall_none;
pooption : [po_abstractmethod]; pooption : [po_abstractmethod];
@ -2639,7 +2661,7 @@ const
exit; exit;
{ check if method and directive not for record/class helper } { check if method and directive not for record/class helper }
if is_objectpascal_classhelper(tprocdef(pd).struct) and if is_objectpascal_helper(tprocdef(pd).struct) and
(pd_nothelper in proc_direcdata[p].pd_flags) then (pd_nothelper in proc_direcdata[p].pd_flags) then
exit; exit;

View File

@ -1031,7 +1031,7 @@ implementation
else else
static_name:=lower(generate_nested_name(sym.owner,'_'))+'_'+sym.name; static_name:=lower(generate_nested_name(sym.owner,'_'))+'_'+sym.name;
if sym.owner.defowner.typ=objectdef then if sym.owner.defowner.typ=objectdef then
searchsym_in_class(tobjectdef(sym.owner.defowner),tobjectdef(sym.owner.defowner),static_name,sym,srsymtable) searchsym_in_class(tobjectdef(sym.owner.defowner),tobjectdef(sym.owner.defowner),static_name,sym,srsymtable,true)
else else
searchsym_in_record(trecorddef(sym.owner.defowner),static_name,sym,srsymtable); searchsym_in_record(trecorddef(sym.owner.defowner),static_name,sym,srsymtable);
if assigned(sym) then if assigned(sym) then
@ -1489,7 +1489,7 @@ implementation
p1:=comp_expr(true,false); p1:=comp_expr(true,false);
consume(_RKLAMMER); consume(_RKLAMMER);
{ type casts to class helpers aren't allowed } { type casts to class helpers aren't allowed }
if is_objectpascal_classhelper(hdef) then if is_objectpascal_helper(hdef) then
Message(parser_e_no_category_as_types) Message(parser_e_no_category_as_types)
{ recovery by not creating a conversion node } { recovery by not creating a conversion node }
else else
@ -1508,7 +1508,7 @@ implementation
begin begin
p1:=ctypenode.create(hdef); p1:=ctypenode.create(hdef);
{ search also in inherited methods } { search also in inherited methods }
searchsym_in_class(tobjectdef(hdef),tobjectdef(current_structdef),pattern,srsym,srsymtable); searchsym_in_class(tobjectdef(hdef),tobjectdef(current_structdef),pattern,srsym,srsymtable,true);
if assigned(srsym) then if assigned(srsym) then
check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg); check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg);
consume(_ID); consume(_ID);
@ -1535,16 +1535,17 @@ implementation
end end
else else
begin begin
{ TClassHelper.Something is not allowed }
if is_objectpascal_helper(hdef) then
begin
Message(parser_e_no_category_as_types);
{ for recovery we use the extended class }
hdef:=tobjectdef(hdef).extendeddef;
end;
{ class reference ? } { class reference ? }
if is_class(hdef) or if is_class(hdef) or
is_objcclass(hdef) then is_objcclass(hdef) then
begin begin
if is_objectpascal_classhelper(hdef) then
begin
Message(parser_e_no_category_as_types);
{ for recovery we use the extended class }
hdef:=tobjectdef(hdef).childof;
end;
if getaddr and (token=_POINT) then if getaddr and (token=_POINT) then
begin begin
consume(_POINT); consume(_POINT);
@ -2140,7 +2141,7 @@ implementation
if token=_ID then if token=_ID then
begin begin
structh:=tobjectdef(tclassrefdef(p1.resultdef).pointeddef); structh:=tobjectdef(tclassrefdef(p1.resultdef).pointeddef);
searchsym_in_class(tobjectdef(structh),tobjectdef(structh),pattern,srsym,srsymtable); searchsym_in_class(tobjectdef(structh),tobjectdef(structh),pattern,srsym,srsymtable,true);
if assigned(srsym) then if assigned(srsym) then
begin begin
check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg); check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg);
@ -2164,7 +2165,7 @@ implementation
if token=_ID then if token=_ID then
begin begin
structh:=tobjectdef(p1.resultdef); structh:=tobjectdef(p1.resultdef);
searchsym_in_class(tobjectdef(structh),tobjectdef(structh),pattern,srsym,srsymtable); searchsym_in_class(tobjectdef(structh),tobjectdef(structh),pattern,srsym,srsymtable,true);
if assigned(srsym) then if assigned(srsym) then
begin begin
check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg); check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg);
@ -2354,7 +2355,16 @@ implementation
assigned(current_structdef) and assigned(current_structdef) and
(current_structdef.typ=objectdef) then (current_structdef.typ=objectdef) then
begin begin
hclassdef:=tobjectdef(current_structdef).childof; { In Object Pascal helpers "inherited" always calls a
method of the extended class }
if is_objectpascal_helper(current_structdef) then
begin
if not is_class(tobjectdef(current_structdef).extendeddef) then
Internalerror(2011021701);
hclassdef:=tobjectdef(tobjectdef(current_structdef).extendeddef);
end
else
hclassdef:=tobjectdef(current_structdef).childof;
{ Objective-C categories *replace* methods in the class { Objective-C categories *replace* methods in the class
they extend, or add methods to it. So calling an they extend, or add methods to it. So calling an
inherited method always calls the method inherited from inherited method always calls the method inherited from
@ -2378,7 +2388,8 @@ implementation
if (po_msgstr in pd.procoptions) then if (po_msgstr in pd.procoptions) then
searchsym_in_class_by_msgstr(hclassdef,pd.messageinf.str^,srsym,srsymtable) searchsym_in_class_by_msgstr(hclassdef,pd.messageinf.str^,srsym,srsymtable)
else else
searchsym_in_class(hclassdef,tobjectdef(current_structdef),hs,srsym,srsymtable); { disable search for helpers }
searchsym_in_class(hclassdef,tobjectdef(current_structdef),hs,srsym,srsymtable,false);
end end
else else
begin begin
@ -2386,7 +2397,8 @@ implementation
hsorg:=orgpattern; hsorg:=orgpattern;
consume(_ID); consume(_ID);
anon_inherited:=false; anon_inherited:=false;
searchsym_in_class(hclassdef,tobjectdef(current_structdef),hs,srsym,srsymtable); { disable search for helpers }
searchsym_in_class(hclassdef,tobjectdef(current_structdef),hs,srsym,srsymtable,false);
end; end;
if assigned(srsym) then if assigned(srsym) then
begin begin
@ -2420,7 +2432,7 @@ implementation
if (po_msgint in pd.procoptions) or if (po_msgint in pd.procoptions) or
(po_msgstr in pd.procoptions) then (po_msgstr in pd.procoptions) then
begin begin
searchsym_in_class(hclassdef,hclassdef,'DEFAULTHANDLER',srsym,srsymtable); searchsym_in_class(hclassdef,hclassdef,'DEFAULTHANDLER',srsym,srsymtable,true);
if not assigned(srsym) or if not assigned(srsym) or
(srsym.typ<>procsym) then (srsym.typ<>procsym) then
internalerror(200303171); internalerror(200303171);

View File

@ -434,7 +434,7 @@ implementation
{ search the constructor also in the symbol tables of { search the constructor also in the symbol tables of
the parents } the parents }
afterassignment:=false; afterassignment:=false;
searchsym_in_class(classh,classh,pattern,srsym,srsymtable); searchsym_in_class(classh,classh,pattern,srsym,srsymtable,true);
consume(_ID); consume(_ID);
do_member_read(classh,false,srsym,p1,again,[cnf_new_call]); do_member_read(classh,false,srsym,p1,again,[cnf_new_call]);
{ we need to know which procedure is called } { we need to know which procedure is called }

View File

@ -568,7 +568,8 @@ implementation
Message(parser_e_no_generics_as_types); Message(parser_e_no_generics_as_types);
def:=generrordef; def:=generrordef;
end end
else if is_classhelper(def) then else if is_classhelper(def) and
not (stoParseClassParent in options) then
begin begin
Message(parser_e_no_category_as_types); Message(parser_e_no_category_as_types);
def:=generrordef def:=generrordef
@ -1498,12 +1499,12 @@ implementation
_CLASS : _CLASS :
begin begin
consume(_CLASS); consume(_CLASS);
def:=object_dec(odt_class,name,genericdef,genericlist,nil); def:=object_dec(odt_class,name,genericdef,genericlist,nil,ht_none);
end; end;
_OBJECT : _OBJECT :
begin begin
consume(_OBJECT); consume(_OBJECT);
def:=object_dec(odt_object,name,genericdef,genericlist,nil); def:=object_dec(odt_object,name,genericdef,genericlist,nil,ht_none);
end; end;
else else
def:=record_dec(name,genericdef,genericlist); def:=record_dec(name,genericdef,genericlist);
@ -1518,7 +1519,7 @@ implementation
if not(m_class in current_settings.modeswitches) then if not(m_class in current_settings.modeswitches) then
Message(parser_f_need_objfpc_or_delphi_mode); Message(parser_f_need_objfpc_or_delphi_mode);
consume(token); consume(token);
def:=object_dec(odt_dispinterface,name,genericdef,genericlist,nil); def:=object_dec(odt_dispinterface,name,genericdef,genericlist,nil,ht_none);
end; end;
_CLASS : _CLASS :
begin begin
@ -1548,15 +1549,15 @@ implementation
if (idtoken=_HELPER) then if (idtoken=_HELPER) then
begin begin
consume(_HELPER); consume(_HELPER);
def:=object_dec(odt_classhelper,name,genericdef,genericlist,nil); def:=object_dec(odt_helper,name,genericdef,genericlist,nil,ht_class);
end end
else else
def:=object_dec(odt_class,name,genericdef,genericlist,nil); def:=object_dec(odt_class,name,genericdef,genericlist,nil,ht_none);
end; end;
_CPPCLASS : _CPPCLASS :
begin begin
consume(token); consume(token);
def:=object_dec(odt_cppclass,name,genericdef,genericlist,nil); def:=object_dec(odt_cppclass,name,genericdef,genericlist,nil,ht_none);
end; end;
_OBJCCLASS : _OBJCCLASS :
begin begin
@ -1564,7 +1565,7 @@ implementation
Message(parser_f_need_objc); Message(parser_f_need_objc);
consume(token); consume(token);
def:=object_dec(odt_objcclass,name,genericdef,genericlist,nil); def:=object_dec(odt_objcclass,name,genericdef,genericlist,nil,ht_none);
end; end;
_INTERFACE : _INTERFACE :
begin begin
@ -1574,9 +1575,9 @@ implementation
Message(parser_f_need_objfpc_or_delphi_mode); Message(parser_f_need_objfpc_or_delphi_mode);
consume(token); consume(token);
if current_settings.interfacetype=it_interfacecom then if current_settings.interfacetype=it_interfacecom then
def:=object_dec(odt_interfacecom,name,genericdef,genericlist,nil) def:=object_dec(odt_interfacecom,name,genericdef,genericlist,nil,ht_none)
else {it_interfacecorba} else {it_interfacecorba}
def:=object_dec(odt_interfacecorba,name,genericdef,genericlist,nil); def:=object_dec(odt_interfacecorba,name,genericdef,genericlist,nil,ht_none);
end; end;
_OBJCPROTOCOL : _OBJCPROTOCOL :
begin begin
@ -1584,7 +1585,7 @@ implementation
Message(parser_f_need_objc); Message(parser_f_need_objc);
consume(token); consume(token);
def:=object_dec(odt_objcprotocol,name,genericdef,genericlist,nil); def:=object_dec(odt_objcprotocol,name,genericdef,genericlist,nil,ht_none);
end; end;
_OBJCCATEGORY : _OBJCCATEGORY :
begin begin
@ -1592,12 +1593,12 @@ implementation
Message(parser_f_need_objc); Message(parser_f_need_objc);
consume(token); consume(token);
def:=object_dec(odt_objccategory,name,genericdef,genericlist,nil); def:=object_dec(odt_objccategory,name,genericdef,genericlist,nil,ht_none);
end; end;
_OBJECT : _OBJECT :
begin begin
consume(token); consume(token);
def:=object_dec(odt_object,name,genericdef,genericlist,nil); def:=object_dec(odt_object,name,genericdef,genericlist,nil,ht_none);
end; end;
_PROCEDURE, _PROCEDURE,
_FUNCTION: _FUNCTION:

View File

@ -329,7 +329,13 @@ type
odt_objcclass, odt_objcclass,
odt_objcprotocol, odt_objcprotocol,
odt_objccategory, { note that these are changed into odt_class afterwards } odt_objccategory, { note that these are changed into odt_class afterwards }
odt_classhelper odt_helper
);
{ defines the type of the extended "structure"; only used for parsing }
thelpertype=(ht_none,
ht_class,
ht_record
); );
{ Variations in interfaces implementation } { Variations in interfaces implementation }

View File

@ -259,12 +259,9 @@ interface
childof : tobjectdef; childof : tobjectdef;
childofderef : tderef; childofderef : tderef;
{ for Object Pascal class helpers: the parent class helper is only { for Object Pascal helpers }
used to extend the scope of a used class helper by another class extendeddef : tabstractrecorddef;
helper for the same extended class or a superclass (which is defined extendeddefderef: tderef;
by childof }
helperparent : tobjectdef;
helperparentderef: tderef;
{ for C++ classes: name of the library this class is imported from } { for C++ classes: name of the library this class is imported from }
import_lib, import_lib,
{ for Objective-C: protocols and classes can have the same name there } { for Objective-C: protocols and classes can have the same name there }
@ -322,7 +319,6 @@ interface
procedure set_parent(c : tobjectdef); procedure set_parent(c : tobjectdef);
function find_destructor: tprocdef; function find_destructor: tprocdef;
function implements_any_interfaces: boolean; function implements_any_interfaces: boolean;
procedure finish_classhelper;
{ dispinterface support } { dispinterface support }
function get_next_dispid: longint; function get_next_dispid: longint;
{ enumerator support } { enumerator support }
@ -788,7 +784,7 @@ interface
function is_object(def: tdef): boolean; function is_object(def: tdef): boolean;
function is_class(def: tdef): boolean; function is_class(def: tdef): boolean;
function is_cppclass(def: tdef): boolean; function is_cppclass(def: tdef): boolean;
function is_objectpascal_classhelper(def: tdef): boolean; function is_objectpascal_helper(def: tdef): boolean;
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;
@ -4153,7 +4149,7 @@ implementation
fcurrent_dispid:=0; fcurrent_dispid:=0;
objecttype:=ot; objecttype:=ot;
childof:=nil; childof:=nil;
if objecttype in [odt_classhelper] then if objecttype=odt_helper then
owner.includeoption(sto_has_classhelper); owner.includeoption(sto_has_classhelper);
symtable:=tObjectSymtable.create(self,n,current_settings.packrecords); symtable:=tObjectSymtable.create(self,n,current_settings.packrecords);
{ create space for vmt !! } { create space for vmt !! }
@ -4163,7 +4159,7 @@ implementation
if objecttype in [odt_interfacecorba,odt_interfacecom,odt_dispinterface] then if objecttype in [odt_interfacecorba,odt_interfacecom,odt_dispinterface] then
prepareguid; prepareguid;
{ setup implemented interfaces } { setup implemented interfaces }
if objecttype in [odt_class,odt_objcclass,odt_objcprotocol,odt_classhelper] then if objecttype in [odt_class,odt_objcclass,odt_objcprotocol] then
ImplementedInterfaces:=TFPObjectList.Create(true) ImplementedInterfaces:=TFPObjectList.Create(true)
else else
ImplementedInterfaces:=nil; ImplementedInterfaces:=nil;
@ -4205,8 +4201,8 @@ implementation
iidstr:=stringdup(ppufile.getstring); iidstr:=stringdup(ppufile.getstring);
end; end;
if oo_is_classhelper in objectoptions then if objecttype=odt_helper then
ppufile.getderef(helperparentderef); ppufile.getderef(extendeddefderef);
vmtentries:=TFPList.Create; vmtentries:=TFPList.Create;
vmtentries.count:=ppufile.getlongint; vmtentries.count:=ppufile.getlongint;
@ -4369,8 +4365,8 @@ implementation
ppufile.putguid(iidguid^); ppufile.putguid(iidguid^);
ppufile.putstring(iidstr^); ppufile.putstring(iidstr^);
end; end;
if oo_is_classhelper in objectoptions then if objecttype=odt_helper then
ppufile.putderef(helperparentderef); ppufile.putderef(extendeddefderef);
ppufile.putlongint(vmtentries.count); ppufile.putlongint(vmtentries.count);
for i:=0 to vmtentries.count-1 do for i:=0 to vmtentries.count-1 do
@ -4429,8 +4425,8 @@ implementation
else else
tstoredsymtable(symtable).buildderef; tstoredsymtable(symtable).buildderef;
if oo_is_classhelper in objectoptions then if objecttype=odt_helper then
helperparentderef.build(helperparent); extendeddefderef.build(extendeddef);
for i:=0 to vmtentries.count-1 do for i:=0 to vmtentries.count-1 do
begin begin
@ -4460,8 +4456,8 @@ implementation
end end
else else
tstoredsymtable(symtable).deref; tstoredsymtable(symtable).deref;
if oo_is_classhelper in objectoptions then if objecttype=odt_helper then
helperparent:=tobjectdef(helperparentderef.resolve); extendeddef:=tobjectdef(extendeddefderef.resolve);
for i:=0 to vmtentries.count-1 do for i:=0 to vmtentries.count-1 do
begin begin
vmtentry:=pvmtentry(vmtentries[i]); vmtentry:=pvmtentry(vmtentries[i]);
@ -4743,14 +4739,9 @@ implementation
(assigned(childof) and childof.implements_any_interfaces); (assigned(childof) and childof.implements_any_interfaces);
end; end;
procedure tobjectdef.finish_classhelper;
begin
self.symtable.DefList.foreachcall(@create_class_helper_for_procdef,nil);
end;
function tobjectdef.size : aint; function tobjectdef.size : aint;
begin begin
if objecttype in [odt_class,odt_interfacecom,odt_interfacecorba,odt_dispinterface,odt_objcclass,odt_objcprotocol] then if objecttype in [odt_class,odt_interfacecom,odt_interfacecorba,odt_dispinterface,odt_objcclass,odt_objcprotocol,odt_helper] then
result:=sizeof(pint) result:=sizeof(pint)
else else
result:=tObjectSymtable(symtable).datasize; result:=tObjectSymtable(symtable).datasize;
@ -4759,7 +4750,7 @@ implementation
function tobjectdef.alignment:shortint; function tobjectdef.alignment:shortint;
begin begin
if objecttype in [odt_class,odt_interfacecom,odt_interfacecorba,odt_dispinterface,odt_objcclass,odt_objcprotocol] then if objecttype in [odt_class,odt_interfacecom,odt_interfacecorba,odt_dispinterface,odt_objcclass,odt_objcprotocol,odt_helper] then
alignment:=sizeof(pint) alignment:=sizeof(pint)
else else
alignment:=tObjectSymtable(symtable).recordalignment; alignment:=tObjectSymtable(symtable).recordalignment;
@ -4773,6 +4764,7 @@ implementation
odt_class: odt_class:
{ the +2*sizeof(pint) is size and -size } { the +2*sizeof(pint) is size and -size }
vmtmethodoffset:=(index+10)*sizeof(pint)+2*sizeof(pint); vmtmethodoffset:=(index+10)*sizeof(pint)+2*sizeof(pint);
odt_helper,
odt_objcclass, odt_objcclass,
odt_objcprotocol: odt_objcprotocol:
vmtmethodoffset:=0; vmtmethodoffset:=0;
@ -4799,6 +4791,7 @@ implementation
function tobjectdef.needs_inittable : boolean; function tobjectdef.needs_inittable : boolean;
begin begin
case objecttype of case objecttype of
odt_helper,
odt_class : odt_class :
needs_inittable:=false; needs_inittable:=false;
odt_dispinterface, odt_dispinterface,
@ -5472,16 +5465,12 @@ implementation
end; end;
function is_objectpascal_classhelper(def: tdef): boolean; function is_objectpascal_helper(def: tdef): boolean;
begin begin
result:= result:=
assigned(def) and assigned(def) and
(def.typ=objectdef) and (def.typ=objectdef) and
{ if used as a forward type } (tobjectdef(def).objecttype=odt_helper);
((tobjectdef(def).objecttype=odt_classhelper) or
{ if used as after it has been resolved }
((tobjectdef(def).objecttype=odt_class) and
(oo_is_classhelper in tobjectdef(def).objectoptions)));
end; end;
@ -5537,7 +5526,7 @@ implementation
function is_classhelper(def: tdef): boolean; function is_classhelper(def: tdef): boolean;
begin begin
result:= result:=
is_objectpascal_classhelper(def) or is_objectpascal_helper(def) or
is_objccategory(def); is_objccategory(def);
end; end;

View File

@ -220,7 +220,7 @@ interface
function searchsym_type(const s : TIDString;out srsym:tsym;out srsymtable:TSymtable):boolean; function searchsym_type(const s : TIDString;out srsym:tsym;out srsymtable:TSymtable):boolean;
function searchsym_in_module(pm:pointer;const s : TIDString;out srsym:tsym;out srsymtable:TSymtable):boolean; function searchsym_in_module(pm:pointer;const s : TIDString;out srsym:tsym;out srsymtable:TSymtable):boolean;
function searchsym_in_named_module(const unitname, symname: TIDString; out srsym: tsym; out srsymtable: tsymtable): boolean; function searchsym_in_named_module(const unitname, symname: 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; function searchsym_in_class(classh,contextclassh:tobjectdef;const s : TIDString;out srsym:tsym;out srsymtable:TSymtable;searchhelper:boolean):boolean;
function searchsym_in_record(recordh:tabstractrecorddef;const s : TIDString;out srsym:tsym;out srsymtable:TSymtable):boolean; function searchsym_in_record(recordh:tabstractrecorddef;const s : TIDString;out srsym:tsym;out srsymtable:TSymtable):boolean;
function searchsym_in_class_by_msgint(classh:tobjectdef;msgid:longint;out srdef : tdef;out srsym:tsym;out srsymtable:TSymtable):boolean; function searchsym_in_class_by_msgint(classh:tobjectdef;msgid:longint;out srdef : tdef;out srsym:tsym;out srsymtable:TSymtable):boolean;
function searchsym_in_class_by_msgstr(classh:tobjectdef;const s:string;out srsym:tsym;out srsymtable:TSymtable):boolean; function searchsym_in_class_by_msgstr(classh:tobjectdef;const s:string;out srsym:tsym;out srsymtable:TSymtable):boolean;
@ -229,7 +229,7 @@ interface
function search_struct_member(pd : tabstractrecorddef;const s : string):tsym; function search_struct_member(pd : tabstractrecorddef;const s : string):tsym;
function search_assignment_operator(from_def,to_def:Tdef;explicit:boolean):Tprocdef; function search_assignment_operator(from_def,to_def:Tdef;explicit:boolean):Tprocdef;
function search_enumerator_operator(from_def,to_def:Tdef):Tprocdef; function search_enumerator_operator(from_def,to_def:Tdef):Tprocdef;
function search_last_objectpascal_classhelper(pd : tobjectdef;out odef : tobjectdef):boolean; function search_last_objectpascal_helper(pd : tabstractrecorddef;out odef : tobjectdef):boolean;
function search_objectpascal_class_helper(pd,contextclassh : tobjectdef;const s : string; out srsym: tsym; out srsymtable: tsymtable):boolean; function search_objectpascal_class_helper(pd,contextclassh : tobjectdef;const s : string; out srsym: tsym; out srsymtable: tsymtable):boolean;
function search_class_helper(pd : tobjectdef;const s : string; out srsym: tsym; out srsymtable: tsymtable):boolean; function search_class_helper(pd : tobjectdef;const s : string; out srsym: tsym; out srsymtable: tsymtable):boolean;
function search_objc_method(const s : string; out srsym: tsym; out srsymtable: tsymtable):boolean; function search_objc_method(const s : string; out srsym: tsym; out srsymtable: tsymtable):boolean;
@ -1906,7 +1906,7 @@ implementation
srsymtable:=stackitem^.symtable; srsymtable:=stackitem^.symtable;
if (srsymtable.symtabletype=objectsymtable) then if (srsymtable.symtabletype=objectsymtable) then
begin begin
if searchsym_in_class(tobjectdef(srsymtable.defowner),tobjectdef(srsymtable.defowner),s,srsym,srsymtable) then if searchsym_in_class(tobjectdef(srsymtable.defowner),tobjectdef(srsymtable.defowner),s,srsym,srsymtable,true) then
begin begin
result:=true; result:=true;
exit; exit;
@ -2136,19 +2136,27 @@ implementation
end; end;
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;searchhelper:boolean):boolean;
var var
hashedid : THashedIDString; hashedid : THashedIDString;
exdef : tabstractrecorddef;
orgclass : tobjectdef; orgclass : tobjectdef;
i : longint; i : longint;
begin begin
{ search for a class helper method first if this is an Object Pascal { search for a class helper method first if this is an Object Pascal
class } class }
if is_class(classh) then if is_class(classh) and searchhelper then
begin begin
result:=search_objectpascal_class_helper(classh,contextclassh,s,srsym,srsymtable); result:=search_objectpascal_class_helper(classh,contextclassh,s,srsym,srsymtable);
if result then if result then
exit; begin
{ if the procsym is overloaded we need to use the "original"
symbol; the helper symbol will be find when searching for
overloads }
if (srsym.typ<>procsym) or
not (sp_has_overloaded in tprocsym(srsym).symoptions) then
Exit;
end;
end; end;
orgclass:=classh; orgclass:=classh;
@ -2159,8 +2167,9 @@ implementation
classh:=find_real_objcclass_definition(classh,true); classh:=find_real_objcclass_definition(classh,true);
{ 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 or a class helper. }
if not contextclassh.is_related(classh) then if not (contextclassh.is_related(classh) or
(contextclassh.extendeddef=classh)) then
internalerror(200811161); internalerror(200811161);
end; end;
result:=false; result:=false;
@ -2180,7 +2189,7 @@ implementation
end; end;
for i:=0 to classh.ImplementedInterfaces.count-1 do for i:=0 to classh.ImplementedInterfaces.count-1 do
begin begin
if searchsym_in_class(TImplementedInterface(classh.ImplementedInterfaces[i]).intfdef,contextclassh,s,srsym,srsymtable) then if searchsym_in_class(TImplementedInterface(classh.ImplementedInterfaces[i]).intfdef,contextclassh,s,srsym,srsymtable,true) then
begin begin
result:=true; result:=true;
exit; exit;
@ -2189,6 +2198,24 @@ implementation
end end
else else
begin begin
{ if we're searching for a symbol inside a helper, we must search in
the extended class/record/whatever first }
if is_objectpascal_helper(classh) then
begin
{ important: disable the search for helpers here! }
if is_class(classh.extendeddef) and
searchsym_in_class(tobjectdef(classh.extendeddef), tobjectdef(classh.extendeddef), s, srsym, srsymtable, false) then
begin
result:=true;
exit;
end
else if is_record(classh.extendeddef) and
searchsym_in_record(classh.extendeddef, s, srsym, srsymtable) then
begin
result:=true;
exit;
end;
end;
while assigned(classh) do while assigned(classh) do
begin begin
srsymtable:=classh.symtable; srsymtable:=classh.symtable;
@ -2435,7 +2462,7 @@ implementation
end; end;
end; end;
function search_last_objectpascal_classhelper(pd : tobjectdef;out odef : tobjectdef):boolean; function search_last_objectpascal_helper(pd : tabstractrecorddef;out odef : tobjectdef):boolean;
var var
stackitem : psymtablestackitem; stackitem : psymtablestackitem;
i : integer; i : integer;
@ -2455,11 +2482,11 @@ implementation
begin begin
if not (srsymtable.symlist[i] is ttypesym) then if not (srsymtable.symlist[i] is ttypesym) then
continue; continue;
if not is_objectpascal_classhelper(ttypesym(srsymtable.symlist[i]).typedef) then if not is_objectpascal_helper(ttypesym(srsymtable.symlist[i]).typedef) then
continue; continue;
odef:=tobjectdef(ttypesym(srsymtable.symlist[i]).typedef); odef:=tobjectdef(ttypesym(srsymtable.symlist[i]).typedef);
{ does the class helper extend the correct class? } { does the class helper extend the correct class? }
result:=odef.childof=pd; result:=odef.extendeddef=pd;
if result then if result then
exit exit
else else
@ -2482,7 +2509,7 @@ implementation
{ if there is no class helper for the class then there is no need to { if there is no class helper for the class then there is no need to
search further } search further }
if not search_last_objectpascal_classhelper(pd,classh) then if not search_last_objectpascal_helper(pd,classh) then
exit; exit;
hashedid.id:=s; hashedid.id:=s;
@ -2524,8 +2551,8 @@ implementation
end; end;
end; end;
{ try the class helper "parent" if available } { try the class helper parent if available }
classh:=classh.helperparent; classh:=classh.childof;
until classh=nil; until classh=nil;
srsym:=nil; srsym:=nil;