Skip to content

Commit

Permalink
Simplify empty collections
Browse files Browse the repository at this point in the history
  • Loading branch information
AndriySvyryd committed Jun 16, 2022
1 parent 9d052bf commit f9d834b
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 51 deletions.
28 changes: 23 additions & 5 deletions src/CSharpScriptSerializer/ArrayCSScriptSerializer.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;

namespace CSharpScriptSerialization
{
Expand All @@ -14,15 +16,31 @@ public ArrayCSScriptSerializer(Type type)
}

public override ExpressionSyntax GetCreation(object obj)
=> SyntaxFactory.ArrayCreationExpression((ArrayTypeSyntax)GetTypeSyntax(Type))
.WithInitializer(AddNewLine(
GetArrayInitializerExpression((Array)obj, startingDimension: 0, indices: ImmutableArray<int>.Empty)));
{
var array = (Array)obj;
return array.Length == 0
? ArrayCreationExpression(ArrayType(GetTypeSyntax(GetArrayElementType(Type)),
List(GetEmptyArrayRanks(Type))))
: ArrayCreationExpression((ArrayTypeSyntax)GetTypeSyntax(Type)).WithInitializer(AddNewLine(
GetArrayInitializerExpression(array, startingDimension: 0, indices: ImmutableArray<int>.Empty)));
}

private static IEnumerable<ArrayRankSpecifierSyntax> GetEmptyArrayRanks(Type type)
=> new[]
{
ArrayRankSpecifier(
SeparatedList<ExpressionSyntax>(
ToCommaSeparatedList(
Enumerable.Repeat(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(0)),
type.GetArrayRank()))))
}
.Concat(GetArrayRanks(type.GetElementType()));

private InitializerExpressionSyntax GetArrayInitializerExpression
(Array array, int startingDimension, ImmutableArray<int> indices)
=> SyntaxFactory.InitializerExpression(
=> InitializerExpression(
SyntaxKind.ArrayInitializerExpression,
SyntaxFactory.SeparatedList<ExpressionSyntax>(
SeparatedList<ExpressionSyntax>(
ToCommaSeparatedList(Enumerable.Range(
array.GetLowerBound(startingDimension),
array.GetUpperBound(startingDimension) - array.GetLowerBound(startingDimension) + 1)
Expand Down
16 changes: 9 additions & 7 deletions src/CSharpScriptSerializer/CSScriptSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -527,17 +527,19 @@ private static NameSyntax GetNameSyntax(Type type, List<Type> genericArguments)
return QualifiedName(GetNameSyntax(declaringType, declaringTypeGenericArguments), simpleName);
}

private static Type GetArrayElementType(Type type)
protected static Type GetArrayElementType(Type type)
=> type.IsArray ? GetArrayElementType(type.GetElementType()) : type;

private static IEnumerable<ArrayRankSpecifierSyntax> GetArrayRanks(Type type)
protected static IEnumerable<ArrayRankSpecifierSyntax> GetArrayRanks(Type type)
=> type == null || !type.IsArray
? Enumerable.Empty<ArrayRankSpecifierSyntax>()
: Enumerable.Repeat(ArrayRankSpecifier(
SeparatedList<ExpressionSyntax>(
ToCommaSeparatedList(
Enumerable.Repeat(OmittedArraySizeExpression(), type.GetArrayRank())))),
count: 1)
: new[]
{
ArrayRankSpecifier(
SeparatedList<ExpressionSyntax>(
ToCommaSeparatedList(
Enumerable.Repeat(OmittedArraySizeExpression(), type.GetArrayRank()))))
}
.Concat(GetArrayRanks(type.GetElementType()));

protected static TSyntax AddNewLine<TSyntax>(TSyntax expression)
Expand Down
8 changes: 3 additions & 5 deletions src/CSharpScriptSerializer/CSharpScriptSerializer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<PackageId>CSharpScriptSerializer</PackageId>
<AssemblyTitle>CSharpScriptSerializer</AssemblyTitle>
<Title>CSharpScriptSerializer</Title>
<VersionPrefix>3.0.2</VersionPrefix>
<VersionPrefix>3.0.3</VersionPrefix>
<TargetFrameworks>netstandard2.1</TargetFrameworks>
<NetStandardImplicitPackageVersion>2.0.3</NetStandardImplicitPackageVersion>
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
Expand All @@ -15,6 +15,8 @@
<PackageTags>Roslyn;CSharp;C#;CSX;Script;Serialization</PackageTags>
<PackageReleaseNotes>
<![CDATA[
Version 3.0.3
* Simplify empty collections
Version 3.0.2
* Remove trailing new line
Version 3.0.0
Expand All @@ -29,10 +31,6 @@ Version 1.5.0
* Update to Roslyn V2.8.0
Version 1.4.0
* Add support for ValueTuple, Type and plain Object
Version 1.3.0
* Update to Roslyn V2.3.1
Version 1.2.0
* Update to Roslyn V2
]]>
</PackageReleaseNotes>
<PackageProjectUrl>https://github.com/AndriySvyryd/CSharpScriptSerializer</PackageProjectUrl>
Expand Down
20 changes: 13 additions & 7 deletions src/CSharpScriptSerializer/CollectionCSScriptSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,19 @@ public CollectionCSScriptSerializer(
public override ExpressionSyntax GetCreation(object obj) => GetObjectCreationExpression((T)obj);

protected override ObjectCreationExpressionSyntax GetObjectCreationExpression(T obj)
=> base.GetObjectCreationExpression(obj)
.WithInitializer(AddNewLine(
SyntaxFactory.InitializerExpression(
SyntaxKind.CollectionInitializerExpression,
SyntaxFactory.SeparatedList<ExpressionSyntax>(
ToCommaSeparatedList(_getEnumerable(obj)
.Select(GetElementExpression))))));
{
var list = _getEnumerable(obj).ToList();
return list.Count == 0
? base.GetObjectCreationExpression(obj)
.WithArgumentList(SyntaxFactory.ArgumentList())
: base.GetObjectCreationExpression(obj)
.WithInitializer(AddNewLine(
SyntaxFactory.InitializerExpression(
SyntaxKind.CollectionInitializerExpression,
SyntaxFactory.SeparatedList<ExpressionSyntax>(
ToCommaSeparatedList(list
.Select(GetElementExpression))))));
}

protected virtual ExpressionSyntax GetElementExpression(object element)
=> _elementDecomposers == null
Expand Down
8 changes: 5 additions & 3 deletions src/CSharpScriptSerializer/ConstructorCSScriptSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,12 @@ public ConstructorCSScriptSerializer(IReadOnlyCollection<Func<T, object>> constr
public override ExpressionSyntax GetCreation(object obj) => GetObjectCreationExpression((T)obj);

protected virtual ObjectCreationExpressionSyntax GetObjectCreationExpression(T obj)
=> GetObjectCreationExpression(obj, GenerateEmptyArgumentList);

protected virtual ObjectCreationExpressionSyntax GetObjectCreationExpression(T obj, bool generateEmptyArgumentList)
=> _constructorParameterGetters == null
|| _constructorParameterGetters.Count == 0
? GenerateEmptyArgumentList
? generateEmptyArgumentList
? GetObjectCreationExpression().WithArgumentList(SyntaxFactory.ArgumentList())
: GetObjectCreationExpression()
: GetObjectCreationExpression()
Expand All @@ -43,7 +46,6 @@ protected virtual ObjectCreationExpressionSyntax GetObjectCreationExpression(T o
SyntaxFactory.Argument(GetCreationExpression(a(obj)))))))));

protected virtual ObjectCreationExpressionSyntax GetObjectCreationExpression()
=> _objectCreationExpression ??
(_objectCreationExpression = SyntaxFactory.ObjectCreationExpression(GetTypeSyntax(Type)));
=>_objectCreationExpression ??= SyntaxFactory.ObjectCreationExpression(GetTypeSyntax(Type));
}
}
28 changes: 17 additions & 11 deletions src/CSharpScriptSerializer/PropertyCSScriptSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,17 +181,23 @@ public override ExpressionSyntax GetCreation(object obj)
}

protected override ObjectCreationExpressionSyntax GetObjectCreationExpression(T obj)
=> base.GetObjectCreationExpression(obj)
.WithInitializer(AddNewLine(
InitializerExpression(
SyntaxKind.ObjectInitializerExpression,
SeparatedList<ExpressionSyntax>(
ToCommaSeparatedList(_propertyData
.Where(p => p.PropertyCondition(obj, p.PropertyValueGetter(obj)))
.Select(p => AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression,
IdentifierName(p.PropertyName),
GetCreationExpression(p.PropertyValueGetter(obj)))))))));
{
var properties = _propertyData
.Where(p => p.PropertyCondition(obj, p.PropertyValueGetter(obj)))
.Select(p => AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression,
IdentifierName(p.PropertyName),
GetCreationExpression(p.PropertyValueGetter(obj)))).ToList();

var expression = base.GetObjectCreationExpression(obj, generateEmptyArgumentList: properties.Count == 0)
.WithInitializer(AddNewLine(
InitializerExpression(
SyntaxKind.ObjectInitializerExpression,
SeparatedList<ExpressionSyntax>(
ToCommaSeparatedList(properties)))));

return expression;
}

protected static Func<T, object> CreatePropertyValueGetter(PropertyInfo property)
{
Expand Down
2 changes: 1 addition & 1 deletion test/CSharpScriptSerializer.Tests/NegativeScenarioTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace CSharpScriptSerialization.Tests
public class NegativeScenarioTest
{
[Fact]
public void NousableProperties()
public void NoUsableProperties()
{
var input = new Private();

Expand Down
45 changes: 33 additions & 12 deletions test/CSharpScriptSerializer.Tests/RoundTrippingTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -169,17 +169,13 @@ public void CombinedFlagsEnum()
+ typeof(RoundtrippingTest).Name + "." + typeof(FlagsEnum).Name + "." + FlagsEnum.SecondAndThird, script);
}

[Fact]
public void VerbatimStrings()
{
ValidateStringLiteral("\r", verbatim: true);
ValidateStringLiteral("\n", verbatim: true);
ValidateStringLiteral("\"", verbatim: false);
ValidateStringLiteral("@", verbatim: false);
ValidateStringLiteral("A", verbatim: false);
}

private void ValidateStringLiteral(string input, bool verbatim)
[Theory]
[InlineData("\r", true)]
[InlineData("\n", true)]
[InlineData("\"", false)]
[InlineData("@", false)]
[InlineData("A", false)]
public void VerbatimStrings(string input, bool verbatim)
{
var script = CSScriptSerializer.Serialize(input);
Assert.Equal(verbatim ? '@' : '"', script[0]);
Expand All @@ -188,6 +184,16 @@ private void ValidateStringLiteral(string input, bool verbatim)
Assert.Equal(input, output);
}

[Fact]
public void EmptyCollections()
{
Validate(new int?[,] { });
Validate(new List<string[]>[] { });
Validate(new object[][] { });
Validate(new List<string>());
Validate(new Dictionary<bool, bool?>());
}

[Fact]
public void LongString()
{
Expand All @@ -211,8 +217,15 @@ public void LongString()
17
18
19";

Validate(input);
}

private static void Validate<T>(T input)
{
var script = CSScriptSerializer.Serialize(input);
var output = CSScriptSerializer.Deserialize<string>(script);
var output = CSScriptSerializer.Deserialize<T>(script);

Assert.Equal(input, output);
}

Expand Down Expand Up @@ -349,6 +362,14 @@ public void OverridenProperties()

Assert.Equal(input.Property, output.Property);
Assert.Equal(input.GetSetCount(), output.GetSetCount());

input = new OverrideDerived();

script = CSScriptSerializer.Serialize(input);
output = CSScriptSerializer.Deserialize<OverrideDerived>(script);

Assert.Equal(input.Property, output.Property);
Assert.Equal(input.GetSetCount(), output.GetSetCount());
}

public class OverrideDerived : HiddenBase
Expand Down

0 comments on commit f9d834b

Please # to comment.