Browse Source

* Patch from Ondrej Pokorny to allow correct nodefault/stored for strings

git-svn-id: trunk@37954 -
michael 7 years ago
parent
commit
f6a08a2c74
5 changed files with 152 additions and 4 deletions
  1. 1 0
      .gitattributes
  2. 9 0
      compiler/defutil.pas
  3. 13 0
      compiler/pdecvar.pas
  4. 13 4
      rtl/objpas/classes/writer.inc
  5. 116 0
      tests/test/tpropdef.pp

+ 1 - 0
.gitattributes

@@ -13441,6 +13441,7 @@ tests/test/tprocvar3.pp svneol=native#text/plain
 tests/test/tprop.pp svneol=native#text/plain
 tests/test/tprop1.pp svneol=native#text/plain
 tests/test/tprop2.pp svneol=native#text/plain
+tests/test/tpropdef.pp svneol=native#text/plain
 tests/test/trange1.pp svneol=native#text/plain
 tests/test/trange2.pp svneol=native#text/plain
 tests/test/trange3.pp svneol=native#text/plain

+ 9 - 0
compiler/defutil.pas

@@ -205,6 +205,9 @@ interface
     {# Returns true if p is a short string type }
     function is_shortstring(p : tdef) : boolean;
 
+    {# Returns true if p is any pointer def }
+    function is_pointer(p : tdef) : boolean;
+
     {# Returns true if p is a pchar def }
     function is_pchar(p : tdef) : boolean;
 
@@ -856,6 +859,12 @@ implementation
                                 is_widechar(tarraydef(p).elementdef);
       end;
 
+    { true if p is any pointer def }
+    function is_pointer(p : tdef) : boolean;
+      begin
+        is_pointer:=(p.typ=pointerdef);
+      end;
+
     { true if p is a pchar def }
     function is_pchar(p : tdef) : boolean;
       begin

+ 13 - 0
compiler/pdecvar.pas

@@ -222,6 +222,15 @@ implementation
              end;
           end;
 
+          function has_implicit_default(p : tpropertysym) : boolean;
+
+          begin
+             has_implicit_default:=
+               (is_string(p.propdef) or
+               is_real(p.propdef) or
+               is_pointer(p.propdef));
+          end;
+
           function allow_default_property(p : tpropertysym) : boolean;
 
           begin
@@ -656,6 +665,10 @@ implementation
                   end;
               end;
            end;
+         if has_implicit_default(p) then
+           begin
+              p.default:=0;
+           end;
          if not is_record(astruct) and try_to_consume(_DEFAULT) then
            begin
               if not allow_default_property(p) then

+ 13 - 4
rtl/objpas/classes/writer.inc

@@ -944,7 +944,7 @@ begin
           DefValue :=PPropInfo(PropInfo)^.Default;
           DefFloatValue:=PSingle(@PPropInfo(PropInfo)^.Default)^;
           end;
-        if (FloatValue<>DefFloatValue) or (DefValue=longint($80000000)) then
+        if (FloatValue<>DefFloatValue) or (not HasAncestor and (DefValue=longint($80000000))) then
         begin
           Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
           WriteFloat(FloatValue);
@@ -985,9 +985,12 @@ begin
         if HasAncestor then
           DefStrValue := GetStrProp(Ancestor, PropInfo)
         else
+        begin
+          DefValue :=PPropInfo(PropInfo)^.Default;
           SetLength(DefStrValue, 0);
+        end;
 
-        if StrValue <> DefStrValue then
+        if (StrValue<>DefStrValue) or (not HasAncestor and (DefValue=longint($80000000))) then
         begin
           Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
           if Assigned(FOnWriteStringProperty) then
@@ -1002,9 +1005,12 @@ begin
         if HasAncestor then
           WDefStrValue := GetWideStrProp(Ancestor, PropInfo)
         else
+        begin
+          DefValue :=PPropInfo(PropInfo)^.Default;
           SetLength(WDefStrValue, 0);
+        end;
 
-        if WStrValue <> WDefStrValue then
+        if (WStrValue<>WDefStrValue) or (not HasAncestor and (DefValue=longint($80000000))) then
         begin
           Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
           WriteWideString(WStrValue);
@@ -1017,9 +1023,12 @@ begin
         if HasAncestor then
           UDefStrValue := GetUnicodeStrProp(Ancestor, PropInfo)
         else
+        begin
+          DefValue :=PPropInfo(PropInfo)^.Default;
           SetLength(UDefStrValue, 0);
+        end;
 
-        if UStrValue <> UDefStrValue then
+        if (UStrValue<>UDefStrValue) or (not HasAncestor and (DefValue=longint($80000000))) then
         begin
           Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
           WriteUnicodeString(UStrValue);

+ 116 - 0
tests/test/tpropdef.pp

@@ -0,0 +1,116 @@
+program EmptyStringWriter;
+
+{$mode objfpc}{$h+}
+
+uses
+  SysUtils, Classes;
+
+type
+  TMyComp = class(TComponent)
+  public const
+    cDefS = 'default';
+  private
+    fS: string;
+    fT: string;
+    fU: string;
+    fSn: string;
+    fTn: string;
+    fUn: string;
+    fSdef: string;
+    function SStored: Boolean;
+    function SnStored: Boolean;
+    function SdefStored: Boolean;
+  public
+    constructor Create(AOwner: TComponent); override;
+  published
+    property S: string read fS write fS stored SStored nodefault;
+    property T: string read fT write fT nodefault;
+    property U: string read fU write fU;
+    property Sn: string read fSn write fSn stored SnStored nodefault;
+    property Tn: string read fTn write fTn nodefault;
+    property Un: string read fUn write fUn;
+    property Sdef: string read fSdef write fSdef stored SdefStored nodefault;
+  end;
+
+{ TMyComp }
+
+constructor TMyComp.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner);
+
+  fS := cDefS;
+  fSn := cDefS;
+  fSdef := cDefS;
+end;
+
+function TMyComp.SdefStored: Boolean;
+begin
+  Result := fSdef <> cDefS;
+end;
+
+function TMyComp.SnStored: Boolean;
+begin
+  Result := fSn <> cDefS;
+end;
+
+function TMyComp.SStored: Boolean;
+begin
+  Result := fS <> cDefS;
+end;
+
+const
+  ExpectedOutput: RawByteString = #7#84#77#121#67#111#109#112#0#1#83#6#0#1#84#6#0#2#83#110#6#1#110#2#84#110#6#1#110#2#85#110#6#1#110#0#0;
+var
+  xStream: TStream;
+  xWriter: TWriter;
+  C: TMyComp;
+  xReader: TReader;
+  B: Byte;
+  I: Integer;
+begin
+  xStream := TMemoryStream.Create;
+  C := TMyComp.Create(nil);
+  C.S := '';
+  C.T := '';
+  C.U := '';
+  C.Sn := 'n';
+  C.Tn := 'n';
+  C.Un := 'n';
+  //keep SDef to default value -> won't be streamed
+  xWriter := TWriter.Create(xStream, 1024);
+  xWriter.WriteComponent(C);
+  C.Free;
+  xWriter.Free;
+  xStream.Position := 0;
+  I := 1;
+  while xStream.Read(B, 1) = 1 do
+  begin
+    if (I>Length(ExpectedOutput)) or (B<>Ord(ExpectedOutput[I])) then
+      raise Exception.CreateFmt('Wrong output at character index: %d', [I]);
+    Inc(I);
+  end;
+  xStream.Position := 0;
+  C := TMyComp.Create(nil);
+  xReader := TReader.Create(xStream, 1024);
+  xReader.BeginReferences;
+  xReader.ReadComponent(C);
+  xReader.EndReferences;
+  if C.S<>'' then
+    raise Exception.Create('S invalid.');
+  if C.T<>'' then
+    raise Exception.Create('T invalid.');
+  if C.U<>'' then
+    raise Exception.Create('U invalid.');
+  if C.Sn<>'n' then
+    raise Exception.Create('Sn invalid.');
+  if C.Tn<>'n' then
+    raise Exception.Create('Tn invalid.');
+  if C.Un<>'n' then
+    raise Exception.Create('Un invalid.');
+  if C.Sdef<>TMyComp.cDefS then
+    raise Exception.Create('Un invalid.');
+  C.Free;
+  xReader.Free;
+  xStream.Free;
+end.
+