trtti15.pp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. program trtti15;
  2. {$mode objfpc}{$H+}
  3. uses
  4. typinfo,
  5. sysutils;
  6. type
  7. IBlubb = interface
  8. procedure Test;
  9. end;
  10. {$push}
  11. {$M+}
  12. ITest = interface
  13. procedure Test;
  14. function Test2: LongInt;
  15. procedure Test3(arg1: LongInt; arg2: String);
  16. function Test4(arg1: LongInt; arg2: String): String;
  17. function Test5(arg1: array of LongInt; arg2: Int64): Int64;
  18. function Test6(arg1: LongInt; arg2: String): String; stdcall;
  19. {$if defined(CPUI386) or defined(CPUI8086)}
  20. function Test7(arg1: LongInt; arg2: String): String; pascal;
  21. {$endif}
  22. function Test8(arg1: LongInt; arg2: String): String; cdecl;
  23. procedure Test9(var arg1; out arg2; constref arg3);
  24. property T: LongInt read Test2;
  25. property T2: LongInt read Test2;
  26. end;
  27. {$interfaces corba}
  28. ITestRaw = interface
  29. ['Test']
  30. function Test: LongInt;
  31. property T: LongInt read Test;
  32. end;
  33. {$pop}
  34. procedure ErrorHalt(const aMsg: String; const aArgs: array of const);
  35. begin
  36. if Length(aArgs) = 0 then
  37. Writeln(aMsg)
  38. else
  39. Writeln(Format(aMsg, aArgs));
  40. Halt(1);
  41. end;
  42. procedure TestParam(aParam: PVmtMethodParam; const aName: String; aFlags: TParamFlags; aTypeInfo: PTypeInfo);
  43. begin
  44. Writeln(#9'Testing parameter ', aName);
  45. if not (pfHidden in aFlags) and (aParam^.Name <> aName) then
  46. ErrorHalt('Expected parameter name %s, but got %s', [aName, aParam^.Name]);
  47. if aParam^.Flags <> aFlags then
  48. ErrorHalt('Expected parameter flags %s, but got %s', [HexStr(Word(aFlags), 4), HexStr(Word(aParam^.Flags), 4)]);
  49. if Assigned(aTypeInfo) then begin
  50. if not Assigned(aParam^.ParamType) then
  51. ErrorHalt('Expected parameter type %s, but got Nil', [aTypeInfo^.Name]);
  52. if aParam^.ParamType^ <> aTypeInfo then
  53. ErrorHalt('Expected parameter type %s, but got %s', [aTypeInfo^.Name, aParam^.ParamType^^.Name]);
  54. end else begin
  55. if Assigned(aParam^.ParamType) then
  56. ErrorHalt('Expected Nil parameter type, but got %s', [aParam^.ParamType^^.Name])
  57. end;
  58. end;
  59. type
  60. TTestParam = record
  61. name: String;
  62. flags: TParamFlags;
  63. paramtype: PTypeInfo;
  64. end;
  65. function MakeParam(const aName: String; aFlags: TParamFlags; aTypeInfo: PTypeInfo): TTestParam;
  66. begin
  67. Result.name := aName;
  68. Result.flags := aFlags;
  69. Result.paramtype := aTypeInfo;
  70. end;
  71. procedure TestMethod(aMethod: PIntfMethodEntry; const aName: String; aKind: TMethodKind; aCC: TCallConv; aParams: array of TTestParam; aResult: PTypeInfo);
  72. var
  73. c, i: LongInt;
  74. param: PVmtMethodParam;
  75. begin
  76. Writeln('Testing method ', aName);
  77. if aMethod^.Name <> aName then
  78. ErrorHalt('Expected method name %s, but got %s', [aName, aMethod^.Name]);
  79. if aMethod^.CC <> aCC then
  80. ErrorHalt('Expected calling convention %d, but got %d', [Ord(aCC), Ord(aMethod^.CC)]);
  81. if aMethod^.Kind <> aKind then
  82. ErrorHalt('Expected method kind %d, but got %d', [Ord(aKind), Ord(aMethod^.Kind)]);
  83. if Assigned(aResult) and not Assigned(aMethod^.ResultType) then
  84. ErrorHalt('Expected result type %s, but got Nil', [aResult^.Name]);
  85. if Assigned(aResult) and (aResult <> aMethod^.ResultType^) then
  86. ErrorHalt('Expected result type %s, but got %s', [aResult^.Name, aMethod^.ResultType^^.Name]);
  87. { we ignore an eventual result parameter }
  88. if aMethod^.ParamCount < Length(aParams) then
  89. ErrorHalt('Expected at least %d parameters, but got %d', [Length(aParams), aMethod^.ParamCount]);
  90. if aMethod^.ParamCount < 1 then
  91. ErrorHalt('Expected at least 1 parameter, but got 0', []);
  92. { first parameter is always self }
  93. c := 1;
  94. TestParam(aMethod^.Param[0], aParams[0].name, aParams[0].flags, aParams[0].paramtype);
  95. for i := 1 to aMethod^.ParamCount - 1 do begin
  96. param := aMethod^.Param[i];
  97. if pfResult in param^.Flags then
  98. Continue;
  99. TestParam(param, aParams[c].name, aParams[c].flags, aParams[c].paramtype);
  100. Inc(c);
  101. end;
  102. if c <> Length(aParams) then
  103. ErrorHalt('Expected %d parameters, but got %d', [Length(aParams), c]);
  104. end;
  105. type
  106. TTestMethod = record
  107. name: String;
  108. cc: TCallConv;
  109. kind: TMethodKind;
  110. result: PTypeInfo;
  111. params: array of TTestParam;
  112. end;
  113. function MakeMethod(const aName: String; aCC: TCallConv; aKind: TMethodKind; aResult: PTypeInfo; aParams: array of TTestParam): TTestMethod;
  114. var
  115. i: LongInt;
  116. begin
  117. Result.name := aName;
  118. Result.cc := aCC;
  119. Result.kind := aKind;
  120. Result.result := aResult;
  121. SetLength(Result.params, Length(aParams));
  122. for i := Low(aParams) to High(aParams) do
  123. Result.params[i - Low(aParams)] := aParams[i];
  124. end;
  125. procedure TestInterface(aIntf: PTypeData; aRaw: Boolean; aIIDStr: String; aPropCount: LongInt; aMethods: array of TTestMethod);
  126. var
  127. proptable: PPropData;
  128. methtable: PIntfMethodTable;
  129. i: LongInt;
  130. begin
  131. if aRaw then begin
  132. proptable := PInterfaceRawData(aIntf)^.PropertyTable;
  133. methtable := PInterfaceRawData(aIntf)^.MethodTable;
  134. if PInterfaceRawData(aIntf)^.IIDStr <> aIIDStr then
  135. ErrorHalt('Expected IIDStr ''%s'', but got ''%s''', [aIIDStr, PInterfaceRawData(aIntf)^.IIDStr]);
  136. end else begin
  137. proptable := PInterfaceData(aIntf)^.PropertyTable;
  138. methtable := PInterfaceData(aIntf)^.MethodTable;
  139. end;
  140. if proptable^.PropCount <> aPropCount then
  141. ErrorHalt('Expected %d properties, but got %d', [aPropCount, proptable^.PropCount]);
  142. if methtable^.Count <> Length(aMethods) then
  143. ErrorHalt('Expected %d methods, but got %d', [Length(aMethods), methtable^.Count]);
  144. if methtable^.RttiCount = $ffff then
  145. Exit;
  146. for i := 0 to methtable^.Count - 1 do begin
  147. TestMethod(methtable^.Method[i], aMethods[i].name, aMethods[i].kind, aMethods[i].cc, aMethods[i].params, aMethods[i].result);
  148. end;
  149. end;
  150. const
  151. {$if defined(CPUI386) or defined(CPUI8086) or defined(CPUX86_64) or defined(CPUM68K)}
  152. DefaultCallingConvention = ccReg;
  153. {$else}
  154. DefaultCallingConvention = ccStdCall;
  155. {$endif}
  156. begin
  157. Writeln('Testing interface ITestRaw');
  158. { raw interfaces don't support $M+ currently }
  159. TestInterface(GetTypeData(TypeInfo(ITestRaw)), True, 'Test', 0{1}, [
  160. MakeMethod('Test', ccReg, mkFunction, TypeInfo(LongInt), [])
  161. ]);
  162. Writeln('Testing interface ITest');
  163. TestInterface(GetTypeData(TypeInfo(ITest)), False, '', 2, [
  164. MakeMethod('Test', DefaultCallingConvention, mkProcedure, Nil, [
  165. MakeParam('$self', [pfHidden, pfSelf, pfAddress], TypeInfo(ITest))
  166. ]),
  167. MakeMethod('Test2', DefaultCallingConvention, mkFunction, TypeInfo(LongInt), [
  168. MakeParam('$self', [pfHidden, pfSelf, pfAddress], TypeInfo(ITest))
  169. ]),
  170. MakeMethod('Test3', DefaultCallingConvention, mkProcedure, Nil, [
  171. MakeParam('$self', [pfHidden, pfSelf, pfAddress], TypeInfo(ITest)),
  172. MakeParam('arg1', [], TypeInfo(LongInt)),
  173. MakeParam('arg2', [], TypeInfo(String))
  174. ]),
  175. MakeMethod('Test4', DefaultCallingConvention, mkFunction, TypeInfo(String), [
  176. MakeParam('$self', [pfHidden, pfSelf, pfAddress], TypeInfo(ITest)),
  177. MakeParam('arg1', [], TypeInfo(LongInt)),
  178. MakeParam('arg2', [], TypeInfo(String))
  179. ]),
  180. MakeMethod('Test5', DefaultCallingConvention, mkFunction, TypeInfo(Int64), [
  181. MakeParam('$self', [pfHidden, pfSelf, pfAddress], TypeInfo(ITest)),
  182. MakeParam('arg1', [pfArray, pfReference], TypeInfo(LongInt)),
  183. MakeParam('$highARG1', [pfHidden, pfHigh, pfConst], TypeInfo(SizeInt)),
  184. MakeParam('arg2', [], TypeInfo(Int64))
  185. ]),
  186. MakeMethod('Test6', ccStdCall, mkFunction, TypeInfo(String), [
  187. MakeParam('$self', [pfHidden, pfSelf, pfAddress], TypeInfo(ITest)),
  188. MakeParam('arg1', [], TypeInfo(LongInt)),
  189. MakeParam('arg2', [], TypeInfo(String))
  190. ]),
  191. {$if defined(CPUI386) or defined(CPUI8086)}
  192. MakeMethod('Test7', ccPascal, mkFunction, TypeInfo(String), [
  193. MakeParam('$self', [pfHidden, pfSelf, pfAddress], TypeInfo(ITest)),
  194. MakeParam('arg1', [], TypeInfo(LongInt)),
  195. MakeParam('arg2', [], TypeInfo(String))
  196. ]),
  197. {$endif}
  198. MakeMethod('Test8', ccCdecl, mkFunction, TypeInfo(String), [
  199. MakeParam('$self', [pfHidden, pfSelf, pfAddress], TypeInfo(ITest)),
  200. MakeParam('arg1', [], TypeInfo(LongInt)),
  201. MakeParam('arg2', [], TypeInfo(String))
  202. ]),
  203. MakeMethod('Test9', DefaultCallingConvention, mkProcedure, Nil, [
  204. MakeParam('$self', [pfHidden, pfSelf, pfAddress], TypeInfo(ITest)),
  205. MakeParam('arg1', [pfVar], Nil),
  206. MakeParam('arg2', [pfOut], Nil),
  207. MakeParam('arg3', [pfConstRef], Nil)
  208. ])
  209. ]);
  210. end.