Skip to content
This repository was archived by the owner on May 16, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions src/ZeroFormatter.Analyzer/ZeroFormatterAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ public class ZeroFormatterAnalyzer : DiagnosticAnalyzer
internal const string UnionAttributeShortName = "UnionAttribute";
internal const string DynamicUnionAttributeShortName = "DynamicUnionAttribute";
internal const string UnionKeyAttributeShortName = "UnionKeyAttribute";
internal const string ZeroFormattableFormatterProperty = "FormatterType";
internal const string FormatterTypeName = "Formatter";

internal static readonly DiagnosticDescriptor TypeMustBeZeroFormattable = new DiagnosticDescriptor(
id: DiagnosticIdBase + "_" + nameof(TypeMustBeZeroFormattable), title: Title, category: Category,
Expand Down Expand Up @@ -102,6 +104,12 @@ public class ZeroFormatterAnalyzer : DiagnosticAnalyzer
description: "All Union subTypes must be inherited type.",
defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true);

internal static readonly DiagnosticDescriptor ExplicitFormatterMustInheritFormatter = new DiagnosticDescriptor(
id: DiagnosticIdBase + "_" + nameof(ExplicitFormatterMustInheritFormatter), title: Title, category: Category,
messageFormat: "Explicit Formatter type must inherit from Formatter<>. Type: {0}, Formatter: {1}", // type.Name subType.Name
description: "Explicit Formatter type must inherit from Formatter<>.",
defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true);

static readonly ImmutableArray<DiagnosticDescriptor> supportedDiagnostics = ImmutableArray.Create(
TypeMustBeZeroFormattable,
PublicPropertyNeedsIndex,
Expand Down Expand Up @@ -164,9 +172,9 @@ static void Analyze(SyntaxNodeAnalysisContext context)
if (declaredSymbol == null) return;

var isUnion = declaredSymbol.GetAttributes().FindAttributeShortName(UnionAttributeShortName) != null;
var isZeroFormattable = declaredSymbol.GetAttributes().FindAttributeShortName(ZeroFormattableAttributeShortName) != null;
var zeroFormattableAttribute = declaredSymbol.GetAttributes().FindAttributeShortName(ZeroFormattableAttributeShortName);

if (!isUnion && !isZeroFormattable)
if (!isUnion && zeroFormattableAttribute == null)
{
return;
}
Expand All @@ -176,8 +184,21 @@ static void Analyze(SyntaxNodeAnalysisContext context)
{
VerifyUnion(reportContext, typeDeclaration.GetLocation(), declaredSymbol);
}
if (isZeroFormattable)
if (zeroFormattableAttribute != null)
{
var explicitFormatter =
zeroFormattableAttribute.NamedArguments.Where(
x => x.Key == ZeroFormattableFormatterProperty);
if (explicitFormatter.Any())
{
if (explicitFormatter.First().Value.Type.BaseType.Name != FormatterTypeName)
reportContext.Add(Diagnostic.Create(ExplicitFormatterMustInheritFormatter,
typeDeclaration.GetLocation(), typeDeclaration.GetLocation(),
explicitFormatter.First().Value.Type));

return;
}

VerifyType(reportContext, typeDeclaration.GetLocation(), declaredSymbol, new HashSet<ITypeSymbol>(), null);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="System.Runtime" Version="4.1.0" />
<PackageReference Include="System.Linq" Version="4.1.0" />
<PackageReference Include="System.Runtime" Version="4.3.0" />
<PackageReference Include="System.Linq" Version="4.3.0" />
</ItemGroup>

</Project>
1 change: 1 addition & 0 deletions src/ZeroFormatter.Interfaces/Attributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace ZeroFormatter
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = true)]
public class ZeroFormattableAttribute : Attribute
{
public Type FormatterType { get; set; }
}

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
Expand Down
28 changes: 14 additions & 14 deletions src/ZeroFormatter.NETCore/ZeroFormatter.NETCore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,20 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="System.Reflection.Emit" Version="4.0.1" />
<PackageReference Include="System.Runtime" Version="4.1.0" />
<PackageReference Include="System.Runtime.Extensions" Version="4.1.0" />
<PackageReference Include="System.Collections" Version="4.0.11" />
<PackageReference Include="System.Linq" Version="4.1.0" />
<PackageReference Include="System.Linq.Expressions" Version="4.1.0" />
<PackageReference Include="System.Runtime.InteropServices" Version="4.1.0" />
<PackageReference Include="System.Reflection" Version="4.1.0" />
<PackageReference Include="System.Reflection.Extensions" Version="4.0.1" />
<PackageReference Include="System.Threading" Version="4.0.11" />
<PackageReference Include="System.Text.Encoding" Version="4.0.11" />
<PackageReference Include="System.Text.Encoding.Extensions" Version="4.0.11" />
<PackageReference Include="System.Collections.Concurrent" Version="4.0.12" />
<PackageReference Include="System.ObjectModel" Version="4.0.12" />
<PackageReference Include="System.Reflection.Emit" Version="4.3.0" />
<PackageReference Include="System.Runtime" Version="4.3.0" />
<PackageReference Include="System.Runtime.Extensions" Version="4.3.0" />
<PackageReference Include="System.Collections" Version="4.3.0" />
<PackageReference Include="System.Linq" Version="4.3.0" />
<PackageReference Include="System.Linq.Expressions" Version="4.3.0" />
<PackageReference Include="System.Runtime.InteropServices" Version="4.3.0" />
<PackageReference Include="System.Reflection" Version="4.3.0" />
<PackageReference Include="System.Reflection.Extensions" Version="4.3.0" />
<PackageReference Include="System.Threading" Version="4.3.0" />
<PackageReference Include="System.Text.Encoding" Version="4.3.0" />
<PackageReference Include="System.Text.Encoding.Extensions" Version="4.3.0" />
<PackageReference Include="System.Collections.Concurrent" Version="4.3.0" />
<PackageReference Include="System.ObjectModel" Version="4.3.0" />
</ItemGroup>

</Project>
28 changes: 27 additions & 1 deletion src/ZeroFormatter/Formatters/Formatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,33 @@ static Formatter()
var resolver = ResolverCache<TTypeResolver>.Default;
try
{
formatter = resolver.ResolveFormatter(t);

#if NET_CORE
var ti = t.GetTypeInfo();
#else
var ti = t;
#endif
var attribute = (ZeroFormattableAttribute) ti.GetCustomAttributes(typeof(ZeroFormattableAttribute))
.FirstOrDefault();
if (attribute != null && attribute.FormatterType != null)
{
Type[] genericArguments;
if (ti.IsGenericType)
{
var classTypes = ti.GetGenericArguments();
genericArguments = new Type[1 + classTypes.Length];
genericArguments[0] = typeof(TTypeResolver);
Array.Copy(classTypes, 0, genericArguments, 1, classTypes.Length);
}
else
genericArguments = new[] {typeof(TTypeResolver)};

formatter = Activator.CreateInstance(
attribute.FormatterType.MakeGenericType(genericArguments));
}

if (formatter == null)
formatter = resolver.ResolveFormatter(t);

// If Unity, should avoid long static constructor and <T> code because IL2CPP generate every <T>.
if (formatter == null && resolver.IsUseBuiltinSerializer)
Expand Down
1 change: 1 addition & 0 deletions tests/ZeroFormatter.Tests/ZeroFormatter.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
<Compile Include="EqTest.cs" />
<Compile Include="VersiongTest.cs" />
<Compile Include="ZeroArgumentTest.cs" />
<Compile Include="ZeroFormatterAttributeTest.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="ChainingAssertion.Ext.cs" />
Expand Down
55 changes: 55 additions & 0 deletions tests/ZeroFormatter.Tests/ZeroFormatterAttributeTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ZeroFormatter.Formatters;
using ZeroFormatter.Internal;

namespace ZeroFormatter.Tests
{
[TestClass]
public class ZeroFormatterAttributeTest
{
[TestMethod]
public void Serialize()
{
var customClass = new CustomClass("Hello World");

var data = ZeroFormatterSerializer.Serialize(customClass);
var result = ZeroFormatterSerializer.Deserialize<CustomClass>(data);
result.Test.Is(customClass.Test);
}

[ZeroFormattable(FormatterType = typeof(CustomClassFormatter<>))]
public class CustomClass
{
public CustomClass(string test)
{
Test = test;
}

public string Test { get; }
}

public class CustomClassFormatter<TTypeResolver> : Formatter<TTypeResolver, CustomClass>
where TTypeResolver : ITypeResolver, new()
{
public override int? GetLength()
{
return null;
}

public override int Serialize(ref byte[] bytes, int offset, CustomClass value)
{
var stringLength = BinaryUtil.WriteString(ref bytes, offset + 4, value.Test);
BinaryUtil.WriteInt32Unsafe(ref bytes, offset, stringLength);
return stringLength + 4;
}

public override CustomClass Deserialize(ref byte[] bytes, int offset, DirtyTracker tracker,
out int byteSize)
{
var length = BinaryUtil.ReadInt32(ref bytes, offset);
byteSize = 4 + length;
return new CustomClass(BinaryUtil.ReadString(ref bytes, offset + 4, length));
}
}
}
}