Skip to content
Merged
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
50 changes: 39 additions & 11 deletions NewType.Generator/AliasCodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -751,28 +751,49 @@ private void AppendSerializationConverters()
_sb.AppendLine($"{indent}#region Serialization");
_sb.AppendLine();

// When T is string, typeof(T) == typeof(string); emit only the string arm to avoid
// duplicate conditions and unreachable branches.
var aliasedIsString = _model.AliasedTypeSpecialType == SpecialType.System_String;

// TypeConverter — covers Newtonsoft.Json, ASP.NET model binding, configuration binding, etc.
_sb.AppendLine($"{indent}/// <summary>Converts {name} to and from {minimal} and string.</summary>");
_sb.AppendLine($"{indent}public sealed class NewtypeTypeConverter : global::System.ComponentModel.TypeConverter");
_sb.AppendLine($"{indent}{{");
if (!aliasedIsString)
{
// Resolve the underlying type's converter once — TypeDescriptor lookups aren't free.
_sb.AppendLine($"{inner}private static readonly global::System.ComponentModel.TypeConverter _inner = global::System.ComponentModel.TypeDescriptor.GetConverter(typeof({t}));");
_sb.AppendLine();
}
_sb.AppendLine($"{inner}/// <inheritdoc/>");
_sb.AppendLine($"{inner}public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType)");
_sb.AppendLine($"{body}=> sourceType == typeof(string) || sourceType == typeof({t}) || base.CanConvertFrom(context, sourceType);");
_sb.AppendLine(aliasedIsString
? $"{body}=> sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);"
: $"{body}=> sourceType == typeof(string) || sourceType == typeof({t}) || base.CanConvertFrom(context, sourceType);");
_sb.AppendLine();
_sb.AppendLine($"{inner}/// <inheritdoc/>");
_sb.AppendLine($"{inner}public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? destinationType)");
_sb.AppendLine($"{body}=> destinationType == typeof(string) || destinationType == typeof({t}) || base.CanConvertTo(context, destinationType);");
_sb.AppendLine(aliasedIsString
? $"{body}=> destinationType == typeof(string) || base.CanConvertTo(context, destinationType);"
: $"{body}=> destinationType == typeof(string) || destinationType == typeof({t}) || base.CanConvertTo(context, destinationType);");
_sb.AppendLine();
_sb.AppendLine($"{inner}/// <inheritdoc/>");
_sb.AppendLine($"{inner}public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value)");
_sb.AppendLine($"{inner}{{");
_sb.AppendLine($"{body}if (value is {t} unwrapped) return new {name}(unwrapped);");
_sb.AppendLine($"{body}if (value is string text)");
_sb.AppendLine($"{body}{{");
_sb.AppendLine($"{body} var converted = global::System.ComponentModel.TypeDescriptor.GetConverter(typeof({t})).ConvertFromString(context, culture, text);");
_sb.AppendLine($"{body} if (converted is null) return null;");
_sb.AppendLine($"{body} return new {name}(({t})converted);");
_sb.AppendLine($"{body}}}");
if (aliasedIsString)
{
_sb.AppendLine($"{body}if (value is string unwrapped) return new {name}(unwrapped);");
}
else
{
_sb.AppendLine($"{body}if (value is {t} unwrapped) return new {name}(unwrapped);");
_sb.AppendLine($"{body}if (value is string text)");
_sb.AppendLine($"{body}{{");
_sb.AppendLine($"{body} var converted = _inner.ConvertFromString(context, culture, text);");
_sb.AppendLine($"{body} if (converted is null) return null;");
_sb.AppendLine($"{body} return new {name}(({t})converted);");
_sb.AppendLine($"{body}}}");
}
_sb.AppendLine($"{body}return base.ConvertFrom(context, culture, value);");
_sb.AppendLine($"{inner}}}");
_sb.AppendLine();
Expand All @@ -781,8 +802,15 @@ private void AppendSerializationConverters()
_sb.AppendLine($"{inner}{{");
_sb.AppendLine($"{body}if (value is {name} wrapped)");
_sb.AppendLine($"{body}{{");
_sb.AppendLine($"{body} if (destinationType == typeof({t})) return wrapped._value;");
_sb.AppendLine($"{body} if (destinationType == typeof(string)) return global::System.ComponentModel.TypeDescriptor.GetConverter(typeof({t})).ConvertToString(context, culture, wrapped._value);");
if (aliasedIsString)
{
_sb.AppendLine($"{body} if (destinationType == typeof(string)) return wrapped._value;");
}
else
{
_sb.AppendLine($"{body} if (destinationType == typeof({t})) return wrapped._value;");
_sb.AppendLine($"{body} if (destinationType == typeof(string)) return _inner.ConvertToString(context, culture, wrapped._value);");
}
_sb.AppendLine($"{body}}}");
_sb.AppendLine($"{body}return base.ConvertTo(context, culture, value, destinationType);");
_sb.AppendLine($"{inner}}}");
Expand Down
14 changes: 6 additions & 8 deletions NewType.Generator/AliasModelExtractor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ private static ConstraintModel ExtractValidationMethod(ITypeSymbol targetType,

foreach (var method in targetType.GetMembers().OfType<IMethodSymbol>())
{
foreach (var attributeData in method.GetAttributes().Where(x => x is not null))
foreach (var attributeData in method.GetAttributes())
{
if (attributeData.AttributeClass!.Name == ConstraintAttributeSource.AttributeName)
{
Expand Down Expand Up @@ -470,14 +470,12 @@ private static bool ImplementsInterface(ITypeSymbol type, string interfaceFullNa
}

private static LocationInfo? ToLocationStruct(Location? location) =>
location is not null && location.IsInSource ?
new LocationInfo(
location is not null && location.IsInSource
? new LocationInfo(
location.SourceTree.FilePath,
location.SourceSpan,
new LinePositionSpan(
location.GetLineSpan().StartLinePosition,
location.GetLineSpan().EndLinePosition))
:null;
location.SourceSpan,
location.GetLineSpan().Span)
: null;
}

internal record ConstraintModel(
Expand Down
10 changes: 5 additions & 5 deletions NewType.Generator/AnalyzerReleases.Unshipped.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
; Unshipped analyzer release
; Unshipped analyzer release
; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md

### New Rules

| Rule ID | Category | Severity | Notes |
|------------|-----------|----------|----------------|
| NEWTYPE001 | `Unknown` | Error | AliasGenerator |
| NEWTYPE002 | `Unknown` | Error | AliasGenerator |
Rule ID | Category | Severity | Notes
--------|----------|----------|-------
NEWTYPE001 | Unknown | Error | AliasGenerator
NEWTYPE002 | Unknown | Error | AliasGenerator
Loading