mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-12 17:29:37 +02:00

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 -
654 lines
25 KiB
ObjectPascal
654 lines
25 KiB
ObjectPascal
{
|
||
Copyright (c) 2010 by Jonas Maebe
|
||
|
||
This unit implements some Objective-C type helper routines (minimal
|
||
unit dependencies, usable in symdef).
|
||
|
||
This program is free software; you can redistribute it and/or modify
|
||
it under the terms of the GNU General Public License as published by
|
||
the Free Software Foundation; either version 2 of the License, or
|
||
(at your option) any later version.
|
||
|
||
This program is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
GNU General Public License for more details.
|
||
|
||
You should have received a copy of the GNU General Public License
|
||
along with this program; if not, write to the Free Software
|
||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
|
||
****************************************************************************
|
||
}
|
||
|
||
{$i fpcdefs.inc}
|
||
|
||
unit objcdef;
|
||
|
||
interface
|
||
|
||
uses
|
||
node,
|
||
symtype;
|
||
|
||
{ The internals of Objective-C's @encode() functionality: encode a
|
||
type into the internal format used by the run time. Returns false
|
||
if a type is not representable by the Objective-C run time, and in
|
||
that case also the failing definition. }
|
||
function objctryencodetype(def: tdef; out encodedtype: ansistring; out founderror: tdef): boolean;
|
||
|
||
{ Check whether a type can be used in an Objective-C method
|
||
signature or field declaration. }
|
||
function objcchecktype(def: tdef; out founderror: tdef): boolean;
|
||
|
||
{ add type info for def at the end of encodedstr. recordinfostate influences
|
||
whether a record-style type will be fully encoded, or just using its
|
||
type name. bpacked indicates whether a record/array is bitpacked.
|
||
On error, founderror contains the type that triggered the error. }
|
||
type
|
||
trecordinfostate = (ris_initial, ris_afterpointer, ris_dontprint);
|
||
|
||
function objcaddencodedtype(def: tdef; recordinfostate: trecordinfostate; bpacked: boolean; var encodedstr: ansistring; out founderror: tdef): boolean;
|
||
|
||
implementation
|
||
|
||
uses
|
||
globtype,
|
||
cutils,cclasses,
|
||
verbose,systems,
|
||
symtable,symconst,symsym,symdef,
|
||
defutil,paramgr;
|
||
|
||
{******************************************************************
|
||
Type encoding
|
||
*******************************************************************}
|
||
|
||
function encoderecst(const recname: ansistring; recst: tabstractrecordsymtable; var encodedstr: ansistring; out founderror: tdef): boolean;
|
||
var
|
||
variantstarts: tfplist;
|
||
i, varindex: longint;
|
||
field,
|
||
firstfield: tfieldvarsym;
|
||
firstfieldvariant,
|
||
bpacked: boolean;
|
||
begin
|
||
result:=false;
|
||
bpacked:=recst.fieldalignment=bit_alignment;
|
||
{ Is the first field already the start of a variant? }
|
||
firstfield:=nil;
|
||
firstfieldvariant:=false;
|
||
for i:=0 to recst.symlist.count-1 do
|
||
begin
|
||
if (tsym(recst.symlist[i]).typ<>fieldvarsym) then
|
||
continue;
|
||
field:=tfieldvarsym(recst.symlist[i]);
|
||
if not assigned(firstfield) then
|
||
firstfield:=field
|
||
else if (vo_is_first_field in field.varoptions) then
|
||
begin
|
||
if (field.fieldoffset=firstfield.fieldoffset) then
|
||
firstfieldvariant:=true;
|
||
end;
|
||
end;
|
||
variantstarts:=tfplist.create;
|
||
encodedstr:=encodedstr+'{'+recname+'=';
|
||
for i:=0 to recst.symlist.count-1 do
|
||
begin
|
||
if (tsym(recst.symlist[i]).typ<>fieldvarsym) then
|
||
continue;
|
||
|
||
field:=tfieldvarsym(recst.symlist[i]);
|
||
{ start of a variant part? }
|
||
if ((field=firstfield) and
|
||
firstfieldvariant) or
|
||
((field<>firstfield) and
|
||
(vo_is_first_field in field.varoptions)) then
|
||
begin
|
||
varindex:=variantstarts.count-1;
|
||
if (varindex=-1) or
|
||
(tfieldvarsym(variantstarts[varindex]).fieldoffset<field.fieldoffset) then
|
||
begin
|
||
{ new, more deeply nested variant }
|
||
encodedstr:=encodedstr+'(?={?=';
|
||
variantstarts.add(field);
|
||
end
|
||
else
|
||
begin
|
||
{ close existing nested variants if any }
|
||
while (varindex>=0) and
|
||
(tfieldvarsym(variantstarts[varindex]).fieldoffset>field.fieldoffset) do
|
||
begin
|
||
{ close more deeply nested variants }
|
||
encodedstr:=encodedstr+'})';
|
||
dec(varindex);
|
||
end;
|
||
if (varindex<0) then
|
||
internalerror(2009081805);
|
||
if (tfieldvarsym(variantstarts[varindex]).fieldoffset<>field.fieldoffset) then
|
||
internalerror(2009081804);
|
||
|
||
{ variant at the same level as a previous one }
|
||
variantstarts.count:=varindex+1;
|
||
{ No need to add this field, it has the same offset as the
|
||
previous one at this position. }
|
||
if tfieldvarsym(variantstarts[varindex]).fieldoffset<>field.fieldoffset then
|
||
internalerror(2009081601);
|
||
{ close previous variant sub-part and start new one }
|
||
encodedstr:=encodedstr+'}{?=';
|
||
end
|
||
end;
|
||
if not objcaddencodedtype(field.vardef,ris_afterpointer,bpacked,encodedstr,founderror) then
|
||
exit;
|
||
end;
|
||
for i:=0 to variantstarts.count-1 do
|
||
encodedstr:=encodedstr+'})';
|
||
variantstarts.free;
|
||
encodedstr:=encodedstr+'}';
|
||
result:=true
|
||
end;
|
||
|
||
|
||
function objcaddencodedtype(def: tdef; recordinfostate: trecordinfostate; bpacked: boolean; var encodedstr: ansistring; out founderror: tdef): boolean;
|
||
var
|
||
recname: ansistring;
|
||
recdef: trecorddef;
|
||
objdef: tobjectdef;
|
||
len: aint;
|
||
c: char;
|
||
newstate: trecordinfostate;
|
||
addrpara: boolean;
|
||
begin
|
||
result:=true;
|
||
case def.typ of
|
||
stringdef :
|
||
begin
|
||
case tstringdef(def).stringtype of
|
||
st_shortstring:
|
||
{ include length byte }
|
||
encodedstr:=encodedstr+'['+tostr(tstringdef(def).len+1)+'C]';
|
||
else
|
||
{ While we could handle refcounted Pascal strings correctly
|
||
when such methods are called from Pascal code, things would
|
||
completely break down if they were called from Objective-C
|
||
code/reflection since the necessary refcount helper calls
|
||
would be missing on the caller side (unless we'd
|
||
automatically generate wrappers). }
|
||
result:=false;
|
||
end;
|
||
end;
|
||
enumdef,
|
||
orddef :
|
||
begin
|
||
if bpacked and
|
||
not is_void(def) then
|
||
encodedstr:=encodedstr+'b'+tostr(def.packedbitsize)
|
||
else
|
||
begin
|
||
if is_void(def) then
|
||
c:='v'
|
||
{ in gcc, sizeof(_Bool) = sizeof(char) }
|
||
else if is_boolean(def) and
|
||
(def.size=1) then
|
||
c:='B'
|
||
else
|
||
begin
|
||
case def.size of
|
||
1:
|
||
c:='c';
|
||
2:
|
||
c:='s';
|
||
4:
|
||
c:='i';
|
||
8:
|
||
c:='q';
|
||
else
|
||
internalerror(2009081502);
|
||
end;
|
||
if not is_signed(def) then
|
||
c:=upcase(c);
|
||
end;
|
||
encodedstr:=encodedstr+c;
|
||
end;
|
||
end;
|
||
pointerdef :
|
||
begin
|
||
if is_pchar(def) then
|
||
encodedstr:=encodedstr+'*'
|
||
else if (def=objc_idtype) then
|
||
encodedstr:=encodedstr+'@'
|
||
else if (def=objc_seltype) then
|
||
encodedstr:=encodedstr+':'
|
||
else if (def=objc_metaclasstype) then
|
||
encodedstr:=encodedstr+'#'
|
||
else
|
||
begin
|
||
encodedstr:=encodedstr+'^';
|
||
newstate:=recordinfostate;
|
||
if (recordinfostate<ris_dontprint) then
|
||
newstate:=succ(newstate);
|
||
if not objcaddencodedtype(tpointerdef(def).pointeddef,newstate,false,encodedstr,founderror) then
|
||
begin
|
||
result:=false;
|
||
{ report the exact (nested) error defintion }
|
||
exit;
|
||
end;
|
||
end;
|
||
end;
|
||
floatdef :
|
||
begin
|
||
case tfloatdef(def).floattype of
|
||
s32real:
|
||
c:='f';
|
||
s64real:
|
||
c:='d';
|
||
else
|
||
begin
|
||
c:='!';
|
||
result:=false;
|
||
end;
|
||
end;
|
||
encodedstr:=encodedstr+c;
|
||
end;
|
||
filedef :
|
||
result:=false;
|
||
recorddef :
|
||
begin
|
||
if assigned(def.typesym) then
|
||
recname:=def.typename
|
||
else
|
||
recname:='?';
|
||
|
||
if (recordinfostate<>ris_dontprint) then
|
||
begin
|
||
if not encoderecst(recname,tabstractrecordsymtable(trecorddef(def).symtable),encodedstr,founderror) then
|
||
begin
|
||
result:=false;
|
||
{ report the exact (nested) error defintion }
|
||
exit;
|
||
end
|
||
end
|
||
else
|
||
encodedstr:=encodedstr+'{'+recname+'}'
|
||
end;
|
||
variantdef :
|
||
begin
|
||
recdef:=trecorddef(search_system_type('TVARDATA').typedef);
|
||
if (recordinfostate<>ris_dontprint) then
|
||
begin
|
||
if not encoderecst(recdef.typename,tabstractrecordsymtable(recdef.symtable),encodedstr,founderror) then
|
||
begin
|
||
result:=false;
|
||
{ report the exact (nested) error defintion }
|
||
exit;
|
||
end
|
||
end
|
||
else
|
||
encodedstr:=encodedstr+'{'+recdef.typename+'}';
|
||
end;
|
||
classrefdef :
|
||
begin
|
||
encodedstr:=encodedstr+'^';
|
||
newstate:=recordinfostate;
|
||
if (recordinfostate<>ris_dontprint) then
|
||
newstate:=succ(newstate);
|
||
if is_objcclassref(def) then
|
||
begin
|
||
objdef:=tobjectdef(tclassrefdef(def).pointeddef);
|
||
if (newstate<>ris_dontprint) then
|
||
{ anonymous (objc)class definitions do not exist }
|
||
begin
|
||
if not encoderecst(objdef.objextname^,tabstractrecordsymtable(objdef.symtable),encodedstr,founderror) then
|
||
{ The fields of an Objective-C class should always be
|
||
encodeable. }
|
||
internalerror(2009081702);
|
||
end
|
||
else
|
||
encodedstr:=encodedstr+'{'+objdef.objextname^+'}'
|
||
end
|
||
{ Object Pascal classrefdefs point to a vmt, not really useful
|
||
to completely write those here. I'm not even sure what the
|
||
Objective-C run time uses this information for, since in C you
|
||
can have forward struct definitions so not all structs passed
|
||
to functions can be written out here either -> treat
|
||
classrefdefs the same as such forward-defined structs. }
|
||
else
|
||
begin
|
||
if assigned(def.typesym) then
|
||
recname:=def.typename
|
||
else
|
||
recname:='?';
|
||
encodedstr:=encodedstr+'{'+recname;
|
||
if (newstate<>ris_dontprint) then
|
||
encodedstr:=encodedstr+'=';
|
||
encodedstr:=encodedstr+'}'
|
||
end;
|
||
end;
|
||
setdef :
|
||
begin
|
||
addrpara:=paramanager.push_addr_param(vs_value,def,pocall_cdecl);
|
||
if not addrpara then
|
||
{ encode as an record, they are always passed by value in C. }
|
||
encodedstr:=encodedstr+'{?=';
|
||
{ Encode the set itself as an array. Without an encompassing
|
||
record, these are always passed by reference in C. }
|
||
encodedstr:=encodedstr+'['+tostr(def.size)+'C]';
|
||
if not addrpara then
|
||
encodedstr:=encodedstr+'}';
|
||
end;
|
||
formaldef :
|
||
begin
|
||
encodedstr:=encodedstr+'^v';
|
||
end;
|
||
arraydef :
|
||
begin
|
||
if is_array_of_const(def) then
|
||
{ do nothing, varargs are ignored in signatures }
|
||
else if is_special_array(def) then
|
||
result:=false
|
||
else
|
||
begin
|
||
len:=tarraydef(def).highrange-tarraydef(def).lowrange+1;
|
||
if is_packed_array(def) then
|
||
begin
|
||
{ convert from bits to bytes for bitpacked arrays }
|
||
len:=(len+7) div 8;
|
||
{ and encode as plain array of bytes }
|
||
encodedstr:=encodedstr+'['+tostr(len)+'C]';
|
||
end
|
||
else
|
||
begin
|
||
encodedstr:=encodedstr+'['+tostr(len);
|
||
{ Embedded structured types in the array are printed
|
||
in full regardless of the current recordinfostate. }
|
||
if not objcaddencodedtype(tarraydef(def).elementdef,ris_initial,false,encodedstr,founderror) then
|
||
begin
|
||
result:=false;
|
||
{ report the exact (nested) error defintion }
|
||
exit;
|
||
end;
|
||
encodedstr:=encodedstr+']';
|
||
end;
|
||
end;
|
||
end;
|
||
procvardef :
|
||
encodedstr:=encodedstr+'^?';
|
||
objectdef :
|
||
case tobjectdef(def).objecttype of
|
||
odt_helper,
|
||
odt_class,
|
||
odt_object,
|
||
odt_cppclass:
|
||
begin
|
||
newstate:=recordinfostate;
|
||
{ implicit pointer for classes }
|
||
if (tobjectdef(def).objecttype in [odt_class,odt_helper]) then
|
||
begin
|
||
encodedstr:=encodedstr+'^';
|
||
{ make all classes opaque, so even if they contain a
|
||
reference-counted field there is no problem. Since a
|
||
"dereferenced class" object does not exist, this should
|
||
not cause problems }
|
||
newstate:=ris_dontprint;
|
||
end;
|
||
if newstate<>ris_dontprint then
|
||
begin
|
||
if not encoderecst(def.typename,tabstractrecordsymtable(tobjectdef(def).symtable),encodedstr,founderror) then
|
||
begin
|
||
result:=false;
|
||
{ report the exact (nested) error defintion }
|
||
exit;
|
||
end
|
||
end
|
||
else
|
||
encodedstr:=encodedstr+'{'+def.typename+'}'
|
||
end;
|
||
odt_interfacecom,
|
||
odt_interfacecom_property,
|
||
odt_interfacecom_function,
|
||
odt_dispinterface:
|
||
result:=false;
|
||
odt_interfacecorba:
|
||
encodedstr:=encodedstr+'^{'+def.typename+'=}';
|
||
{ In Objective-C, the actual types of class instances are
|
||
NSObject* etc, and those are encoded as "@". In FPC, to keep
|
||
the similarity with Delphi-style Object Pascal, the type is
|
||
NSObject and the pointer is implicit. Objective-C's "NSObject"
|
||
has "class of NSObject" as equivalent here. }
|
||
odt_objcclass,
|
||
odt_objcprotocol:
|
||
encodedstr:=encodedstr+'@';
|
||
else
|
||
internalerror(2009081509);
|
||
end;
|
||
undefineddef,
|
||
errordef :
|
||
result:=false;
|
||
procdef :
|
||
{ must be done via objcencodemethod() }
|
||
internalerror(2009081511);
|
||
else
|
||
internalerror(2009150812);
|
||
end;
|
||
if not result then
|
||
founderror:=def;
|
||
end;
|
||
|
||
|
||
function objctryencodetype(def: tdef; out encodedtype: ansistring; out founderror: tdef): boolean;
|
||
begin
|
||
result:=objcaddencodedtype(def,ris_initial,false,encodedtype,founderror);
|
||
end;
|
||
|
||
|
||
{******************************************************************
|
||
ObjC type validity checking
|
||
*******************************************************************}
|
||
|
||
function objcdochecktype(def: tdef; recordinfostate: trecordinfostate; out founderror: tdef): boolean; forward;
|
||
|
||
function checkrecsttype(recst: tabstractrecordsymtable; recordinfostate: trecordinfostate; out founderror: tdef): boolean;
|
||
var
|
||
i: longint;
|
||
field: tfieldvarsym;
|
||
newstate: trecordinfostate;
|
||
begin
|
||
result:=false;
|
||
newstate:=recordinfostate;
|
||
{ Although we never have to print the type info for nested
|
||
records, check them anyway in case we're not after a pointer
|
||
since if such records contain refcounted types then they
|
||
can cause just as much trouble as if they were a simple
|
||
refcounted field. }
|
||
if (newstate=ris_afterpointer) then
|
||
newstate:=ris_dontprint;
|
||
for i:=0 to recst.symlist.count-1 do
|
||
begin
|
||
if (tsym(recst.symlist[i]).typ<>fieldvarsym) then
|
||
continue;
|
||
|
||
field:=tfieldvarsym(recst.symlist[i]);
|
||
if not objcdochecktype(field.vardef,newstate,founderror) then
|
||
exit;
|
||
end;
|
||
result:=true
|
||
end;
|
||
|
||
|
||
function objcdochecktype(def: tdef; recordinfostate: trecordinfostate; out founderror: tdef): boolean;
|
||
var
|
||
recdef: trecorddef;
|
||
objdef: tobjectdef;
|
||
newstate: trecordinfostate;
|
||
begin
|
||
result:=true;
|
||
case def.typ of
|
||
stringdef :
|
||
begin
|
||
case tstringdef(def).stringtype of
|
||
st_shortstring:
|
||
;
|
||
else
|
||
{ While we could handle refcounted Pascal strings correctly
|
||
when such methods are called from Pascal code, things would
|
||
completely break down if they were called from Objective-C
|
||
code/reflection since the necessary refcount helper calls
|
||
would be missing on the caller side (unless we'd
|
||
automatically generate wrappers). }
|
||
result:=false;
|
||
end;
|
||
end;
|
||
enumdef,
|
||
orddef :
|
||
;
|
||
pointerdef :
|
||
begin
|
||
newstate:=recordinfostate;
|
||
if (recordinfostate<ris_dontprint) then
|
||
newstate:=succ(newstate);
|
||
if not objcdochecktype(tpointerdef(def).pointeddef,newstate,founderror) then
|
||
begin
|
||
result:=false;
|
||
{ report the exact (nested) error defintion }
|
||
exit;
|
||
end;
|
||
end;
|
||
floatdef :
|
||
begin
|
||
case tfloatdef(def).floattype of
|
||
s32real,
|
||
s64real:
|
||
;
|
||
else
|
||
result:=false;
|
||
end;
|
||
end;
|
||
filedef :
|
||
result:=false;
|
||
recorddef :
|
||
begin
|
||
if (recordinfostate<>ris_dontprint) then
|
||
begin
|
||
if not checkrecsttype(tabstractrecordsymtable(trecorddef(def).symtable),recordinfostate,founderror) then
|
||
begin
|
||
result:=false;
|
||
{ report the exact (nested) error defintion }
|
||
exit;
|
||
end
|
||
end
|
||
end;
|
||
variantdef :
|
||
begin
|
||
recdef:=trecorddef(search_system_type('TVARDATA').typedef);
|
||
if (recordinfostate<>ris_dontprint) then
|
||
begin
|
||
if not checkrecsttype(tabstractrecordsymtable(recdef.symtable),recordinfostate,founderror) then
|
||
begin
|
||
result:=false;
|
||
{ report the exact (nested) error defintion }
|
||
exit;
|
||
end
|
||
end;
|
||
end;
|
||
classrefdef:
|
||
begin
|
||
if is_objcclassref(def) then
|
||
begin
|
||
objdef:=tobjectdef(tclassrefdef(def).pointeddef);
|
||
newstate:=recordinfostate;
|
||
if (recordinfostate<ris_dontprint) then
|
||
newstate:=succ(newstate);
|
||
if (newstate<>ris_dontprint) then
|
||
begin
|
||
if not checkrecsttype(tabstractrecordsymtable(objdef.symtable),recordinfostate,founderror) then
|
||
begin
|
||
result:=false;
|
||
{ report the exact (nested) error defintion }
|
||
exit;
|
||
end
|
||
end
|
||
end
|
||
end;
|
||
setdef,
|
||
formaldef :
|
||
;
|
||
arraydef :
|
||
begin
|
||
if is_array_of_const(def) then
|
||
{ ok, varargs are ignored in signatures }
|
||
else if is_special_array(def) then
|
||
result:=false
|
||
else
|
||
begin
|
||
if not is_packed_array(def) then
|
||
begin
|
||
if not objcdochecktype(tarraydef(def).elementdef,ris_initial,founderror) then
|
||
begin
|
||
result:=false;
|
||
{ report the exact (nested) error defintion }
|
||
exit;
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
procvardef :
|
||
;
|
||
objectdef :
|
||
case tobjectdef(def).objecttype of
|
||
odt_helper,
|
||
odt_class,
|
||
odt_object,
|
||
odt_cppclass:
|
||
begin
|
||
newstate:=recordinfostate;
|
||
{ implicit pointer for classes }
|
||
if (tobjectdef(def).objecttype in [odt_class,odt_helper]) then
|
||
begin
|
||
{ make all classes opaque, so even if they contain a
|
||
reference-counted field there is no problem. Since a
|
||
"dereferenced class" object does not exist, this should
|
||
not cause problems }
|
||
newstate:=ris_dontprint;
|
||
end;
|
||
if newstate<>ris_dontprint then
|
||
begin
|
||
if not checkrecsttype(tabstractrecordsymtable(tobjectdef(def).symtable),newstate,founderror) then
|
||
begin
|
||
result:=false;
|
||
{ report the exact (nested) error defintion }
|
||
exit;
|
||
end
|
||
end
|
||
end;
|
||
odt_interfacecom,
|
||
odt_interfacecom_property,
|
||
odt_interfacecom_function,
|
||
odt_dispinterface:
|
||
result:=false;
|
||
odt_interfacecorba,
|
||
odt_objcclass,
|
||
odt_objcprotocol:
|
||
;
|
||
else
|
||
internalerror(2009081709);
|
||
end;
|
||
undefineddef,
|
||
errordef :
|
||
result:=false;
|
||
procdef :
|
||
result:=false;
|
||
else
|
||
internalerror(2009170812);
|
||
end;
|
||
if not result then
|
||
founderror:=def;
|
||
end;
|
||
|
||
|
||
function objcchecktype(def: tdef; out founderror: tdef): boolean;
|
||
begin
|
||
result:=objcdochecktype(def,ris_initial,founderror);
|
||
end;
|
||
|
||
|
||
end.
|