mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-13 11:59:19 +02:00
Reintegration of Custom Attributes branch by Joost van der Sluis with patches reworked by Svetozar Belic [patch 1/3]
Implemented attributes for class types and properties (based on work by Joost van der Sluis). Added TCustomAttribute - a base class for attributes. Added TUnitInfo record to RTTI. It contains the unit name and unit options (for now only a flag which specifies if the unit contains attributes). Added several tests for attributes. git-svn-id: trunk@42356 -
This commit is contained in:
parent
28e07f77e4
commit
b2932393df
10
.gitattributes
vendored
10
.gitattributes
vendored
@ -13139,6 +13139,16 @@ tests/test/tclass6.pp svneol=native#text/plain
|
|||||||
tests/test/tclass7.pp svneol=native#text/plain
|
tests/test/tclass7.pp svneol=native#text/plain
|
||||||
tests/test/tclass8.pp svneol=native#text/plain
|
tests/test/tclass8.pp svneol=native#text/plain
|
||||||
tests/test/tclass9.pp svneol=native#text/pascal
|
tests/test/tclass9.pp svneol=native#text/pascal
|
||||||
|
tests/test/tclassattribute1.pp svneol=native#text/pascal
|
||||||
|
tests/test/tclassattribute10.pp svneol=native#text/pascal
|
||||||
|
tests/test/tclassattribute2.pp svneol=native#text/pascal
|
||||||
|
tests/test/tclassattribute3.pp svneol=native#text/pascal
|
||||||
|
tests/test/tclassattribute4.pp svneol=native#text/pascal
|
||||||
|
tests/test/tclassattribute5.pp svneol=native#text/pascal
|
||||||
|
tests/test/tclassattribute6.pp svneol=native#text/pascal
|
||||||
|
tests/test/tclassattribute7.pp svneol=native#text/pascal
|
||||||
|
tests/test/tclassattribute8.pp svneol=native#text/pascal
|
||||||
|
tests/test/tclassattribute9.pp svneol=native#text/pascal
|
||||||
tests/test/tclassinfo1.pp svneol=native#text/pascal
|
tests/test/tclassinfo1.pp svneol=native#text/pascal
|
||||||
tests/test/tclrprop.pp svneol=native#text/plain
|
tests/test/tclrprop.pp svneol=native#text/plain
|
||||||
tests/test/tcmov1.pp svneol=native#text/plain
|
tests/test/tcmov1.pp svneol=native#text/plain
|
||||||
|
@ -44,7 +44,7 @@ interface
|
|||||||
uses
|
uses
|
||||||
cutils,cclasses,cfileutl,
|
cutils,cclasses,cfileutl,
|
||||||
globtype,finput,ogbase,fpkg,
|
globtype,finput,ogbase,fpkg,
|
||||||
symbase,symsym,
|
symbase,symsym,symtype,
|
||||||
wpobase,
|
wpobase,
|
||||||
aasmbase,aasmdata;
|
aasmbase,aasmdata;
|
||||||
|
|
||||||
@ -68,6 +68,9 @@ interface
|
|||||||
);
|
);
|
||||||
tmoduleoptions = set of tmoduleoption;
|
tmoduleoptions = set of tmoduleoption;
|
||||||
|
|
||||||
|
trtti_moduleoption = (rmo_hasattributes);
|
||||||
|
trtti_moduleoptions = set of trtti_moduleoption;
|
||||||
|
|
||||||
tlinkcontaineritem=class(tlinkedlistitem)
|
tlinkcontaineritem=class(tlinkedlistitem)
|
||||||
public
|
public
|
||||||
data : TPathStr;
|
data : TPathStr;
|
||||||
@ -195,6 +198,11 @@ interface
|
|||||||
moduleoptions: tmoduleoptions;
|
moduleoptions: tmoduleoptions;
|
||||||
deprecatedmsg: pshortstring;
|
deprecatedmsg: pshortstring;
|
||||||
|
|
||||||
|
{ contains a reference to the TUnitInfo rtti information for this module }
|
||||||
|
rttiunitinfo : TAsmSymbol;
|
||||||
|
rttiunitinfodef : tdef;
|
||||||
|
rtti_options : trtti_moduleoptions;
|
||||||
|
|
||||||
{ contains a list of types that are extended by helper types; the key is
|
{ contains a list of types that are extended by helper types; the key is
|
||||||
the full name of the type and the data is a TFPObjectList of
|
the full name of the type and the data is a TFPObjectList of
|
||||||
tobjectdef instances (the helper defs) }
|
tobjectdef instances (the helper defs) }
|
||||||
@ -634,6 +642,8 @@ implementation
|
|||||||
deprecatedmsg:=nil;
|
deprecatedmsg:=nil;
|
||||||
namespace:=nil;
|
namespace:=nil;
|
||||||
tcinitcode:=nil;
|
tcinitcode:=nil;
|
||||||
|
rttiunitinfo:=nil;
|
||||||
|
rttiunitinfodef:=nil;
|
||||||
_exports:=TLinkedList.Create;
|
_exports:=TLinkedList.Create;
|
||||||
dllscannerinputlist:=TFPHashList.Create;
|
dllscannerinputlist:=TFPHashList.Create;
|
||||||
asmdata:=casmdata.create(modulename);
|
asmdata:=casmdata.create(modulename);
|
||||||
|
@ -55,7 +55,7 @@ interface
|
|||||||
m_pointer_2_procedure,m_autoderef,m_tp_procvar,m_initfinal,m_default_ansistring,
|
m_pointer_2_procedure,m_autoderef,m_tp_procvar,m_initfinal,m_default_ansistring,
|
||||||
m_out,m_default_para,m_duplicate_names,m_hintdirective,
|
m_out,m_default_para,m_duplicate_names,m_hintdirective,
|
||||||
m_property,m_default_inline,m_except,m_advanced_records,
|
m_property,m_default_inline,m_except,m_advanced_records,
|
||||||
m_array_operators];
|
m_array_operators,m_prefixed_attributes];
|
||||||
delphiunicodemodeswitches = delphimodeswitches + [m_systemcodepage,m_default_unicodestring];
|
delphiunicodemodeswitches = delphimodeswitches + [m_systemcodepage,m_default_unicodestring];
|
||||||
fpcmodeswitches =
|
fpcmodeswitches =
|
||||||
[m_fpc,m_string_pchar,m_nested_comment,m_repeat_forward,
|
[m_fpc,m_string_pchar,m_nested_comment,m_repeat_forward,
|
||||||
|
@ -490,7 +490,8 @@ interface
|
|||||||
m_isolike_mod, { mod operation as it is required by an iso compatible compiler }
|
m_isolike_mod, { mod operation as it is required by an iso compatible compiler }
|
||||||
m_array_operators, { use Delphi compatible array operators instead of custom ones ("+") }
|
m_array_operators, { use Delphi compatible array operators instead of custom ones ("+") }
|
||||||
m_multi_helpers, { helpers can appear in multiple scopes simultaneously }
|
m_multi_helpers, { helpers can appear in multiple scopes simultaneously }
|
||||||
m_array2dynarray { regular arrays can be implicitly converted to dynamic arrays }
|
m_array2dynarray, { regular arrays can be implicitly converted to dynamic arrays }
|
||||||
|
m_prefixed_attributes { enable attributes that are defined before the type they belong to }
|
||||||
);
|
);
|
||||||
tmodeswitches = set of tmodeswitch;
|
tmodeswitches = set of tmodeswitch;
|
||||||
|
|
||||||
@ -681,7 +682,8 @@ interface
|
|||||||
'ISOMOD',
|
'ISOMOD',
|
||||||
'ARRAYOPERATORS',
|
'ARRAYOPERATORS',
|
||||||
'MULTIHELPERS',
|
'MULTIHELPERS',
|
||||||
'ARRAYTODYNARRAY'
|
'ARRAYTODYNARRAY',
|
||||||
|
'PREFIXEDATTRIBUTES'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ general_t_unitscope=01027_T_Using unit scope: $1
|
|||||||
#
|
#
|
||||||
# Scanner
|
# Scanner
|
||||||
#
|
#
|
||||||
# 02105 is the last used one
|
# 02106 is the last used one
|
||||||
#
|
#
|
||||||
% \section{Scanner messages.}
|
% \section{Scanner messages.}
|
||||||
% This section lists the messages that the scanner emits. The scanner takes
|
% This section lists the messages that the scanner emits. The scanner takes
|
||||||
@ -432,6 +432,8 @@ scan_w_setpeosversion_not_support=02103_W_SETPEOSVERSION is not supported by the
|
|||||||
scan_w_setpesubsysversion_not_support=02104_W_SETPESUBSYSVERSION is not supported by the target OS
|
scan_w_setpesubsysversion_not_support=02104_W_SETPESUBSYSVERSION is not supported by the target OS
|
||||||
% The \var{\{\$SETPESUBSYSVERSION\}} directive is not supported by the target OS.
|
% The \var{\{\$SETPESUBSYSVERSION\}} directive is not supported by the target OS.
|
||||||
scan_n_changecputype=02105_N_Changed CPU type to be consistent with specified controller
|
scan_n_changecputype=02105_N_Changed CPU type to be consistent with specified controller
|
||||||
|
scan_e_unresolved_attribute=02106_E_Unresolved custom attribute: "$1".
|
||||||
|
% A custom attribute is defined, but there is no identifier to bind it to.
|
||||||
% \end{description}
|
% \end{description}
|
||||||
#
|
#
|
||||||
# Parser
|
# Parser
|
||||||
|
@ -57,6 +57,8 @@ interface
|
|||||||
function ref_rtti(def:tdef;rt:trttitype;indirect:boolean;suffix:tsymstr):tasmsymbol;
|
function ref_rtti(def:tdef;rt:trttitype;indirect:boolean;suffix:tsymstr):tasmsymbol;
|
||||||
procedure write_rtti_name(tcb: ttai_typedconstbuilder; def: tdef);
|
procedure write_rtti_name(tcb: ttai_typedconstbuilder; def: tdef);
|
||||||
procedure write_rtti_data(tcb: ttai_typedconstbuilder; def:tdef; rt: trttitype);
|
procedure write_rtti_data(tcb: ttai_typedconstbuilder; def:tdef; rt: trttitype);
|
||||||
|
procedure write_attribute_data(tcb: ttai_typedconstbuilder; def:tdef);
|
||||||
|
procedure write_unit_info_reference(tcb: ttai_typedconstbuilder);
|
||||||
procedure write_child_rtti_data(def:tdef;rt:trttitype);
|
procedure write_child_rtti_data(def:tdef;rt:trttitype);
|
||||||
procedure write_rtti_reference(tcb: ttai_typedconstbuilder; def: tdef; rt: trttitype);
|
procedure write_rtti_reference(tcb: ttai_typedconstbuilder; def: tdef; rt: trttitype);
|
||||||
procedure write_methods(tcb:ttai_typedconstbuilder;st:tsymtable;visibilities:tvisibilities);
|
procedure write_methods(tcb:ttai_typedconstbuilder;st:tsymtable;visibilities:tvisibilities);
|
||||||
@ -72,6 +74,8 @@ interface
|
|||||||
function get_rtti_label(def:tdef;rt:trttitype;indirect:boolean):tasmsymbol; inline;
|
function get_rtti_label(def:tdef;rt:trttitype;indirect:boolean):tasmsymbol; inline;
|
||||||
function get_rtti_label_ord2str(def:tdef;rt:trttitype;indirect:boolean):tasmsymbol; inline;
|
function get_rtti_label_ord2str(def:tdef;rt:trttitype;indirect:boolean):tasmsymbol; inline;
|
||||||
function get_rtti_label_str2ord(def:tdef;rt:trttitype;indirect:boolean):tasmsymbol; inline;
|
function get_rtti_label_str2ord(def:tdef;rt:trttitype;indirect:boolean):tasmsymbol; inline;
|
||||||
|
procedure start_write_unit_info;
|
||||||
|
procedure after_write_unit_info(st: TSymtable);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ generate RTTI and init tables }
|
{ generate RTTI and init tables }
|
||||||
@ -116,6 +120,8 @@ implementation
|
|||||||
{ no Delphi-style RTTI for managed platforms }
|
{ no Delphi-style RTTI for managed platforms }
|
||||||
if target_info.system in systems_managed_vm then
|
if target_info.system in systems_managed_vm then
|
||||||
exit;
|
exit;
|
||||||
|
if current_module.rttiunitinfo=nil then
|
||||||
|
RTTIWriter.start_write_unit_info;
|
||||||
for i:=0 to st.DefList.Count-1 do
|
for i:=0 to st.DefList.Count-1 do
|
||||||
begin
|
begin
|
||||||
def:=tdef(st.DefList[i]);
|
def:=tdef(st.DefList[i]);
|
||||||
@ -170,6 +176,8 @@ implementation
|
|||||||
(ds_rtti_table_used in def.defstates) then
|
(ds_rtti_table_used in def.defstates) then
|
||||||
RTTIWriter.write_rtti(def,fullrtti);
|
RTTIWriter.write_rtti(def,fullrtti);
|
||||||
end;
|
end;
|
||||||
|
if st.symtabletype = staticsymtable then
|
||||||
|
RTTIWriter.after_write_unit_info(st);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -753,6 +761,9 @@ implementation
|
|||||||
proctypesinfo : byte;
|
proctypesinfo : byte;
|
||||||
propnameitem : tpropnamelistitem;
|
propnameitem : tpropnamelistitem;
|
||||||
propdefname : string;
|
propdefname : string;
|
||||||
|
attridx: ShortInt;
|
||||||
|
attrcount: byte;
|
||||||
|
attr: trtti_attribute;
|
||||||
|
|
||||||
procedure writeaccessproc(pap:tpropaccesslisttypes; shiftvalue : byte; unsetvalue: byte);
|
procedure writeaccessproc(pap:tpropaccesslisttypes; shiftvalue : byte; unsetvalue: byte);
|
||||||
var
|
var
|
||||||
@ -897,7 +908,23 @@ implementation
|
|||||||
internalerror(200512201);
|
internalerror(200512201);
|
||||||
tcb.emit_ord_const(propnameitem.propindex,u16inttype);
|
tcb.emit_ord_const(propnameitem.propindex,u16inttype);
|
||||||
tcb.emit_ord_const(proctypesinfo,u8inttype);
|
tcb.emit_ord_const(proctypesinfo,u8inttype);
|
||||||
|
|
||||||
|
{ Write property attribute count }
|
||||||
|
if assigned(tpropertysym(sym).rtti_attributesdef) then
|
||||||
|
attrcount:=tpropertysym(sym).rtti_attributesdef.get_attribute_count
|
||||||
|
else
|
||||||
|
attrcount:=0;
|
||||||
|
tcb.emit_ord_const(attrcount,u8inttype);
|
||||||
|
|
||||||
|
{ Write property name }
|
||||||
tcb.emit_shortstring_const(tpropertysym(sym).realname);
|
tcb.emit_shortstring_const(tpropertysym(sym).realname);
|
||||||
|
|
||||||
|
{ Write property attributes }
|
||||||
|
for attridx := 0 to attrcount-1 do
|
||||||
|
begin
|
||||||
|
attr := trtti_attribute(tpropertysym(sym).rtti_attributesdef.rtti_attributes[attridx]);
|
||||||
|
tcb.emit_tai(Tai_const.Createname(attr.symbolname,AT_DATA_FORCEINDIRECT,0), cpointerdef.getreusable(ttypesym(attr.typesym).typedef));
|
||||||
|
end;
|
||||||
tcb.end_anonymous_record;
|
tcb.end_anonymous_record;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -1551,8 +1578,12 @@ implementation
|
|||||||
{ total number of unique properties }
|
{ total number of unique properties }
|
||||||
tcb.emit_ord_const(propnamelist.count,u16inttype);
|
tcb.emit_ord_const(propnamelist.count,u16inttype);
|
||||||
|
|
||||||
{ write unit name }
|
{ reference to unitinfo with unit-name }
|
||||||
tcb.emit_shortstring_const(current_module.realmodulename^);
|
write_unit_info_reference(tcb);
|
||||||
|
|
||||||
|
{ TAttributeData }
|
||||||
|
if rmo_hasattributes in current_module.rtti_options then
|
||||||
|
write_attribute_data(tcb, def);
|
||||||
|
|
||||||
{ write published properties for this object }
|
{ write published properties for this object }
|
||||||
published_properties_write_rtti_data(tcb,propnamelist,def.symtable);
|
published_properties_write_rtti_data(tcb,propnamelist,def.symtable);
|
||||||
@ -1715,6 +1746,31 @@ implementation
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TRTTIWriter.write_attribute_data(tcb: ttai_typedconstbuilder; def: tdef);
|
||||||
|
var
|
||||||
|
count: word;
|
||||||
|
idx: byte;
|
||||||
|
attr: trtti_attribute;
|
||||||
|
begin
|
||||||
|
if (def.typ = objectdef) and (assigned(tobjectdef(def).rtti_attributesdef)) then
|
||||||
|
count:=tobjectdef(def).rtti_attributesdef.get_attribute_count
|
||||||
|
else
|
||||||
|
count:=0;
|
||||||
|
|
||||||
|
tcb.emit_ord_const(count,u16inttype);
|
||||||
|
|
||||||
|
if count>0 then
|
||||||
|
for idx:=0 to count-1 do
|
||||||
|
begin
|
||||||
|
attr := trtti_attribute(tobjectdef(def).rtti_attributesdef.rtti_attributes[idx]);
|
||||||
|
tcb.emit_tai(Tai_const.Createname(attr.symbolname,AT_DATA_FORCEINDIRECT,0), cpointerdef.getreusable(ttypesym(attr.typesym).typedef));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TRTTIWriter.write_unit_info_reference(tcb: ttai_typedconstbuilder);
|
||||||
|
begin
|
||||||
|
tcb.emit_tai(Tai_const.Create_sym(current_module.rttiunitinfo), current_module.rttiunitinfodef);
|
||||||
|
end;
|
||||||
|
|
||||||
function enumsym_compare_name(item1, item2: pointer): Integer;
|
function enumsym_compare_name(item1, item2: pointer): Integer;
|
||||||
var
|
var
|
||||||
@ -2098,5 +2154,37 @@ implementation
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TRTTIWriter.start_write_unit_info;
|
||||||
|
var
|
||||||
|
s : string;
|
||||||
|
tcb: ttai_typedconstbuilder;
|
||||||
|
begin
|
||||||
|
tcb:=ctai_typedconstbuilder.create([tcalo_make_dead_strippable,tcalo_new_section]);
|
||||||
|
tcb.begin_anonymous_record(make_mangledname('RTTIU',current_module.localsymtable,''), 1, sizeof(pint), 1, 1);
|
||||||
|
|
||||||
|
{ write the TRTTIUnitOptions }
|
||||||
|
tcb.emit_ord_const(byte(longint(current_module.rtti_options)),u8inttype);
|
||||||
|
|
||||||
|
{ Write the unit-name }
|
||||||
|
s := current_module.realmodulename^;
|
||||||
|
tcb.emit_shortstring_const(current_module.realmodulename^);
|
||||||
|
|
||||||
|
current_module.rttiunitinfodef := tcb.end_anonymous_record;
|
||||||
|
current_module.rttiunitinfo := current_asmdata.DefineAsmSymbol(make_mangledname('RTTIU_',current_module.localsymtable,''),AB_GLOBAL,AT_DATA, current_module.rttiunitinfodef);
|
||||||
|
current_asmdata.AsmLists[al_rtti].concatList(
|
||||||
|
tcb.get_final_asmlist(current_module.rttiunitinfo,current_module.rttiunitinfodef,sec_rodata,current_module.rttiunitinfo.name,const_align(sizeof(pint))));
|
||||||
|
tcb.free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TRTTIWriter.after_write_unit_info(st: TSymtable);
|
||||||
|
begin
|
||||||
|
if current_module.rttiunitinfo<>nil then
|
||||||
|
begin
|
||||||
|
{ Write a trailing 255 to mark the end of the symbols-list }
|
||||||
|
current_asmdata.asmlists[al_rtti].concat(cai_align.Create(sizeof(TConstPtrUInt)));
|
||||||
|
current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(255));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -43,6 +43,8 @@ interface
|
|||||||
end;
|
end;
|
||||||
pinitfinalentry = ^tinitfinalentry;
|
pinitfinalentry = ^tinitfinalentry;
|
||||||
|
|
||||||
|
{ tnodeutils }
|
||||||
|
|
||||||
tnodeutils = class
|
tnodeutils = class
|
||||||
class function call_fail_node:tnode; virtual;
|
class function call_fail_node:tnode; virtual;
|
||||||
class function initialize_data_node(p:tnode; force: boolean):tnode; virtual;
|
class function initialize_data_node(p:tnode; force: boolean):tnode; virtual;
|
||||||
@ -113,6 +115,7 @@ interface
|
|||||||
|
|
||||||
class function create_main_procdef(const name: string; potype:tproctypeoption; ps: tprocsym):tdef; virtual;
|
class function create_main_procdef(const name: string; potype:tproctypeoption; ps: tprocsym):tdef; virtual;
|
||||||
class procedure InsertInitFinalTable;
|
class procedure InsertInitFinalTable;
|
||||||
|
class procedure InsertRTTIUnitList; virtual;
|
||||||
protected
|
protected
|
||||||
class procedure InsertRuntimeInits(const prefix:string;list:TLinkedList;unitflag:tmoduleflag); virtual;
|
class procedure InsertRuntimeInits(const prefix:string;list:TLinkedList;unitflag:tmoduleflag); virtual;
|
||||||
class procedure InsertRuntimeInitsTablesTable(const prefix,tablename:string;unitflag:tmoduleflag); virtual;
|
class procedure InsertRuntimeInitsTablesTable(const prefix,tablename:string;unitflag:tmoduleflag); virtual;
|
||||||
@ -1031,6 +1034,32 @@ implementation
|
|||||||
release_init_final_list(entries);
|
release_init_final_list(entries);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
class procedure tnodeutils.InsertRTTIUnitList;
|
||||||
|
var
|
||||||
|
hp : tused_unit;
|
||||||
|
unitinits : TAsmList;
|
||||||
|
count : longint;
|
||||||
|
begin
|
||||||
|
unitinits:=TAsmList.Create;
|
||||||
|
count:=0;
|
||||||
|
hp:=tused_unit(usedunits.first);
|
||||||
|
while assigned(hp) do
|
||||||
|
begin
|
||||||
|
unitinits.concat(Tai_const.Createname(make_mangledname('RTTIU_',hp.u.globalsymtable,''),0));
|
||||||
|
inc(count);
|
||||||
|
hp:=tused_unit(hp.next);
|
||||||
|
end;
|
||||||
|
{ Insert TableCount,InitCount at start }
|
||||||
|
unitinits.insert(Tai_const.Create_32bit(count));
|
||||||
|
{ Add to data segment }
|
||||||
|
maybe_new_object_file(current_asmdata.asmlists[al_globals]);
|
||||||
|
new_section(current_asmdata.asmlists[al_globals],sec_data,'RTTIUNITLIST',sizeof(pint));
|
||||||
|
current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('RTTIUNITLIST',AT_DATA,0, carraydef.getreusable(cansichartype,length('RTTIUNITLIST'))));
|
||||||
|
current_asmdata.asmlists[al_globals].concatlist(unitinits);
|
||||||
|
current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname('RTTIUNITLIST'));
|
||||||
|
unitinits.free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
class procedure tnodeutils.insert_init_final_table(entries:tfplist);
|
class procedure tnodeutils.insert_init_final_table(entries:tfplist);
|
||||||
var
|
var
|
||||||
|
@ -41,24 +41,27 @@ interface
|
|||||||
procedure consts_dec(in_structure, allow_typed_const: boolean;out had_generic:boolean);
|
procedure consts_dec(in_structure, allow_typed_const: boolean;out had_generic:boolean);
|
||||||
procedure label_dec;
|
procedure label_dec;
|
||||||
procedure type_dec(out had_generic:boolean);
|
procedure type_dec(out had_generic:boolean);
|
||||||
procedure types_dec(in_structure: boolean;out had_generic:boolean);
|
procedure types_dec(in_structure: boolean;out had_generic:boolean;var rtti_attrs_def: trtti_attributesdef);
|
||||||
procedure var_dec(out had_generic:boolean);
|
procedure var_dec(out had_generic:boolean);
|
||||||
procedure threadvar_dec(out had_generic:boolean);
|
procedure threadvar_dec(out had_generic:boolean);
|
||||||
procedure property_dec;
|
procedure property_dec;
|
||||||
procedure resourcestring_dec(out had_generic:boolean);
|
procedure resourcestring_dec(out had_generic:boolean);
|
||||||
|
procedure parse_rttiattributes(var rtti_attrs_def: trtti_attributesdef);
|
||||||
|
procedure add_synthetic_rtti_funtion_declarations(rtti_attrs_def: trtti_attributesdef; name: shortstring);
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
|
SysUtils,
|
||||||
{ common }
|
{ common }
|
||||||
cutils,
|
cutils,
|
||||||
{ global }
|
{ global }
|
||||||
globals,tokens,verbose,widestr,constexp,
|
globals,tokens,verbose,widestr,constexp,
|
||||||
systems,aasmdata,fmodule,compinnr,
|
systems,aasmdata,fmodule,compinnr,
|
||||||
{ symtable }
|
{ symtable }
|
||||||
symconst,symbase,symtype,symcpu,symcreat,defutil,
|
symconst,symbase,symtype,symcpu,symcreat,defutil,defcmp,symtable,
|
||||||
{ pass 1 }
|
{ pass 1 }
|
||||||
ninl,ncon,nobj,ngenutil,
|
ninl,ncon,nobj,ngenutil,nld,nmem,ncal,
|
||||||
{ parser }
|
{ parser }
|
||||||
scanner,
|
scanner,
|
||||||
pbase,pexpr,ptype,ptconst,pdecsub,pdecvar,pdecobj,pgenutil,pparautl,
|
pbase,pexpr,ptype,ptconst,pdecsub,pdecvar,pdecobj,pgenutil,pparautl,
|
||||||
@ -69,6 +72,39 @@ implementation
|
|||||||
cpuinfo
|
cpuinfo
|
||||||
;
|
;
|
||||||
|
|
||||||
|
var
|
||||||
|
system_custom_attribute_def: tobjectdef = nil;
|
||||||
|
|
||||||
|
function is_system_custom_attribute_descendant(def:tdef): Boolean;
|
||||||
|
begin
|
||||||
|
if system_custom_attribute_def=nil then
|
||||||
|
system_custom_attribute_def := tobjectdef(search_system_type('TCUSTOMATTRIBUTE').typedef);
|
||||||
|
Result := def_is_related(def, system_custom_attribute_def);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure create_renamed_attr_type_if_needed(hdef: tobjectdef);
|
||||||
|
const
|
||||||
|
attrconst = 'attribute';
|
||||||
|
var
|
||||||
|
newname : TIDString;
|
||||||
|
newtypeattr : ttypesym;
|
||||||
|
i: integer;
|
||||||
|
begin
|
||||||
|
if not is_system_custom_attribute_descendant(hdef) then
|
||||||
|
Exit;
|
||||||
|
|
||||||
|
{ Check if the name ends with 'attribute'. }
|
||||||
|
i := Pos(attrconst, lower(hdef.typename), max(0, length(hdef.typename) - length(attrconst)));
|
||||||
|
newname:=Copy(hdef.typename, 0, i-1);
|
||||||
|
if (i > 0) and (length(newname) > 0) then
|
||||||
|
begin
|
||||||
|
{ Create a new typesym with 'attribute' removed. }
|
||||||
|
newtypeattr:=ctypesym.create(newname,hdef,true);
|
||||||
|
newtypeattr.visibility:=symtablestack.top.currentvisibility;
|
||||||
|
include(newtypeattr.symoptions,sp_implicitrename);
|
||||||
|
symtablestack.top.insert(newtypeattr);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function readconstant(const orgname:string;const filepos:tfileposinfo; out nodetype: tnodetype):tconstsym;
|
function readconstant(const orgname:string;const filepos:tfileposinfo; out nodetype: tnodetype):tconstsym;
|
||||||
var
|
var
|
||||||
@ -386,7 +422,100 @@ implementation
|
|||||||
consume(_SEMICOLON);
|
consume(_SEMICOLON);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure types_dec(in_structure: boolean;out had_generic:boolean);
|
function find_create_constructor(objdef: tobjectdef): tsymentry;
|
||||||
|
begin
|
||||||
|
while assigned(objdef) do
|
||||||
|
begin
|
||||||
|
result:=objdef.symtable.Find('CREATE');
|
||||||
|
if assigned(result) then
|
||||||
|
exit;
|
||||||
|
objdef:=objdef.childof;
|
||||||
|
end;
|
||||||
|
// A class without a constructor called 'create'?!?
|
||||||
|
internalerror(2012111101);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure parse_rttiattributes(var rtti_attrs_def: trtti_attributesdef);
|
||||||
|
var
|
||||||
|
p, p1: tnode;
|
||||||
|
again: boolean;
|
||||||
|
od: tobjectdef;
|
||||||
|
constrSym: tsymentry;
|
||||||
|
constrProcDef: tprocdef;
|
||||||
|
typeSym: ttypesym;
|
||||||
|
oldblock_type: tblock_type;
|
||||||
|
begin
|
||||||
|
consume(_LECKKLAMMER);
|
||||||
|
|
||||||
|
{ Parse attribute type }
|
||||||
|
p := factor(false,[ef_type_only]);
|
||||||
|
if p.nodetype<> errorn then
|
||||||
|
begin
|
||||||
|
typeSym := ttypesym(ttypenode(p).typesym);
|
||||||
|
od := tobjectdef(ttypenode(p).typedef);
|
||||||
|
if Assigned(od) then
|
||||||
|
begin
|
||||||
|
{ Check if the attribute class is related to TCustomAttribute }
|
||||||
|
if not is_system_custom_attribute_descendant(od) then
|
||||||
|
incompatibletypes(od, system_custom_attribute_def);
|
||||||
|
|
||||||
|
{ Search the tprocdef of the constructor which has to be called. }
|
||||||
|
constrSym := find_create_constructor(od);
|
||||||
|
if constrSym.typ<>procsym then
|
||||||
|
internalerror(2018102301);
|
||||||
|
constrProcDef:=tprocsym(constrSym).find_procdef_bytype(potype_constructor);
|
||||||
|
|
||||||
|
{ Parse the attribute-parameters as if it is a list of parameters from
|
||||||
|
a call to the constrProcDef constructor in an execution-block. }
|
||||||
|
p1 := cloadvmtaddrnode.create(ctypenode.create(od));
|
||||||
|
again:=true;
|
||||||
|
oldblock_type := block_type;
|
||||||
|
block_type := bt_body;
|
||||||
|
do_member_read(od,false,constrProcDef.procsym,p1,again,[], nil);
|
||||||
|
|
||||||
|
{ Check the number of parameters }
|
||||||
|
if (tcallnode(p1).para_count < constrProcDef.minparacount) then
|
||||||
|
CGMessagePos1(p.fileinfo, parser_e_wrong_parameter_size, od.typename + '.' + constrProcDef.procsym.prettyname);
|
||||||
|
|
||||||
|
block_type:=oldblock_type;
|
||||||
|
|
||||||
|
{ Add attribute to attribute list which will be added
|
||||||
|
to the property which is defined next. }
|
||||||
|
if not assigned(rtti_attrs_def) then
|
||||||
|
rtti_attrs_def := trtti_attributesdef.create;
|
||||||
|
rtti_attrs_def.addattribute(typeSym,p1);
|
||||||
|
|
||||||
|
Include(current_module.rtti_options, rmo_hasattributes);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
p.free;
|
||||||
|
consume(_RECKKLAMMER);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure add_synthetic_rtti_funtion_declarations(rtti_attrs_def: trtti_attributesdef; name: shortstring);
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
sstate: tscannerstate;
|
||||||
|
attribute: trtti_attribute;
|
||||||
|
pd: tprocdef;
|
||||||
|
begin
|
||||||
|
name := StringReplace(name, '.', '_', [rfReplaceAll]);
|
||||||
|
for i := 0 to rtti_attrs_def.get_attribute_count-1 do
|
||||||
|
begin
|
||||||
|
attribute := trtti_attribute(rtti_attrs_def.rtti_attributes[i]);
|
||||||
|
replace_scanner('rtti_class_attributes',sstate);
|
||||||
|
if str_parse_method_dec('function rtti_'+name+'_'+IntToStr(i)+':'+ attribute.typesym.Name +';',potype_function,false,tabstractrecorddef(ttypesym(attribute.typesym).typedef),pd) then
|
||||||
|
pd.synthetickind:=tsk_get_rttiattribute
|
||||||
|
else
|
||||||
|
internalerror(2012052601);
|
||||||
|
pd.skpara:=attribute;
|
||||||
|
attribute.symbolname:=pd.mangledname;
|
||||||
|
restore_scanner(sstate);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure types_dec(in_structure: boolean;out had_generic:boolean;var rtti_attrs_def: trtti_attributesdef);
|
||||||
|
|
||||||
function determine_generic_def(name:tidstring):tstoreddef;
|
function determine_generic_def(name:tidstring):tstoreddef;
|
||||||
var
|
var
|
||||||
@ -484,6 +613,11 @@ implementation
|
|||||||
generictypelist:=nil;
|
generictypelist:=nil;
|
||||||
generictokenbuf:=nil;
|
generictokenbuf:=nil;
|
||||||
|
|
||||||
|
{ class attribute definitions? }
|
||||||
|
if m_prefixed_attributes in current_settings.modeswitches then
|
||||||
|
while token=_LECKKLAMMER do
|
||||||
|
parse_rttiattributes(rtti_attrs_def);
|
||||||
|
|
||||||
{ fpc generic declaration? }
|
{ fpc generic declaration? }
|
||||||
if first then
|
if first then
|
||||||
had_generic:=not(m_delphi in current_settings.modeswitches) and try_to_consume(_GENERIC);
|
had_generic:=not(m_delphi in current_settings.modeswitches) and try_to_consume(_GENERIC);
|
||||||
@ -888,6 +1022,15 @@ implementation
|
|||||||
vmtbuilder.free;
|
vmtbuilder.free;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ If there are attribute-properties available, bind them to
|
||||||
|
this object }
|
||||||
|
if assigned(rtti_attrs_def) then
|
||||||
|
begin
|
||||||
|
add_synthetic_rtti_funtion_declarations(rtti_attrs_def,hdef.typesym.Name);
|
||||||
|
tobjectdef(hdef).rtti_attributesdef:=rtti_attrs_def;
|
||||||
|
rtti_attrs_def := nil;
|
||||||
|
end;
|
||||||
|
|
||||||
{ In case of an objcclass, verify that all methods have a message
|
{ In case of an objcclass, verify that all methods have a message
|
||||||
name set. We only check this now, because message names can be set
|
name set. We only check this now, because message names can be set
|
||||||
during the protocol (interface) mapping. At the same time, set the
|
during the protocol (interface) mapping. At the same time, set the
|
||||||
@ -903,6 +1046,9 @@ implementation
|
|||||||
|
|
||||||
if is_cppclass(hdef) then
|
if is_cppclass(hdef) then
|
||||||
tobjectdef(hdef).finish_cpp_data;
|
tobjectdef(hdef).finish_cpp_data;
|
||||||
|
|
||||||
|
if (m_prefixed_attributes in current_settings.modeswitches) then
|
||||||
|
create_renamed_attr_type_if_needed(tobjectdef(hdef));
|
||||||
end;
|
end;
|
||||||
recorddef :
|
recorddef :
|
||||||
begin
|
begin
|
||||||
@ -942,7 +1088,10 @@ implementation
|
|||||||
else
|
else
|
||||||
had_generic:=false;
|
had_generic:=false;
|
||||||
first:=false;
|
first:=false;
|
||||||
until (token<>_ID) or
|
if assigned(rtti_attrs_def) and (rtti_attrs_def.get_attribute_count>0) then
|
||||||
|
Message1(scan_e_unresolved_attribute,trtti_attribute(rtti_attrs_def.rtti_attributes[0]).typesym.prettyname);
|
||||||
|
|
||||||
|
until ((token<>_ID) and (token<>_LECKKLAMMER)) or
|
||||||
(in_structure and
|
(in_structure and
|
||||||
((idtoken in [_PRIVATE,_PROTECTED,_PUBLIC,_PUBLISHED,_STRICT]) or
|
((idtoken in [_PRIVATE,_PROTECTED,_PUBLIC,_PUBLISHED,_STRICT]) or
|
||||||
((m_final_fields in current_settings.modeswitches) and
|
((m_final_fields in current_settings.modeswitches) and
|
||||||
@ -958,9 +1107,12 @@ implementation
|
|||||||
|
|
||||||
{ reads a type declaration to the symbol table }
|
{ reads a type declaration to the symbol table }
|
||||||
procedure type_dec(out had_generic:boolean);
|
procedure type_dec(out had_generic:boolean);
|
||||||
|
var
|
||||||
|
rtti_attrs_def: trtti_attributesdef;
|
||||||
begin
|
begin
|
||||||
consume(_TYPE);
|
consume(_TYPE);
|
||||||
types_dec(false,had_generic);
|
rtti_attrs_def := nil;
|
||||||
|
types_dec(false,had_generic,rtti_attrs_def);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ interface
|
|||||||
function class_destructor_head(astruct: tabstractrecorddef):tprocdef;
|
function class_destructor_head(astruct: tabstractrecorddef):tprocdef;
|
||||||
function constructor_head:tprocdef;
|
function constructor_head:tprocdef;
|
||||||
function destructor_head:tprocdef;
|
function destructor_head:tprocdef;
|
||||||
procedure struct_property_dec(is_classproperty:boolean);
|
procedure struct_property_dec(is_classproperty:boolean;var rtti_attrs_def: trtti_attributesdef);
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
@ -162,7 +162,7 @@ implementation
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure struct_property_dec(is_classproperty:boolean);
|
procedure struct_property_dec(is_classproperty:boolean;var rtti_attrs_def: trtti_attributesdef);
|
||||||
var
|
var
|
||||||
p : tpropertysym;
|
p : tpropertysym;
|
||||||
begin
|
begin
|
||||||
@ -214,6 +214,13 @@ implementation
|
|||||||
Message(parser_e_enumerator_identifier_required);
|
Message(parser_e_enumerator_identifier_required);
|
||||||
consume(_SEMICOLON);
|
consume(_SEMICOLON);
|
||||||
end;
|
end;
|
||||||
|
if assigned(rtti_attrs_def) then
|
||||||
|
begin
|
||||||
|
add_synthetic_rtti_funtion_declarations(rtti_attrs_def,current_structdef.RttiName+'_'+p.RealName);
|
||||||
|
p.rtti_attributesdef := rtti_attrs_def;
|
||||||
|
rtti_attrs_def:=nil;
|
||||||
|
end;
|
||||||
|
|
||||||
{ hint directives, these can be separated by semicolons here,
|
{ hint directives, these can be separated by semicolons here,
|
||||||
that needs to be handled here with a loop (PFV) }
|
that needs to be handled here with a loop (PFV) }
|
||||||
while try_consume_hintdirective(p.symoptions,p.deprecatedmsg) do
|
while try_consume_hintdirective(p.symoptions,p.deprecatedmsg) do
|
||||||
@ -1056,6 +1063,7 @@ implementation
|
|||||||
threadvar_fields : boolean;
|
threadvar_fields : boolean;
|
||||||
vdoptions: tvar_dec_options;
|
vdoptions: tvar_dec_options;
|
||||||
fieldlist: tfpobjectlist;
|
fieldlist: tfpobjectlist;
|
||||||
|
rtti_attrs_def: trtti_attributesdef;
|
||||||
|
|
||||||
|
|
||||||
procedure parse_const;
|
procedure parse_const;
|
||||||
@ -1153,6 +1161,7 @@ implementation
|
|||||||
class_fields:=false;
|
class_fields:=false;
|
||||||
is_final:=false;
|
is_final:=false;
|
||||||
final_fields:=false;
|
final_fields:=false;
|
||||||
|
rtti_attrs_def:=nil;
|
||||||
hadgeneric:=false;
|
hadgeneric:=false;
|
||||||
threadvar_fields:=false;
|
threadvar_fields:=false;
|
||||||
object_member_blocktype:=bt_general;
|
object_member_blocktype:=bt_general;
|
||||||
@ -1168,10 +1177,12 @@ implementation
|
|||||||
end;
|
end;
|
||||||
_VAR :
|
_VAR :
|
||||||
begin
|
begin
|
||||||
|
rtti_attrs_def := nil;
|
||||||
parse_var(false);
|
parse_var(false);
|
||||||
end;
|
end;
|
||||||
_CONST:
|
_CONST:
|
||||||
begin
|
begin
|
||||||
|
rtti_attrs_def := nil;
|
||||||
parse_const
|
parse_const
|
||||||
end;
|
end;
|
||||||
_THREADVAR :
|
_THREADVAR :
|
||||||
@ -1266,6 +1277,7 @@ implementation
|
|||||||
begin
|
begin
|
||||||
if object_member_blocktype=bt_general then
|
if object_member_blocktype=bt_general then
|
||||||
begin
|
begin
|
||||||
|
rtti_attrs_def := nil;
|
||||||
if (idtoken=_GENERIC) and
|
if (idtoken=_GENERIC) and
|
||||||
not (m_delphi in current_settings.modeswitches) and
|
not (m_delphi in current_settings.modeswitches) and
|
||||||
(
|
(
|
||||||
@ -1313,7 +1325,7 @@ implementation
|
|||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
else if object_member_blocktype=bt_type then
|
else if object_member_blocktype=bt_type then
|
||||||
types_dec(true,hadgeneric)
|
types_dec(true,hadgeneric, rtti_attrs_def)
|
||||||
else if object_member_blocktype=bt_const then
|
else if object_member_blocktype=bt_const then
|
||||||
begin
|
begin
|
||||||
typedconstswritable:=false;
|
typedconstswritable:=false;
|
||||||
@ -1336,7 +1348,7 @@ implementation
|
|||||||
end;
|
end;
|
||||||
_PROPERTY :
|
_PROPERTY :
|
||||||
begin
|
begin
|
||||||
struct_property_dec(is_classdef);
|
struct_property_dec(is_classdef, rtti_attrs_def);
|
||||||
fields_allowed:=false;
|
fields_allowed:=false;
|
||||||
is_classdef:=false;
|
is_classdef:=false;
|
||||||
end;
|
end;
|
||||||
@ -1349,13 +1361,23 @@ implementation
|
|||||||
_CONSTRUCTOR,
|
_CONSTRUCTOR,
|
||||||
_DESTRUCTOR :
|
_DESTRUCTOR :
|
||||||
begin
|
begin
|
||||||
|
rtti_attrs_def := nil;
|
||||||
method_dec(current_structdef,is_classdef,hadgeneric);
|
method_dec(current_structdef,is_classdef,hadgeneric);
|
||||||
fields_allowed:=false;
|
fields_allowed:=false;
|
||||||
is_classdef:=false;
|
is_classdef:=false;
|
||||||
hadgeneric:=false;
|
hadgeneric:=false;
|
||||||
end;
|
end;
|
||||||
|
_LECKKLAMMER:
|
||||||
|
begin
|
||||||
|
if m_prefixed_attributes in current_settings.modeswitches then
|
||||||
|
parse_rttiattributes(rtti_attrs_def)
|
||||||
|
else
|
||||||
|
consume(_ID);
|
||||||
|
end;
|
||||||
_END :
|
_END :
|
||||||
begin
|
begin
|
||||||
|
if assigned(rtti_attrs_def) and (rtti_attrs_def.get_attribute_count>0) then
|
||||||
|
Message1(scan_e_unresolved_attribute,trtti_attribute(rtti_attrs_def.rtti_attributes[0]).typesym.prettyname);
|
||||||
consume(_END);
|
consume(_END);
|
||||||
break;
|
break;
|
||||||
end;
|
end;
|
||||||
|
@ -2407,6 +2407,7 @@ type
|
|||||||
cnodeutils.InsertWideInitsTablesTable;
|
cnodeutils.InsertWideInitsTablesTable;
|
||||||
cnodeutils.InsertResStrTablesTable;
|
cnodeutils.InsertResStrTablesTable;
|
||||||
cnodeutils.InsertMemorySizes;
|
cnodeutils.InsertMemorySizes;
|
||||||
|
cnodeutils.InsertRTTIUnitList;
|
||||||
|
|
||||||
{ Insert symbol to resource info }
|
{ Insert symbol to resource info }
|
||||||
cnodeutils.InsertResourceInfo(resources_used);
|
cnodeutils.InsertResourceInfo(resources_used);
|
||||||
|
@ -33,6 +33,8 @@ interface
|
|||||||
symdef,procinfo,optdfa;
|
symdef,procinfo,optdfa;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
tcggetcodeblockfunc = function(pd: tprocdef) : tnode;
|
||||||
|
|
||||||
tcgprocinfo = class(tprocinfo)
|
tcgprocinfo = class(tprocinfo)
|
||||||
private
|
private
|
||||||
procedure CreateInlineInfo;
|
procedure CreateInlineInfo;
|
||||||
@ -64,7 +66,7 @@ interface
|
|||||||
procedure resetprocdef;
|
procedure resetprocdef;
|
||||||
procedure add_to_symtablestack;
|
procedure add_to_symtablestack;
|
||||||
procedure remove_from_symtablestack;
|
procedure remove_from_symtablestack;
|
||||||
procedure parse_body;
|
procedure parse_body(get_code_block_func: tcggetcodeblockfunc=nil);
|
||||||
|
|
||||||
function has_assembler_child : boolean;
|
function has_assembler_child : boolean;
|
||||||
procedure set_eh_info; override;
|
procedure set_eh_info; override;
|
||||||
@ -89,7 +91,7 @@ interface
|
|||||||
{ reads any routine in the implementation, or a non-method routine
|
{ reads any routine in the implementation, or a non-method routine
|
||||||
declaration in the interface (depending on whether or not parse_only is
|
declaration in the interface (depending on whether or not parse_only is
|
||||||
true) }
|
true) }
|
||||||
procedure read_proc(isclassmethod:boolean; usefwpd: tprocdef;isgeneric:boolean);
|
procedure read_proc(isclassmethod:boolean; usefwpd: tprocdef; isgeneric:boolean; get_code_block_func: tcggetcodeblockfunc = nil);
|
||||||
|
|
||||||
{ parses only the body of a non nested routine; needs a correctly setup pd }
|
{ parses only the body of a non nested routine; needs a correctly setup pd }
|
||||||
procedure read_proc_body(pd:tprocdef);
|
procedure read_proc_body(pd:tprocdef);
|
||||||
@ -325,10 +327,44 @@ implementation
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure init_main_block_syms(block: tnode);
|
||||||
|
var
|
||||||
|
oldfilepos: tfileposinfo;
|
||||||
|
begin
|
||||||
|
{ initialized variables }
|
||||||
|
if current_procinfo.procdef.localst.symtabletype=localsymtable then
|
||||||
|
begin
|
||||||
|
{ initialization of local variables with their initial
|
||||||
|
values: part of function entry }
|
||||||
|
oldfilepos:=current_filepos;
|
||||||
|
current_filepos:=current_procinfo.entrypos;
|
||||||
|
current_procinfo.procdef.localst.SymList.ForEachCall(@initializevars,block);
|
||||||
|
current_filepos:=oldfilepos;
|
||||||
|
end
|
||||||
|
else if current_procinfo.procdef.localst.symtabletype=staticsymtable then
|
||||||
|
begin
|
||||||
|
{ for program and unit initialization code we also need to
|
||||||
|
initialize the local variables used of Default() }
|
||||||
|
oldfilepos:=current_filepos;
|
||||||
|
current_filepos:=current_procinfo.entrypos;
|
||||||
|
current_procinfo.procdef.localst.SymList.ForEachCall(@initializedefaultvars,block);
|
||||||
|
current_filepos:=oldfilepos;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if assigned(current_procinfo.procdef.parentfpstruct) then
|
||||||
|
begin
|
||||||
|
{ we only do this after the code has been parsed because
|
||||||
|
otherwise for-loop counters moved to the struct cause
|
||||||
|
errors; we still do it nevertheless to prevent false
|
||||||
|
"unused" symbols warnings and to assist debug info
|
||||||
|
generation }
|
||||||
|
redirect_parentfpstruct_local_syms(current_procinfo.procdef);
|
||||||
|
{ finish the parentfpstruct (add padding, ...) }
|
||||||
|
finish_parentfpstruct(current_procinfo.procdef);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function block(islibrary : boolean) : tnode;
|
function block(islibrary : boolean) : tnode;
|
||||||
var
|
|
||||||
oldfilepos: tfileposinfo;
|
|
||||||
begin
|
begin
|
||||||
{ parse const,types and vars }
|
{ parse const,types and vars }
|
||||||
read_declarations(islibrary);
|
read_declarations(islibrary);
|
||||||
@ -388,37 +424,7 @@ implementation
|
|||||||
begin
|
begin
|
||||||
{ parse routine body }
|
{ parse routine body }
|
||||||
block:=statement_block(_BEGIN);
|
block:=statement_block(_BEGIN);
|
||||||
{ initialized variables }
|
init_main_block_syms(block);
|
||||||
if current_procinfo.procdef.localst.symtabletype=localsymtable then
|
|
||||||
begin
|
|
||||||
{ initialization of local variables with their initial
|
|
||||||
values: part of function entry }
|
|
||||||
oldfilepos:=current_filepos;
|
|
||||||
current_filepos:=current_procinfo.entrypos;
|
|
||||||
current_procinfo.procdef.localst.SymList.ForEachCall(@initializevars,block);
|
|
||||||
current_filepos:=oldfilepos;
|
|
||||||
end
|
|
||||||
else if current_procinfo.procdef.localst.symtabletype=staticsymtable then
|
|
||||||
begin
|
|
||||||
{ for program and unit initialization code we also need to
|
|
||||||
initialize the local variables used of Default() }
|
|
||||||
oldfilepos:=current_filepos;
|
|
||||||
current_filepos:=current_procinfo.entrypos;
|
|
||||||
current_procinfo.procdef.localst.SymList.ForEachCall(@initializedefaultvars,block);
|
|
||||||
current_filepos:=oldfilepos;
|
|
||||||
end;
|
|
||||||
|
|
||||||
if assigned(current_procinfo.procdef.parentfpstruct) then
|
|
||||||
begin
|
|
||||||
{ we only do this after the code has been parsed because
|
|
||||||
otherwise for-loop counters moved to the struct cause
|
|
||||||
errors; we still do it nevertheless to prevent false
|
|
||||||
"unused" symbols warnings and to assist debug info
|
|
||||||
generation }
|
|
||||||
redirect_parentfpstruct_local_syms(current_procinfo.procdef);
|
|
||||||
{ finish the parentfpstruct (add padding, ...) }
|
|
||||||
finish_parentfpstruct(current_procinfo.procdef);
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -2065,7 +2071,7 @@ implementation
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure tcgprocinfo.parse_body;
|
procedure tcgprocinfo.parse_body(get_code_block_func: tcggetcodeblockfunc);
|
||||||
var
|
var
|
||||||
old_current_procinfo : tprocinfo;
|
old_current_procinfo : tprocinfo;
|
||||||
old_block_type : tblock_type;
|
old_block_type : tblock_type;
|
||||||
@ -2149,8 +2155,17 @@ implementation
|
|||||||
current_scanner.startrecordtokens(procdef.generictokenbuf);
|
current_scanner.startrecordtokens(procdef.generictokenbuf);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ parse the code ... }
|
if assigned(get_code_block_func) then
|
||||||
code:=block(current_module.islibrary);
|
begin
|
||||||
|
{ generate the code-nodes }
|
||||||
|
code:=get_code_block_func(procdef);
|
||||||
|
init_main_block_syms(code);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
{ parse the code ... }
|
||||||
|
code:=block(current_module.islibrary);
|
||||||
|
end;
|
||||||
|
|
||||||
if recordtokens then
|
if recordtokens then
|
||||||
begin
|
begin
|
||||||
@ -2262,7 +2277,7 @@ implementation
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure read_proc_body(old_current_procinfo:tprocinfo;pd:tprocdef);
|
procedure read_proc_body(old_current_procinfo:tprocinfo;pd:tprocdef;get_code_block_func: tcggetcodeblockfunc=nil);
|
||||||
{
|
{
|
||||||
Parses the procedure directives, then parses the procedure body, then
|
Parses the procedure directives, then parses the procedure body, then
|
||||||
generates the code for it
|
generates the code for it
|
||||||
@ -2308,7 +2323,7 @@ implementation
|
|||||||
tokeninfo^[_FAIL].keyword:=alllanguagemodes;
|
tokeninfo^[_FAIL].keyword:=alllanguagemodes;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
tcgprocinfo(current_procinfo).parse_body;
|
tcgprocinfo(current_procinfo).parse_body(get_code_block_func);
|
||||||
|
|
||||||
{ reset _FAIL as _SELF normal }
|
{ reset _FAIL as _SELF normal }
|
||||||
if (pd.proctypeoption=potype_constructor) then
|
if (pd.proctypeoption=potype_constructor) then
|
||||||
@ -2344,7 +2359,7 @@ implementation
|
|||||||
assigned(current_procinfo.procdef.owner) and
|
assigned(current_procinfo.procdef.owner) and
|
||||||
(current_procinfo.procdef.owner.defowner=current_procinfo.procdef.struct)
|
(current_procinfo.procdef.owner.defowner=current_procinfo.procdef.struct)
|
||||||
)
|
)
|
||||||
) then
|
) and not(assigned(get_code_block_func)) then
|
||||||
consume(_SEMICOLON);
|
consume(_SEMICOLON);
|
||||||
|
|
||||||
if not isnestedproc then
|
if not isnestedproc then
|
||||||
@ -2368,7 +2383,7 @@ implementation
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure read_proc(isclassmethod:boolean; usefwpd: tprocdef;isgeneric:boolean);
|
procedure read_proc(isclassmethod:boolean; usefwpd: tprocdef; isgeneric:boolean; get_code_block_func: tcggetcodeblockfunc);
|
||||||
{
|
{
|
||||||
Parses the procedure directives, then parses the procedure body, then
|
Parses the procedure directives, then parses the procedure body, then
|
||||||
generates the code for it
|
generates the code for it
|
||||||
@ -2527,7 +2542,7 @@ implementation
|
|||||||
{ compile procedure when a body is needed }
|
{ compile procedure when a body is needed }
|
||||||
if (pd_body in pdflags) then
|
if (pd_body in pdflags) then
|
||||||
begin
|
begin
|
||||||
read_proc_body(old_current_procinfo,pd);
|
read_proc_body(old_current_procinfo,pd, get_code_block_func);
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
|
@ -677,6 +677,7 @@ implementation
|
|||||||
hadgeneric,
|
hadgeneric,
|
||||||
fields_allowed, is_classdef, classfields, threadvarfields: boolean;
|
fields_allowed, is_classdef, classfields, threadvarfields: boolean;
|
||||||
vdoptions: tvar_dec_options;
|
vdoptions: tvar_dec_options;
|
||||||
|
rtti_attrs_def: trtti_attributesdef;
|
||||||
begin
|
begin
|
||||||
{ empty record declaration ? }
|
{ empty record declaration ? }
|
||||||
if (token=_SEMICOLON) then
|
if (token=_SEMICOLON) then
|
||||||
@ -697,6 +698,7 @@ implementation
|
|||||||
classfields:=false;
|
classfields:=false;
|
||||||
threadvarfields:=false;
|
threadvarfields:=false;
|
||||||
member_blocktype:=bt_general;
|
member_blocktype:=bt_general;
|
||||||
|
rtti_attrs_def := nil;
|
||||||
repeat
|
repeat
|
||||||
case token of
|
case token of
|
||||||
_TYPE :
|
_TYPE :
|
||||||
@ -857,7 +859,7 @@ implementation
|
|||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
else if member_blocktype=bt_type then
|
else if member_blocktype=bt_type then
|
||||||
types_dec(true,hadgeneric)
|
types_dec(true,hadgeneric, rtti_attrs_def)
|
||||||
else if member_blocktype=bt_const then
|
else if member_blocktype=bt_const then
|
||||||
consts_dec(true,true,hadgeneric)
|
consts_dec(true,true,hadgeneric)
|
||||||
else
|
else
|
||||||
@ -869,7 +871,7 @@ implementation
|
|||||||
begin
|
begin
|
||||||
if IsAnonOrLocal then
|
if IsAnonOrLocal then
|
||||||
Message(parser_e_no_properties_in_local_anonymous_records);
|
Message(parser_e_no_properties_in_local_anonymous_records);
|
||||||
struct_property_dec(is_classdef);
|
struct_property_dec(is_classdef, rtti_attrs_def);
|
||||||
fields_allowed:=false;
|
fields_allowed:=false;
|
||||||
is_classdef:=false;
|
is_classdef:=false;
|
||||||
end;
|
end;
|
||||||
|
@ -465,7 +465,8 @@ type
|
|||||||
tsk_field_setter, // Setter for a field (callthrough property is passed in skpara)
|
tsk_field_setter, // Setter for a field (callthrough property is passed in skpara)
|
||||||
tsk_block_invoke_procvar, // Call a procvar to invoke inside a block
|
tsk_block_invoke_procvar, // Call a procvar to invoke inside a block
|
||||||
tsk_interface_wrapper, // Call through to a method from an interface wrapper
|
tsk_interface_wrapper, // Call through to a method from an interface wrapper
|
||||||
tsk_call_no_parameters // Call skpara procedure without passing any parameters nor returning a result
|
tsk_call_no_parameters, // Call skpara procedure without passing any parameters nor returning a result
|
||||||
|
tsk_get_rttiattribute // Create and return a TCustomAttribute instance
|
||||||
);
|
);
|
||||||
|
|
||||||
{ synthetic procdef supplementary information (tprocdef.skpara) }
|
{ synthetic procdef supplementary information (tprocdef.skpara) }
|
||||||
|
@ -1024,6 +1024,33 @@ implementation
|
|||||||
setverbosity('W+');
|
setverbosity('W+');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function get_attribute_code_block(pd: tprocdef) : tnode;
|
||||||
|
var
|
||||||
|
attribute: trtti_attribute;
|
||||||
|
load: tloadnode;
|
||||||
|
statement: tstatementnode;
|
||||||
|
assignment: tassignmentnode;
|
||||||
|
begin
|
||||||
|
attribute:=trtti_attribute(pd.skpara);
|
||||||
|
|
||||||
|
load := cloadnode.create(pd.funcretsym,pd.funcretsym.Owner);
|
||||||
|
assignment := cassignmentnode.create(load,Attribute.constructorcall);
|
||||||
|
assignment.resultdef := voidtype;
|
||||||
|
|
||||||
|
statement := cstatementnode.Create(assignment,nil);
|
||||||
|
result := cblocknode.create(statement);
|
||||||
|
result.resultdef := voidtype;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure implement_get_attribute(pd: tprocdef);
|
||||||
|
var
|
||||||
|
old_parse_only: boolean;
|
||||||
|
begin
|
||||||
|
old_parse_only:=parse_only;
|
||||||
|
parse_only:=false;
|
||||||
|
read_proc(po_classmethod in pd.procoptions,pd,false,@get_attribute_code_block);
|
||||||
|
parse_only:=old_parse_only;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure add_synthetic_method_implementations_for_st(st: tsymtable);
|
procedure add_synthetic_method_implementations_for_st(st: tsymtable);
|
||||||
var
|
var
|
||||||
@ -1115,6 +1142,8 @@ implementation
|
|||||||
implement_interface_wrapper(pd);
|
implement_interface_wrapper(pd);
|
||||||
tsk_call_no_parameters:
|
tsk_call_no_parameters:
|
||||||
implement_call_no_parameters(pd);
|
implement_call_no_parameters(pd);
|
||||||
|
tsk_get_rttiattribute:
|
||||||
|
implement_get_attribute(pd);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
@ -392,6 +392,21 @@ interface
|
|||||||
end;
|
end;
|
||||||
pvmtentry = ^tvmtentry;
|
pvmtentry = ^tvmtentry;
|
||||||
|
|
||||||
|
{ trtti_attributesdef }
|
||||||
|
|
||||||
|
trtti_attribute = class
|
||||||
|
typesym : tsym;
|
||||||
|
constructorcall : tnode;
|
||||||
|
symbolname : string;
|
||||||
|
end;
|
||||||
|
|
||||||
|
trtti_attributesdef = class
|
||||||
|
rtti_attributes : TFPObjectList;
|
||||||
|
procedure addattribute(atypesym: tsym; constructorcall: tnode);
|
||||||
|
destructor destroy; override;
|
||||||
|
function get_attribute_count: longint;
|
||||||
|
end;
|
||||||
|
|
||||||
{ tobjectdef }
|
{ tobjectdef }
|
||||||
|
|
||||||
tvmcallstatic = (vmcs_default, vmcs_yes, vmcs_no, vmcs_unreachable);
|
tvmcallstatic = (vmcs_default, vmcs_yes, vmcs_no, vmcs_unreachable);
|
||||||
@ -438,6 +453,7 @@ interface
|
|||||||
}
|
}
|
||||||
classref_created_in_current_module : boolean;
|
classref_created_in_current_module : boolean;
|
||||||
objecttype : tobjecttyp;
|
objecttype : tobjecttyp;
|
||||||
|
rtti_attributesdef : trtti_attributesdef;
|
||||||
constructor create(ot:tobjecttyp;const n:string;c:tobjectdef;doregister:boolean);virtual;
|
constructor create(ot:tobjecttyp;const n:string;c:tobjectdef;doregister:boolean);virtual;
|
||||||
constructor ppuload(ppufile:tcompilerppufile);
|
constructor ppuload(ppufile:tcompilerppufile);
|
||||||
destructor destroy;override;
|
destructor destroy;override;
|
||||||
@ -2867,6 +2883,36 @@ implementation
|
|||||||
GetTypeName:='<enumeration type>';
|
GetTypeName:='<enumeration type>';
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{****************************************************************************
|
||||||
|
TRTTI_ATTRIBUTESDEF
|
||||||
|
****************************************************************************}
|
||||||
|
|
||||||
|
procedure trtti_attributesdef.addattribute(atypesym: tsym; constructorcall: tnode);
|
||||||
|
var
|
||||||
|
newattribute: trtti_attribute;
|
||||||
|
begin
|
||||||
|
if not assigned(rtti_attributes) then
|
||||||
|
rtti_attributes := TFPObjectList.Create(True);
|
||||||
|
newattribute := trtti_attribute.Create;
|
||||||
|
newattribute.typesym := atypesym;
|
||||||
|
newattribute.constructorcall:=constructorcall;
|
||||||
|
rtti_attributes.Add(newattribute);
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor trtti_attributesdef.destroy;
|
||||||
|
begin
|
||||||
|
rtti_attributes.Free;
|
||||||
|
inherited destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function trtti_attributesdef.get_attribute_count: longint;
|
||||||
|
begin
|
||||||
|
if assigned(rtti_attributes) then
|
||||||
|
result := rtti_attributes.Count
|
||||||
|
else
|
||||||
|
result := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{****************************************************************************
|
{****************************************************************************
|
||||||
TORDDEF
|
TORDDEF
|
||||||
@ -6979,6 +7025,11 @@ implementation
|
|||||||
freemem(vmcallstaticinfo);
|
freemem(vmcallstaticinfo);
|
||||||
vmcallstaticinfo:=nil;
|
vmcallstaticinfo:=nil;
|
||||||
end;
|
end;
|
||||||
|
if assigned(rtti_attributesdef) then
|
||||||
|
begin
|
||||||
|
rtti_attributesdef.Free;
|
||||||
|
rtti_attributesdef:=nil;
|
||||||
|
end;
|
||||||
inherited destroy;
|
inherited destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -352,6 +352,7 @@ interface
|
|||||||
dispid : longint;
|
dispid : longint;
|
||||||
propaccesslist: array[tpropaccesslisttypes] of tpropaccesslist;
|
propaccesslist: array[tpropaccesslisttypes] of tpropaccesslist;
|
||||||
parast : tsymtable;
|
parast : tsymtable;
|
||||||
|
rtti_attributesdef : trtti_attributesdef;
|
||||||
constructor create(const n : string);virtual;
|
constructor create(const n : string);virtual;
|
||||||
destructor destroy;override;
|
destructor destroy;override;
|
||||||
constructor ppuload(ppufile:tcompilerppufile);
|
constructor ppuload(ppufile:tcompilerppufile);
|
||||||
@ -1375,6 +1376,7 @@ implementation
|
|||||||
for pap:=low(tpropaccesslisttypes) to high(tpropaccesslisttypes) do
|
for pap:=low(tpropaccesslisttypes) to high(tpropaccesslisttypes) do
|
||||||
propaccesslist[pap].free;
|
propaccesslist[pap].free;
|
||||||
parast.free;
|
parast.free;
|
||||||
|
rtti_attributesdef.free;
|
||||||
inherited destroy;
|
inherited destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -955,10 +955,12 @@ implementation
|
|||||||
if (vo_is_funcret in tabstractvarsym(sym).varoptions) then
|
if (vo_is_funcret in tabstractvarsym(sym).varoptions) then
|
||||||
begin
|
begin
|
||||||
{ don't warn about the result of constructors }
|
{ don't warn about the result of constructors }
|
||||||
|
{ or the synthetic helper functions for class-attributes }
|
||||||
if ((tsym(sym).owner.symtabletype<>localsymtable) or
|
if ((tsym(sym).owner.symtabletype<>localsymtable) or
|
||||||
(tprocdef(tsym(sym).owner.defowner).proctypeoption<>potype_constructor)) and
|
(tprocdef(tsym(sym).owner.defowner).proctypeoption<>potype_constructor)) and
|
||||||
not (po_noreturn in tprocdef(tsym(sym).owner.defowner).procoptions) and
|
not (po_noreturn in tprocdef(tsym(sym).owner.defowner).procoptions) and
|
||||||
not(cs_opt_nodedfa in current_settings.optimizerswitches) then
|
not(cs_opt_nodedfa in current_settings.optimizerswitches) and
|
||||||
|
(tprocdef(tsym(sym).owner.defowner).synthetickind <> tsk_get_rttiattribute) then
|
||||||
MessagePos(tsym(sym).fileinfo,sym_w_function_result_not_set)
|
MessagePos(tsym(sym).fileinfo,sym_w_function_result_not_set)
|
||||||
end
|
end
|
||||||
else if (tsym(sym).owner.symtabletype=parasymtable) then
|
else if (tsym(sym).owner.symtabletype=parasymtable) then
|
||||||
|
@ -191,6 +191,7 @@ type
|
|||||||
protected
|
protected
|
||||||
function GetHandle: Pointer; virtual; abstract;
|
function GetHandle: Pointer; virtual; abstract;
|
||||||
public
|
public
|
||||||
|
function GetAttributes: specialize TArray<TCustomAttribute>; virtual; abstract;
|
||||||
property Handle: Pointer read GetHandle;
|
property Handle: Pointer read GetHandle;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -208,6 +209,8 @@ type
|
|||||||
TRttiType = class(TRttiNamedObject)
|
TRttiType = class(TRttiNamedObject)
|
||||||
private
|
private
|
||||||
FTypeInfo: PTypeInfo;
|
FTypeInfo: PTypeInfo;
|
||||||
|
FAttributesResolved: boolean;
|
||||||
|
FAttributes: specialize TArray<TCustomAttribute>;
|
||||||
FMethods: specialize TArray<TRttiMethod>;
|
FMethods: specialize TArray<TRttiMethod>;
|
||||||
function GetAsInstance: TRttiInstanceType;
|
function GetAsInstance: TRttiInstanceType;
|
||||||
protected
|
protected
|
||||||
@ -224,6 +227,7 @@ type
|
|||||||
function GetBaseType: TRttiType; virtual;
|
function GetBaseType: TRttiType; virtual;
|
||||||
public
|
public
|
||||||
constructor Create(ATypeInfo : PTypeInfo);
|
constructor Create(ATypeInfo : PTypeInfo);
|
||||||
|
function GetAttributes: specialize TArray<TCustomAttribute>; override;
|
||||||
function GetProperties: specialize TArray<TRttiProperty>; virtual;
|
function GetProperties: specialize TArray<TRttiProperty>; virtual;
|
||||||
function GetProperty(const AName: string): TRttiProperty; virtual;
|
function GetProperty(const AName: string): TRttiProperty; virtual;
|
||||||
function GetMethods: specialize TArray<TRttiMethod>; virtual;
|
function GetMethods: specialize TArray<TRttiMethod>; virtual;
|
||||||
@ -288,6 +292,8 @@ type
|
|||||||
TRttiProperty = class(TRttiMember)
|
TRttiProperty = class(TRttiMember)
|
||||||
private
|
private
|
||||||
FPropInfo: PPropInfo;
|
FPropInfo: PPropInfo;
|
||||||
|
FAttributesResolved: boolean;
|
||||||
|
FAttributes: specialize TArray<TCustomAttribute>;
|
||||||
function GetPropertyType: TRttiType;
|
function GetPropertyType: TRttiType;
|
||||||
function GetIsWritable: boolean;
|
function GetIsWritable: boolean;
|
||||||
function GetIsReadable: boolean;
|
function GetIsReadable: boolean;
|
||||||
@ -297,6 +303,7 @@ type
|
|||||||
function GetHandle: Pointer; override;
|
function GetHandle: Pointer; override;
|
||||||
public
|
public
|
||||||
constructor Create(AParent: TRttiType; APropInfo: PPropInfo);
|
constructor Create(AParent: TRttiType; APropInfo: PPropInfo);
|
||||||
|
function GetAttributes: specialize TArray<TCustomAttribute>; override;
|
||||||
function GetValue(Instance: pointer): TValue;
|
function GetValue(Instance: pointer): TValue;
|
||||||
procedure SetValue(Instance: pointer; const AValue: TValue);
|
procedure SetValue(Instance: pointer; const AValue: TValue);
|
||||||
property PropertyType: TRttiType read GetPropertyType;
|
property PropertyType: TRttiType read GetPropertyType;
|
||||||
@ -3388,6 +3395,22 @@ begin
|
|||||||
FPropInfo := APropInfo;
|
FPropInfo := APropInfo;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TRttiProperty.GetAttributes: specialize TArray<TCustomAttribute>;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
if not FAttributesResolved then
|
||||||
|
begin
|
||||||
|
setlength(FAttributes,FPropInfo^.AttributeCount);
|
||||||
|
for i := 0 to FPropInfo^.AttributeCount-1 do
|
||||||
|
begin
|
||||||
|
FAttributes[i]:=TCustomAttribute(GetPropAttribute(FPropInfo,i));
|
||||||
|
end;
|
||||||
|
FAttributesResolved:=true;
|
||||||
|
end;
|
||||||
|
result := FAttributes;
|
||||||
|
end;
|
||||||
|
|
||||||
function TRttiProperty.GetValue(Instance: pointer): TValue;
|
function TRttiProperty.GetValue(Instance: pointer): TValue;
|
||||||
|
|
||||||
procedure ValueFromBool(value: Int64);
|
procedure ValueFromBool(value: Int64);
|
||||||
@ -3600,6 +3623,22 @@ begin
|
|||||||
FTypeData:=GetTypeData(ATypeInfo);
|
FTypeData:=GetTypeData(ATypeInfo);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TRttiType.GetAttributes: specialize TArray<TCustomAttribute>;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
ad: PAttributeData;
|
||||||
|
begin
|
||||||
|
if not FAttributesResolved then
|
||||||
|
begin
|
||||||
|
ad := GetAttributeData(FTypeInfo);
|
||||||
|
setlength(FAttributes,ad^.AttributeCount);
|
||||||
|
for i := 0 to ad^.AttributeCount-1 do
|
||||||
|
FAttributes[i]:=GetAttribute(ad,i);
|
||||||
|
FAttributesResolved:=true;
|
||||||
|
end;
|
||||||
|
result := FAttributes;
|
||||||
|
end;
|
||||||
|
|
||||||
function TRttiType.GetProperties: specialize TArray<TRttiProperty>;
|
function TRttiType.GetProperties: specialize TArray<TRttiProperty>;
|
||||||
begin
|
begin
|
||||||
Result := Nil;
|
Result := Nil;
|
||||||
|
@ -979,11 +979,15 @@
|
|||||||
class function TObject.UnitName : {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}ansistring{$else FPC_HAS_FEATURE_ANSISTRINGS}shortstring{$endif FPC_HAS_FEATURE_ANSISTRINGS};
|
class function TObject.UnitName : {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}ansistring{$else FPC_HAS_FEATURE_ANSISTRINGS}shortstring{$endif FPC_HAS_FEATURE_ANSISTRINGS};
|
||||||
type
|
type
|
||||||
// from the typinfo unit
|
// from the typinfo unit
|
||||||
|
TUnitInfo = packed record
|
||||||
|
UnitOptions: byte;
|
||||||
|
UnitName: shortstring;
|
||||||
|
end;
|
||||||
TClassTypeInfo = {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
|
TClassTypeInfo = {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
|
||||||
ClassType: TClass;
|
ClassType: TClass;
|
||||||
ParentInfo: Pointer;
|
ParentInfo: Pointer;
|
||||||
PropCount: SmallInt;
|
PropCount: SmallInt;
|
||||||
UnitName: ShortString;
|
UnitInfo: ^TUnitInfo;
|
||||||
end;
|
end;
|
||||||
PClassTypeInfo = ^TClassTypeInfo;
|
PClassTypeInfo = ^TClassTypeInfo;
|
||||||
var
|
var
|
||||||
@ -997,7 +1001,7 @@
|
|||||||
{$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
|
{$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
|
||||||
classtypeinfo:=aligntoqword(classtypeinfo);
|
classtypeinfo:=aligntoqword(classtypeinfo);
|
||||||
{$endif}
|
{$endif}
|
||||||
result:=classtypeinfo^.UnitName;
|
result:=classtypeinfo^.UnitInfo^.UnitName;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
result:='';
|
result:='';
|
||||||
|
@ -428,6 +428,9 @@
|
|||||||
{$endif FPC_USE_PSABIEH}
|
{$endif FPC_USE_PSABIEH}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
TCustomAttribute = class(TObject)
|
||||||
|
end;
|
||||||
|
|
||||||
Const
|
Const
|
||||||
ExceptProc : TExceptProc = Nil;
|
ExceptProc : TExceptProc = Nil;
|
||||||
RaiseProc : TExceptProc = Nil;
|
RaiseProc : TExceptProc = Nil;
|
||||||
|
@ -226,7 +226,16 @@ unit TypInfo;
|
|||||||
property Field[aIndex: Word]: PVmtFieldEntry read GetField;
|
property Field[aIndex: Word]: PVmtFieldEntry read GetField;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
TRTTIUnitOption = (rmoHasAttributes);
|
||||||
|
TRTTIUnitOptions = set of TRTTIUnitOption;
|
||||||
|
|
||||||
{$PACKRECORDS 1}
|
{$PACKRECORDS 1}
|
||||||
|
PUnitInfo = ^TUnitInfo;
|
||||||
|
TUnitInfo = packed record
|
||||||
|
UnitOptions: TRTTIUnitOptions;
|
||||||
|
UnitName: shortstring;
|
||||||
|
end;
|
||||||
|
|
||||||
TTypeInfo = record
|
TTypeInfo = record
|
||||||
Kind : TTypeKind;
|
Kind : TTypeKind;
|
||||||
Name : ShortString;
|
Name : ShortString;
|
||||||
@ -562,6 +571,7 @@ unit TypInfo;
|
|||||||
{ tkPointer }
|
{ tkPointer }
|
||||||
property RefType: PTypeInfo read GetRefType;
|
property RefType: PTypeInfo read GetRefType;
|
||||||
public
|
public
|
||||||
|
function UnitName: string;
|
||||||
case TTypeKind of
|
case TTypeKind of
|
||||||
tkUnKnown,tkLString,tkWString,tkVariant,tkUString:
|
tkUnKnown,tkLString,tkWString,tkVariant,tkUString:
|
||||||
();
|
();
|
||||||
@ -608,7 +618,8 @@ unit TypInfo;
|
|||||||
(ClassType : TClass;
|
(ClassType : TClass;
|
||||||
ParentInfoRef : TypeInfoPtr;
|
ParentInfoRef : TypeInfoPtr;
|
||||||
PropCount : SmallInt;
|
PropCount : SmallInt;
|
||||||
UnitName : ShortString
|
UnitInfo : PUnitInfo
|
||||||
|
// AttributeData: TAttributeData;
|
||||||
// here the properties follow as array of TPropInfo
|
// here the properties follow as array of TPropInfo
|
||||||
);
|
);
|
||||||
tkRecord:
|
tkRecord:
|
||||||
@ -726,6 +737,7 @@ unit TypInfo;
|
|||||||
// 6 : true, constant index property
|
// 6 : true, constant index property
|
||||||
PropProcs : Byte;
|
PropProcs : Byte;
|
||||||
|
|
||||||
|
AttributeCount : Byte;
|
||||||
Name : ShortString;
|
Name : ShortString;
|
||||||
property PropType: PTypeInfo read GetPropType;
|
property PropType: PTypeInfo read GetPropType;
|
||||||
property Tail: Pointer read GetTail;
|
property Tail: Pointer read GetTail;
|
||||||
@ -734,9 +746,25 @@ unit TypInfo;
|
|||||||
|
|
||||||
TProcInfoProc = Procedure(PropInfo : PPropInfo) of object;
|
TProcInfoProc = Procedure(PropInfo : PPropInfo) of object;
|
||||||
|
|
||||||
|
TAttributeProc = function : TCustomAttribute;
|
||||||
|
PAttributeProcList = ^TAttributeProcList;
|
||||||
|
TAttributeProcList = array[0..$ffff] of TAttributeProc;
|
||||||
|
|
||||||
PPropList = ^TPropList;
|
PPropList = ^TPropList;
|
||||||
TPropList = array[0..{$ifdef cpu16}(32768 div sizeof(PPropInfo))-2{$else}65535{$endif}] of PPropInfo;
|
TPropList = array[0..{$ifdef cpu16}(32768 div sizeof(PPropInfo))-2{$else}65535{$endif}] of PPropInfo;
|
||||||
|
|
||||||
|
TAttributeData = record
|
||||||
|
AttributeCount: word;
|
||||||
|
AttributesList: TAttributeProcList;
|
||||||
|
end;
|
||||||
|
PAttributeData = ^TAttributeData;
|
||||||
|
|
||||||
|
PUnitInfoList = ^TUnitInfoList;
|
||||||
|
TUnitInfoList = record
|
||||||
|
UnitCount: IntPtr;
|
||||||
|
Units: array[0..65535] of PUnitInfo;
|
||||||
|
end;
|
||||||
|
|
||||||
const
|
const
|
||||||
tkString = tkSString;
|
tkString = tkSString;
|
||||||
tkProcedure = tkProcVar; // for compatibility with Delphi
|
tkProcedure = tkProcVar; // for compatibility with Delphi
|
||||||
@ -873,6 +901,18 @@ function GetDynArrayProp(Instance: TObject; PropInfo: PPropInfo): Pointer;
|
|||||||
procedure SetDynArrayProp(Instance: TObject; const PropName: string; const Value: Pointer);
|
procedure SetDynArrayProp(Instance: TObject; const PropName: string; const Value: Pointer);
|
||||||
procedure SetDynArrayProp(Instance: TObject; PropInfo: PPropInfo; const Value: Pointer);
|
procedure SetDynArrayProp(Instance: TObject; PropInfo: PPropInfo; const Value: Pointer);
|
||||||
|
|
||||||
|
// Extended RTTI
|
||||||
|
function GetUnitList: PUnitInfoList;
|
||||||
|
function GetFirstTypeinfoFromUnit(AUnitInfo: PUnitInfo): PTypeInfo;
|
||||||
|
function GetNextTypeInfo(ATypeInfo: PTypeInfo): PTypeInfo;
|
||||||
|
|
||||||
|
function GetAttributeData(TypeInfo: PTypeInfo): PAttributeData;
|
||||||
|
|
||||||
|
function GetPropAttributeProclist(PropInfo: PPropInfo): PAttributeProcList;
|
||||||
|
function GetPropAttribute(PropInfo: PPropInfo; AttributeNr: byte): TObject;
|
||||||
|
|
||||||
|
function GetAttribute(AttributeData: PAttributeData; AttributeNr: byte): TCustomAttribute;
|
||||||
|
|
||||||
// Auxiliary routines, which may be useful
|
// Auxiliary routines, which may be useful
|
||||||
Function GetEnumName(TypeInfo : PTypeInfo;Value : Integer) : string;
|
Function GetEnumName(TypeInfo : PTypeInfo;Value : Integer) : string;
|
||||||
Function GetEnumValue(TypeInfo : PTypeInfo;const Name : string) : Integer;
|
Function GetEnumValue(TypeInfo : PTypeInfo;const Name : string) : Integer;
|
||||||
@ -920,6 +960,15 @@ uses rtlconsts;
|
|||||||
type
|
type
|
||||||
PMethod = ^TMethod;
|
PMethod = ^TMethod;
|
||||||
|
|
||||||
|
{ ---------------------------------------------------------------------
|
||||||
|
TTypeData methods
|
||||||
|
---------------------------------------------------------------------}
|
||||||
|
|
||||||
|
function TTypeData.UnitName: string;
|
||||||
|
begin
|
||||||
|
Result := UnitInfo^.UnitName
|
||||||
|
end;
|
||||||
|
|
||||||
{ ---------------------------------------------------------------------
|
{ ---------------------------------------------------------------------
|
||||||
Auxiliary methods
|
Auxiliary methods
|
||||||
---------------------------------------------------------------------}
|
---------------------------------------------------------------------}
|
||||||
@ -950,6 +999,187 @@ begin
|
|||||||
{$endif}
|
{$endif}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{$ifdef FPC_HAS_UNIT_RTTI}
|
||||||
|
var
|
||||||
|
UnitList: TUnitInfoList; external name 'RTTIUNITLIST';
|
||||||
|
{$endif FPC_HAS_UNIT_RTTI}
|
||||||
|
|
||||||
|
function GetUnitList: PUnitInfoList;
|
||||||
|
begin
|
||||||
|
{$ifdef FPC_HAS_UNIT_RTTI}
|
||||||
|
result := @UnitList;
|
||||||
|
{$else FPC_HAS_UNIT_RTTI}
|
||||||
|
result := nil;
|
||||||
|
{$endif FPC_HAS_UNIT_RTTI}
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetAttributeData(TypeInfo: PTypeInfo): PAttributeData;
|
||||||
|
var
|
||||||
|
TD: PTypeData;
|
||||||
|
begin
|
||||||
|
if TypeInfo^.Kind<>tkClass then
|
||||||
|
result := nil
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
TD := GetTypeData(TypeInfo);
|
||||||
|
if (rmoHasAttributes in td^.UnitInfo^.UnitOptions) then
|
||||||
|
Result:=PAttributeData(aligntoptr(pointer(@TD^.UnitInfo)+sizeof(TD^.UnitInfo)))
|
||||||
|
else
|
||||||
|
result := nil;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetPropData(TypeInfo : PTypeInfo; TypeData: PTypeData) : PPropData;
|
||||||
|
var
|
||||||
|
AD: PAttributeData;
|
||||||
|
begin
|
||||||
|
if rmoHasAttributes in TypeData^.UnitInfo^.UnitOptions then
|
||||||
|
begin
|
||||||
|
AD := GetAttributeData(TypeInfo);
|
||||||
|
result := PPropData(pointer(AD)+SizeOf(AD^.AttributeCount)+(AD^.AttributeCount*SizeOf(TAttributeProc)));
|
||||||
|
end
|
||||||
|
else
|
||||||
|
result := aligntoptr(pointer(@TypeData^.UnitInfo)+sizeof(TypeData^.UnitInfo));
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetFirstTypeinfoFromUnit(AUnitInfo: PUnitInfo): PTypeInfo;
|
||||||
|
begin
|
||||||
|
result := align(pointer(@AUnitInfo^.UnitName)+1+byte(AUnitInfo^.UnitName[0]), sizeof(Pointer));
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetNextTypeInfo(ATypeInfo: PTypeInfo): PTypeInfo;
|
||||||
|
type
|
||||||
|
TEnumTableMode=(lookup,search);
|
||||||
|
var
|
||||||
|
p: pointer;
|
||||||
|
td: PTypeData;
|
||||||
|
pd: ppropdata;
|
||||||
|
i: longint;
|
||||||
|
fc: longint;
|
||||||
|
minv,maxv: longint;
|
||||||
|
EnumTableMode: TEnumTableMode;
|
||||||
|
count: pword;
|
||||||
|
begin
|
||||||
|
td := GetTypeData(ATypeInfo);
|
||||||
|
p := GetTypeData(ATypeInfo);
|
||||||
|
case ATypeInfo^.Kind of
|
||||||
|
tkEnumeration:
|
||||||
|
begin
|
||||||
|
p := aligntoptr(p + 1); { OrdType }
|
||||||
|
minv := PLongInt(p)^;
|
||||||
|
p := p + SizeOf(LongInt); { MinValue }
|
||||||
|
maxv := PLongInt(p)^;
|
||||||
|
p := p + SizeOf(LongInt); { MaxValue }
|
||||||
|
p := p + SizeOf(PTypeInfo); { basetype }
|
||||||
|
for i := minv to maxv do
|
||||||
|
p := p + 1 + pbyte(p)^; { NameList: shortstring length + length of string }
|
||||||
|
p := p + 1 + pbyte(p)^; { UnitName: shortstring length + length of string }
|
||||||
|
p := p + 1; { trailing zero }
|
||||||
|
end;
|
||||||
|
tkInteger,
|
||||||
|
tkChar,
|
||||||
|
tkWChar,
|
||||||
|
tkBool : begin
|
||||||
|
p := aligntoptr(p + 1); { OrdType }
|
||||||
|
p := p + SizeOf(LongInt) + SizeOf(LongInt); { MinValue + MaxValue }
|
||||||
|
end;
|
||||||
|
tkSet : begin
|
||||||
|
p := aligntoptr(p + 1); { OrdType }
|
||||||
|
p := p + sizeof(PTypeInfo); { CompType }
|
||||||
|
end;
|
||||||
|
tkQWord : p := p + SizeOf(QWord) + SizeOf(QWord); { MinQWordValue, MaxQWordValue }
|
||||||
|
tkInt64 : p := p + SizeOf(Int64) + SizeOf(Int64); { MinInt64Value, MaxInt64Value }
|
||||||
|
tkSString: p := P + SizeOf(Byte); { MaxLength }
|
||||||
|
tkArray : begin
|
||||||
|
p := p + sizeof(Ptrint); { Element size }
|
||||||
|
p := p + sizeof(PtrInt); { Element count }
|
||||||
|
p := p + sizeof(pointer); { Element type }
|
||||||
|
p := p + sizeof(longint); { Variant type }
|
||||||
|
end;
|
||||||
|
tkDynArray:begin
|
||||||
|
p := p + sizeof(Ptrint); { Element size }
|
||||||
|
p := p + sizeof(PtrInt); { Element type 2 }
|
||||||
|
p := p + sizeof(longint); { Variant type }
|
||||||
|
p := p + sizeof(pointer); { Element type }
|
||||||
|
p := p + 1 + pbyte(p)^; { unitname: shortstring length + length of string }
|
||||||
|
end;
|
||||||
|
tkFloat : begin
|
||||||
|
p := p + sizeof(TFloatType); { Float type }
|
||||||
|
end;
|
||||||
|
tkObject,
|
||||||
|
tkRecord : begin
|
||||||
|
p := p + 4; { Size }
|
||||||
|
fc := plongint(p)^;
|
||||||
|
p := p + 4; { Fieldcount }
|
||||||
|
p := p + (fc * (sizeof(pointer) + 4)); { Fieldcount * (element type + field offset) }
|
||||||
|
end;
|
||||||
|
tkClass : begin
|
||||||
|
pd := GetPropData(ATypeInfo,td);
|
||||||
|
p:=@pd^.PropList;
|
||||||
|
for i:=1 to pd^.PropCount do
|
||||||
|
p:=aligntoptr(pointer(@ppropinfo(p)^.Name)+byte(ppropinfo(p)^.Name[0])+(ppropinfo(p)^.AttributeCount*SizeOf(TAttributeProc))+1);
|
||||||
|
end;
|
||||||
|
tkInterface :
|
||||||
|
begin
|
||||||
|
p := aligntoptr(pointer(@td^.IntfUnit)+byte(td^.IntfUnit[0])+1);
|
||||||
|
p := p+pbyte(p)^+1; { IIDStr }
|
||||||
|
end;
|
||||||
|
tkMethod : begin
|
||||||
|
p := @td^.ParamList[0];
|
||||||
|
for i := 0 to td^.ParamCount-1 do
|
||||||
|
begin
|
||||||
|
p := aligntoptr(p + sizeof(TParamFlags)); { TParamFlags }
|
||||||
|
p := aligntoptr(p +pbyte(p)^+1); { paramname }
|
||||||
|
p := aligntoptr(p +pbyte(p)^+1); { typename }
|
||||||
|
end;
|
||||||
|
if td^.MethodKind in [mkFunction, mkClassFunction] then
|
||||||
|
begin
|
||||||
|
p := aligntoptr(p +pbyte(p)^+1); { resulttype }
|
||||||
|
p := p + sizeof(PPTypeInfo); { resulttyperef }
|
||||||
|
end;
|
||||||
|
p := aligntoptr(p + sizeof(TCallConv)); { cc }
|
||||||
|
p := p + (td^.ParamCount * sizeof(PPTypeInfo));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
result := PTypeInfo(align(p,sizeof(p)));
|
||||||
|
if PByte(result)^=255 then
|
||||||
|
result := nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetPropAttributeProclist(PropInfo: PPropInfo): PAttributeProcList;
|
||||||
|
begin
|
||||||
|
if PropInfo^.AttributeCount=0 then
|
||||||
|
result := nil
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Result:=PAttributeProcList(aligntoptr(pointer(@PropInfo^.Name)+byte(PropInfo^.Name[0])+1));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetPropAttribute(PropInfo: PPropInfo; AttributeNr: byte): TObject;
|
||||||
|
var
|
||||||
|
AttributeProcList: PAttributeProcList;
|
||||||
|
begin
|
||||||
|
if AttributeNr>=PropInfo^.AttributeCount then
|
||||||
|
result := nil
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
AttributeProcList := GetPropAttributeProclist(PropInfo);
|
||||||
|
result := AttributeProcList^[AttributeNr]();
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetAttribute(AttributeData: PAttributeData; AttributeNr: byte): TCustomAttribute;
|
||||||
|
var
|
||||||
|
AttributeProcList: TAttributeProcList;
|
||||||
|
begin
|
||||||
|
if (AttributeData=nil) or (AttributeNr>=AttributeData^.AttributeCount) then
|
||||||
|
result := nil
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
result := AttributeData^.AttributesList[AttributeNr]();
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
Function GetEnumName(TypeInfo : PTypeInfo;Value : Integer) : string;
|
Function GetEnumName(TypeInfo : PTypeInfo;Value : Integer) : string;
|
||||||
|
|
||||||
@ -1241,7 +1471,7 @@ var
|
|||||||
hp : PTypeData;
|
hp : PTypeData;
|
||||||
i : longint;
|
i : longint;
|
||||||
p : shortstring;
|
p : shortstring;
|
||||||
pd : ^TPropData;
|
pd : PPropData;
|
||||||
begin
|
begin
|
||||||
P:=PropName; // avoid Ansi<->short conversion in a loop
|
P:=PropName; // avoid Ansi<->short conversion in a loop
|
||||||
while Assigned(TypeInfo) do
|
while Assigned(TypeInfo) do
|
||||||
@ -1249,7 +1479,7 @@ begin
|
|||||||
// skip the name
|
// skip the name
|
||||||
hp:=GetTypeData(Typeinfo);
|
hp:=GetTypeData(Typeinfo);
|
||||||
// the class info rtti the property rtti follows immediatly
|
// the class info rtti the property rtti follows immediatly
|
||||||
pd:=aligntoptr(pointer(pointer(@hp^.UnitName)+Length(hp^.UnitName)+1));
|
pd := GetPropData(TypeInfo,hp);
|
||||||
Result:=PPropInfo(@pd^.PropList);
|
Result:=PPropInfo(@pd^.PropList);
|
||||||
for i:=1 to pd^.PropCount do
|
for i:=1 to pd^.PropCount do
|
||||||
begin
|
begin
|
||||||
@ -1257,7 +1487,7 @@ begin
|
|||||||
if ShortCompareText(Result^.Name, P) = 0 then
|
if ShortCompareText(Result^.Name, P) = 0 then
|
||||||
exit;
|
exit;
|
||||||
// skip to next property
|
// skip to next property
|
||||||
Result:=PPropInfo(aligntoptr(pointer(@Result^.Name)+byte(Result^.Name[0])+1));
|
Result:=PPropInfo(aligntoptr(pointer(@Result^.Name)+byte(Result^.Name[0])+(result^.AttributeCount*SizeOf(TAttributeProc))+1));
|
||||||
end;
|
end;
|
||||||
// parent class
|
// parent class
|
||||||
Typeinfo:=hp^.ParentInfo;
|
Typeinfo:=hp^.ParentInfo;
|
||||||
@ -1408,7 +1638,7 @@ begin
|
|||||||
repeat
|
repeat
|
||||||
TD:=GetTypeData(TypeInfo);
|
TD:=GetTypeData(TypeInfo);
|
||||||
// published properties count for this object
|
// published properties count for this object
|
||||||
TP:=aligntoptr(PPropInfo(aligntoptr((Pointer(@TD^.UnitName)+Length(TD^.UnitName)+1))));
|
TP:=PPropInfo(GetPropData(TypeInfo, TD));
|
||||||
Count:=PWord(TP)^;
|
Count:=PWord(TP)^;
|
||||||
// Now point TP to first propinfo record.
|
// Now point TP to first propinfo record.
|
||||||
Inc(Pointer(TP),SizeOF(Word));
|
Inc(Pointer(TP),SizeOF(Word));
|
||||||
@ -1420,7 +1650,7 @@ begin
|
|||||||
PropList^[TP^.NameIndex]:=TP;
|
PropList^[TP^.NameIndex]:=TP;
|
||||||
// Point to TP next propinfo record.
|
// Point to TP next propinfo record.
|
||||||
// Located at Name[Length(Name)+1] !
|
// Located at Name[Length(Name)+1] !
|
||||||
TP:=aligntoptr(PPropInfo(pointer(@TP^.Name)+PByte(@TP^.Name)^+1));
|
TP:=aligntoptr(PPropInfo(pointer(@TP^.Name)+PByte(@TP^.Name)^+(TP^.AttributeCount*SizeOf(TAttributeProc))+1));
|
||||||
Dec(Count);
|
Dec(Count);
|
||||||
end;
|
end;
|
||||||
TypeInfo:=TD^.Parentinfo;
|
TypeInfo:=TD^.Parentinfo;
|
||||||
|
43
tests/test/tclassattribute1.pp
Normal file
43
tests/test/tclassattribute1.pp
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
program tclassattribute1;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
{$modeswitch prefixedattributes}
|
||||||
|
|
||||||
|
uses
|
||||||
|
typinfo;
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
{ tmyt }
|
||||||
|
|
||||||
|
tmyt = class(TCustomAttribute)
|
||||||
|
constructor create;
|
||||||
|
end;
|
||||||
|
|
||||||
|
type
|
||||||
|
[Tmyt]
|
||||||
|
TMyObject = class(TObject)
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
ad: PAttributeData;
|
||||||
|
AClassAttribute: TCustomAttribute;
|
||||||
|
|
||||||
|
{ tmyt }
|
||||||
|
|
||||||
|
constructor tmyt.create;
|
||||||
|
begin
|
||||||
|
//
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
ad := GetAttributeData(TMyObject.ClassInfo);
|
||||||
|
if ad^.AttributeCount<>1 then
|
||||||
|
halt(1);
|
||||||
|
|
||||||
|
AClassAttribute := GetAttribute(ad,0);
|
||||||
|
if AClassAttribute = nil then
|
||||||
|
halt(2);
|
||||||
|
writeln('ok');
|
||||||
|
end.
|
||||||
|
|
34
tests/test/tclassattribute10.pp
Normal file
34
tests/test/tclassattribute10.pp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
program tclassattribute10;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
{$modeswitch prefixedattributes}
|
||||||
|
|
||||||
|
uses
|
||||||
|
typinfo;
|
||||||
|
|
||||||
|
type
|
||||||
|
{ TMyAttr }
|
||||||
|
TMyAttrAttribute = class(TCustomAttribute)
|
||||||
|
end;
|
||||||
|
|
||||||
|
type
|
||||||
|
// The attribute should be also accessable without the Attribute suffix.
|
||||||
|
[TMyAttr]
|
||||||
|
TMyObject = class(TObject)
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
ad: PAttributeData;
|
||||||
|
AClassAttribute: TCustomAttribute;
|
||||||
|
|
||||||
|
begin
|
||||||
|
ad := GetAttributeData(TMyObject.ClassInfo);
|
||||||
|
if ad^.AttributeCount<>1 then
|
||||||
|
halt(1);
|
||||||
|
|
||||||
|
AClassAttribute := GetAttribute(ad,0);
|
||||||
|
if AClassAttribute = nil then
|
||||||
|
halt(2);
|
||||||
|
writeln('ok');
|
||||||
|
end.
|
||||||
|
|
16
tests/test/tclassattribute2.pp
Normal file
16
tests/test/tclassattribute2.pp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{ %fail }
|
||||||
|
program tclassattribute2;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
{$modeswitch prefixedattributes}
|
||||||
|
|
||||||
|
type
|
||||||
|
// Delphi XE does compile attributes that are not defined, but ignores them.
|
||||||
|
// That's clearly a Delphi-bug, so fpc should fail on the following:
|
||||||
|
[TMyAttributeDoesNotExist]
|
||||||
|
TMyObject = class(TObject)
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
end.
|
||||||
|
|
22
tests/test/tclassattribute3.pp
Normal file
22
tests/test/tclassattribute3.pp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{ %fail }
|
||||||
|
program tclassattribute3;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
{$modeswitch prefixedattributes}
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
{ tmyt }
|
||||||
|
|
||||||
|
tmyt = class
|
||||||
|
constructor create;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// tmyt is not a TCustomAttribute, so this should fail.
|
||||||
|
[tmyt]
|
||||||
|
TMyObject = class(TObject)
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
end.
|
||||||
|
|
55
tests/test/tclassattribute4.pp
Normal file
55
tests/test/tclassattribute4.pp
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
program tclassattribute4;
|
||||||
|
|
||||||
|
{$mode delphi}
|
||||||
|
|
||||||
|
uses
|
||||||
|
typinfo;
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
{ tmyt }
|
||||||
|
|
||||||
|
tmyt = class(TCustomAttribute)
|
||||||
|
private
|
||||||
|
FID: integer;
|
||||||
|
public
|
||||||
|
constructor create(Id: integer);
|
||||||
|
end;
|
||||||
|
|
||||||
|
type
|
||||||
|
[Tmyt(924)]
|
||||||
|
[Tmyt(1425)]
|
||||||
|
TMyObject = class(TObject)
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
rtd: PAttributeData;
|
||||||
|
AClassAttribute: tmyt;
|
||||||
|
|
||||||
|
{ tmyt }
|
||||||
|
|
||||||
|
constructor tmyt.create(Id: integer);
|
||||||
|
begin
|
||||||
|
Fid := Id;
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
rtd := GetAttributeData(TMyObject.ClassInfo);
|
||||||
|
|
||||||
|
if rtd^.AttributeCount<>2 then
|
||||||
|
halt(1);
|
||||||
|
|
||||||
|
AClassAttribute := GetAttribute(rtd,1) as tmyt;
|
||||||
|
if AClassAttribute = nil then
|
||||||
|
halt(2);
|
||||||
|
if AClassAttribute.FID<>1425 then
|
||||||
|
halt(3);
|
||||||
|
|
||||||
|
AClassAttribute := GetAttribute(rtd,0) as tmyt;
|
||||||
|
if AClassAttribute = nil then
|
||||||
|
halt(2);
|
||||||
|
if AClassAttribute.FID<>924 then
|
||||||
|
halt(3);
|
||||||
|
writeln('ok');
|
||||||
|
end.
|
||||||
|
|
30
tests/test/tclassattribute5.pp
Normal file
30
tests/test/tclassattribute5.pp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{ %fail }
|
||||||
|
program tclassattribute5;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
{$modeswitch prefixedattributes}
|
||||||
|
|
||||||
|
uses
|
||||||
|
typinfo;
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
{ tmyt }
|
||||||
|
|
||||||
|
tmyt = class(TCustomAttribute)
|
||||||
|
private
|
||||||
|
FID: integer;
|
||||||
|
public
|
||||||
|
constructor create(Id: integer);
|
||||||
|
end;
|
||||||
|
|
||||||
|
type
|
||||||
|
// Delphi XE does compile attributes with invalid parameters.
|
||||||
|
// That's clearly a Delphi-bug, so fpc should fail on the following:
|
||||||
|
[Tmyt(924,32)]
|
||||||
|
TMyObject = class(TObject)
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
end.
|
||||||
|
|
51
tests/test/tclassattribute6.pp
Normal file
51
tests/test/tclassattribute6.pp
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
program tclassattribute6;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
{$modeswitch prefixedattributes}
|
||||||
|
|
||||||
|
uses
|
||||||
|
typinfo;
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
{ tmyt }
|
||||||
|
|
||||||
|
TMyt = class(TCustomAttribute)
|
||||||
|
constructor create;
|
||||||
|
end;
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
{ TMyObject }
|
||||||
|
|
||||||
|
TMyObject = class(TObject)
|
||||||
|
private
|
||||||
|
FInt: integer;
|
||||||
|
published
|
||||||
|
[TMyt]
|
||||||
|
property PublicInt: integer read FInt;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TMyt.create;
|
||||||
|
begin
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
var
|
||||||
|
pi: PPropInfo;
|
||||||
|
AClassAttribute: TCustomAttribute;
|
||||||
|
|
||||||
|
begin
|
||||||
|
pi := GetPropInfo(TMyObject.ClassInfo,'PublicInt');
|
||||||
|
if pi^.AttributeCount<>1 then
|
||||||
|
halt(1);
|
||||||
|
|
||||||
|
AClassAttribute := GetPropAttribute(pi,0) as TCustomAttribute;
|
||||||
|
if AClassAttribute = nil then
|
||||||
|
halt(2);
|
||||||
|
|
||||||
|
writeln('ok');
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
39
tests/test/tclassattribute7.pp
Normal file
39
tests/test/tclassattribute7.pp
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
{ %fail }
|
||||||
|
program tclassattribute7;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
{$modeswitch prefixedattributes}
|
||||||
|
|
||||||
|
uses
|
||||||
|
typinfo;
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
{ tmyt }
|
||||||
|
|
||||||
|
TMyt = class(TCustomAttribute)
|
||||||
|
constructor create;
|
||||||
|
end;
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
{ TMyObject }
|
||||||
|
|
||||||
|
TMyObject = class(TObject)
|
||||||
|
private
|
||||||
|
FInt: integer;
|
||||||
|
published
|
||||||
|
// Should fail because there is nothing to bind the custom attribute to.
|
||||||
|
[TMyt]
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TMyt.create;
|
||||||
|
begin
|
||||||
|
//
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
begin
|
||||||
|
//
|
||||||
|
end.
|
||||||
|
|
37
tests/test/tclassattribute8.pp
Normal file
37
tests/test/tclassattribute8.pp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
{ %fail }
|
||||||
|
program tclassattribute8;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
{$modeswitch prefixedattributes}
|
||||||
|
|
||||||
|
uses
|
||||||
|
typinfo;
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
{ tmyt }
|
||||||
|
|
||||||
|
TMyt = class(TCustomAttribute)
|
||||||
|
constructor create;
|
||||||
|
end;
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
{ TMyObject }
|
||||||
|
|
||||||
|
[TMyt]
|
||||||
|
TMyObject = class(TObject)
|
||||||
|
end;
|
||||||
|
// Attributes for integers are not allowed, so the following should fail, since
|
||||||
|
// there is nothing to bind the attribute to.
|
||||||
|
[TMyt]
|
||||||
|
int = integer;
|
||||||
|
|
||||||
|
constructor TMyt.create;
|
||||||
|
begin
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
end.
|
||||||
|
|
33
tests/test/tclassattribute9.pp
Normal file
33
tests/test/tclassattribute9.pp
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
program tclassattribute9;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
{$modeswitch prefixedattributes}
|
||||||
|
|
||||||
|
uses
|
||||||
|
typinfo;
|
||||||
|
|
||||||
|
type
|
||||||
|
{ tmyt }
|
||||||
|
// TCustomAttribute without constructor
|
||||||
|
tmyt = class(TCustomAttribute);
|
||||||
|
|
||||||
|
type
|
||||||
|
[Tmyt]
|
||||||
|
TMyObject = class(TObject)
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
ad: PAttributeData;
|
||||||
|
AClassAttribute: TCustomAttribute;
|
||||||
|
|
||||||
|
begin
|
||||||
|
ad := GetAttributeData(TMyObject.ClassInfo);
|
||||||
|
if ad^.AttributeCount<>1 then
|
||||||
|
halt(1);
|
||||||
|
|
||||||
|
AClassAttribute := GetAttribute(ad,0);
|
||||||
|
if AClassAttribute = nil then
|
||||||
|
halt(2);
|
||||||
|
writeln('ok');
|
||||||
|
end.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user