Browse Source

* Forgot to commit, main part of indexed properties implementation by Lipinast Lekrisov

Michaël Van Canneyt 7 months ago
parent
commit
cb072b6b8c
1 changed files with 146 additions and 29 deletions
  1. 146 29
      packages/rtl-objpas/src/inc/rtti.pp

+ 146 - 29
packages/rtl-objpas/src/inc/rtti.pp

@@ -765,10 +765,13 @@ type
     FPropInfo: PPropInfo;  
     FAttributesResolved: boolean;
     FAttributes: TCustomAttributeArray;
+    FParams:  TRttiParameterArray;
     FReadMethod: TRttiMethod;
     FWriteMethod: TRttiMethod;
     procedure GetAccessors;
     //function GetIsDefault: Boolean; virtual;
+    function GetIndexParameters: TRttiParameterArray; virtual;
+    function GetIsClassProperty: Boolean; virtual;
     function GetPropertyType: TRttiType; virtual;
     function GetIsReadable: Boolean; virtual;
     function GetIsWritable: Boolean; virtual;
@@ -776,7 +779,8 @@ type
     function GetWriteMethod: TRttiMethod; virtual;
     function GetReadProc: CodePointer; virtual;
     function GetWriteProc: CodePointer; virtual;
-  protected                      
+    procedure ResolveIndexParams;
+  protected
     function GetName: string; override;
     function GetHandle: Pointer; override;
   public
@@ -788,6 +792,8 @@ type
       const aValue: TValue);
     function ToString: String; override;
     property Handle: Pointer read GetHandle;
+    property IndexParameters: TRttiParameterArray read GetIndexParameters;
+    property IsClassProperty: Boolean read GetIsClassProperty;
     property IsReadable: Boolean read GetIsReadable;
     property IsWritable: Boolean read GetIsWritable;
     property PropertyType: TRttiType read GetPropertyType;
@@ -1405,6 +1411,9 @@ resourcestring
   SErrCannotReadClassProperty = 'Cannot read class property "%s"';
   SErrCannotWriteToIndexedProperty = 'Cannot write to indexed property "%s"';
   SErrCannotReadIndexedProperty = 'Cannot read indexed property "%s"';
+  // SErrIndPropArgInvalidType   = 'Invalid type of argument for parameter %s of indexed property %s';
+  SErrIndPropArgCount         = 'Invalid argument count for indexed property %s; expected %d, but got %d';
+  // SErrInvalidIndPropValue     = 'Invalid indexed property value type for: %s';
 
 var
   // Boolean = UsePublishedOnly
@@ -5764,10 +5773,15 @@ end;
 procedure TRttiIndexedProperty.GetAccessors;
 
 begin
-  if Assigned(FReadMethod) or Assigned(FWriteMethod) or
-     not IsReadable and not IsWritable then
+  if Assigned(FReadMethod)
+     or Assigned(FWriteMethod)
+     or not (IsReadable or IsWritable) then
     Exit;
-  // yet not implemented
+  { not tested on virtual methods }
+  if IsReadable then
+    FReadMethod := Parent.GetMethod(ReadProc);
+  if IsWritable then
+    FWriteMethod := Parent.GetMethod(WriteProc);
 end;
 
 function TRttiIndexedProperty.GetPropertyType: TRttiType;
@@ -5782,6 +5796,61 @@ begin
   end;
 end;
 
+procedure TRttiIndexedProperty.ResolveIndexParams;
+var
+  param: PVmtMethodParam;
+  total, visible: SizeInt;
+  context: TRttiContext;
+  obj: TRttiObject;
+  prtti : TRttiVmtMethodParameter;
+begin
+  total := 0;
+  visible := 0;
+  SetLength(FParams,FPropInfo^.PropParams^.Count);
+  context := TRttiContext.Create(FUsePublishedOnly);
+  try
+    param := @FPropInfo^.PropParams^.Params[0];
+    while total < FPropInfo^.PropParams^.Count do
+    begin
+      obj := context.GetByHandle(param);
+      if Assigned(obj) then
+        prtti := obj as TRttiVmtMethodParameter
+      else
+        begin
+        prtti := TRttiVmtMethodParameter.Create(param);
+        context.AddObject(prtti);
+        end;
+      FParams[total]:=prtti;
+      if not (pfHidden in param^.Flags) then
+      begin
+        FParams[visible] := prtti;
+        Inc(visible);
+      end;
+      param := param^.Next;
+      Inc(total);
+    end;
+    if visible <> total then
+      SetLength(FParams, visible);
+  finally
+    context.Free;
+  end;
+end;
+
+function TRttiIndexedProperty.GetIndexParameters: TRttiParameterArray;
+begin
+  if FPropInfo^.PropParams^.Count = 0 then
+    Exit(Nil);
+  if Length(FParams) > 0 then
+    Exit(FParams);
+  ResolveIndexParams;
+  Result := FParams;
+end;
+
+function TRttiIndexedProperty.GetIsClassProperty: boolean;
+begin
+  result := FPropInfo^.IsStatic;
+end;
+
 function TRttiIndexedProperty.GetIsReadable: boolean;
 begin
   Result := Assigned(FPropInfo^.GetProc);
@@ -5794,26 +5863,42 @@ end;
 
 function TRttiIndexedProperty.GetReadMethod: TRttiMethod;
 begin
-  //Result := FPropInfo^.GetProc;
   Result := nil;
-  raise ENotImplemented.Create(SErrNotImplementedRtti);
+  if IsReadable then
+  begin
+    if FReadMethod = nil then
+      GetAccessors;
+    Result := FReadMethod;
+  end;
 end;
 
 function TRttiIndexedProperty.GetWriteMethod: TRttiMethod;
 begin
-  //Result := FPropInfo^.SetProc;
   Result := nil;
-  raise ENotImplemented.Create(SErrNotImplementedRtti);
+  if IsWritable then
+  begin
+    if FWriteMethod = nil then
+      GetAccessors;
+    Result := FWriteMethod;
+  end;
 end;
 
 function TRttiIndexedProperty.GetReadProc: CodePointer;
 begin
-  Result := FPropInfo^.GetProc;
+  if (FPropInfo^.PropProcs and 3)=ptStatic then
+    Result := FPropInfo^.GetProc
+  else
+    { ptVirtual }
+    Result := PCodePointer(Pointer(Parent.AsInstance.MetaClassType)+PtrUInt(FPropInfo^.GetProc))^;
 end;
 
 function TRttiIndexedProperty.GetWriteProc: CodePointer;
 begin
-  Result := FPropInfo^.SetProc;
+  if (FPropInfo^.PropProcs and 3)=ptStatic then
+    Result := FPropInfo^.SetProc
+  else
+    { ptVirtual }
+    Result := PCodePointer(Pointer(Parent.AsInstance.MetaClassType)+PtrUInt(FPropInfo^.SetProc))^;
 end;
 
 function TRttiIndexedProperty.GetName: string;
@@ -5831,6 +5916,7 @@ begin
   inherited Create(AParent);
   FPropInfo := APropInfo;
 end;
+
 destructor TRttiIndexedProperty.Destroy;
 var
   attr: TCustomAttribute;
@@ -5862,36 +5948,67 @@ end;
 function TRttiIndexedProperty.GetValue(aInstance: Pointer;
   const aArgs: array of TValue): TValue;
 var
-  getter: TRttiMethod;
+  argList: TValueArray;
+  I, J: Integer;
+  params: TRttiParameterArray;
 begin
-  getter := ReadMethod;
-  if getter = nil then
+  if not IsReadable then
     raise EPropertyError.CreateFmt(SErrCannotReadIndexedProperty, [Name]);
-  if getter.IsStatic or getter.IsClassMethod then
-    Result := getter.Invoke(TClass(aInstance), aArgs)
+  params := GetIndexParameters;
+  if Length(params) <> Length(aArgs) then
+    raise EInvocationError.CreateFmt(SErrIndPropArgCount, [Name, Length(params), Length(aArgs)]);
+  if FPropInfo^.IsStatic then
+    J := 0
   else
-    Result := getter.Invoke(TObject(aInstance), aArgs);
+    J := 1;
+  argList := [];
+  SetLength(argList, J + Length(aArgs));
+  if not FPropInfo^.IsStatic then
+    if Parent is TRttiInstanceType then
+      argList[0] := TObject(aInstance)
+    else
+      argList[0] := aInstance;
+  for I := 0 to Length(aArgs)-1 do
+    begin
+    argList[J] := aArgs[I].Cast(TypeInfoFromRtti(params[I].ParamType));
+    Inc(J);
+    end;
+  Result := {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}Rtti.Invoke(ReadProc, argList, ccReg, FPropInfo^.PropType, FPropInfo^.IsStatic, False);
 end;
 
 procedure TRttiIndexedProperty.SetValue(aInstance: Pointer;
   const aArgs: array of TValue; const aValue: TValue);
 var
-  setter: TRttiMethod;
-  argsV: TValueArray;
-  i: Integer;
+  argList: TValueArray;
+  I, J: Integer;
+  params: TRttiParameterArray;
 begin
-  argsV:=[];
-  setter := WriteMethod;
-  if setter = nil then
+  if not IsWritable then
     raise EPropertyError.CreateFmt(SErrCannotWriteToIndexedProperty, [Name]);
-  SetLength(argsV, Length(aArgs) + 1);
-  for i := 0 to High(aArgs) do
-    argsV[i] := aArgs[i];
-  argsV[Length(aArgs)] := aValue;
-  if setter.IsStatic or setter.IsClassMethod then
-    setter.Invoke(TClass(aInstance), argsV)
+  params := GetIndexParameters;
+  if Length(params) <> Length(aArgs) then
+    raise EInvocationError.CreateFmt(SErrIndPropArgCount, [Name, Length(params), Length(aArgs)]);
+  if FPropInfo^.IsStatic then
+    J := 0
   else
-    setter.Invoke(TObject(aInstance), argsV);
+    J := 1;
+
+  argList := [];
+  SetLength(argList, J + Length(aArgs) + 1);
+
+  if not FPropInfo^.IsStatic then
+    if Parent is TRttiInstanceType then
+      argList[0] := TObject(aInstance)
+    else
+      argList[0] := aInstance;
+
+  for I := 0 to Length(aArgs)-1 do
+  begin
+    argList[J] := aArgs[I].Cast(TypeInfoFromRtti(params[I].ParamType));
+    Inc(J);
+  end;
+  argList[J] := aValue.Cast(FPropInfo^.PropType);
+  {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}Rtti.Invoke(WriteProc, argList, ccReg, FPropInfo^.PropType, FPropInfo^.IsStatic, False);
 end;
 
 function TRttiIndexedProperty.ToString: string;