Skip to content

Commit

Permalink
sync up changes from microsoft/typespec#3567
Browse files Browse the repository at this point in the history
  • Loading branch information
ArcturusZhang committed Jun 12, 2024
1 parent 0018fa9 commit afe1c87
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 3 deletions.
16 changes: 13 additions & 3 deletions src/AutoRest.CSharp/Common/Generation/Types/CSharpType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ namespace AutoRest.CSharp.Generation.Types
/// CSharpType represents the C# type of an input type.
/// It is constructed from a <see cref="Type"/> and its properties.
/// </summary>
internal class CSharpType
public class CSharpType
{
private readonly TypeProvider? _implementation;
private readonly Type? _type;
Expand Down Expand Up @@ -121,6 +121,16 @@ public CSharpType(Type type, IReadOnlyList<CSharpType> arguments, bool isNullabl
{
Debug.Assert(type.Namespace != null, "type.Namespace != null");

// handle nullable value types explicitly because they are implemented using generic type `System.Nullable<T>`
var underlyingValueType = Nullable.GetUnderlyingType(type);
if (underlyingValueType != null)
{
// in this block, we are converting input like `typeof(int?)` into the way as if they input: `typeof(int), isNullable: true`
type = underlyingValueType;
arguments = type.IsGenericType ? type.GetGenericArguments().Select(p => new CSharpType(p)).ToArray() : Array.Empty<CSharpType>();
isNullable = true;
}

_type = type.IsGenericType ? type.GetGenericTypeDefinition() : type;
ValidateArguments(_type, arguments);

Expand Down Expand Up @@ -149,7 +159,7 @@ private static void ValidateArguments(Type type, IReadOnlyList<CSharpType> argum
}
}

public CSharpType(TypeProvider implementation, IReadOnlyList<CSharpType>? arguments = null, bool isNullable = false)
internal CSharpType(TypeProvider implementation, IReadOnlyList<CSharpType>? arguments = null, bool isNullable = false)
{
_implementation = implementation;
_arguments = arguments ?? Array.Empty<CSharpType>();
Expand Down Expand Up @@ -206,7 +216,7 @@ private void Initialize(string? name, bool isValueType, bool isEnum, bool isNull
public bool IsGenericType => Arguments.Count > 0;
public bool IsCollection => _isCollection ??= TypeIsCollection();
public Type FrameworkType => _type ?? throw new InvalidOperationException("Not a framework type");
public Constant? Literal { get; private init; }
internal Constant? Literal { get; private init; }
internal TypeProvider Implementation => _implementation ?? throw new InvalidOperationException($"Not implemented type: '{Namespace}.{Name}'");
public IReadOnlyList<CSharpType> Arguments { get { return _arguments; } }
public CSharpType InitializationType => _initializationType ??= GetImplementationType();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,5 +213,72 @@ private class TestAsyncPageable<T> : AsyncPageable<T> where T : notnull
public TestAsyncPageable(IAsyncEnumerable<Page<T>> enumerable) => _enumerable = enumerable;
public override IAsyncEnumerable<Page<T>> AsPages(string? continuationToken = null, int? pageSizeHint = null) => _enumerable;
}

[TestCaseSource(nameof(ValidateNullableTypesData))]
public void ValidateNullableTypes(Type type, IReadOnlyList<CSharpType> expectedArguments, bool expectedIsNullable)
{
var csharpType = new CSharpType(type);

CollectionAssert.AreEqual(expectedArguments, csharpType.Arguments);
Assert.AreEqual(expectedIsNullable, csharpType.IsNullable);
}

private static object[] ValidateNullableTypesData = new[]
{
new object[]
{
typeof(int), Array.Empty<CSharpType>(), false
},
new object[]
{
typeof(int?), Array.Empty<CSharpType>(), true
},
new object[]
{
typeof(Uri), Array.Empty<CSharpType>(), false
},
new object[]
{
typeof(Guid), Array.Empty<CSharpType>(), false
},
new object[]
{
typeof(Guid?), Array.Empty<CSharpType>(), true
},
new object[]
{
typeof(TestStruct<int>), new CSharpType[] { typeof(int) }, false
},
new object[]
{
typeof(TestStruct<int>?), new CSharpType[] { typeof(int) }, true
},
new object[]
{
typeof(TestStruct<int?>), new CSharpType[] { typeof(int?) }, false
},
new object[]
{
typeof(TestStruct<int?>?), new CSharpType[] { typeof(int?) }, true
},
new object[]
{
typeof(TestStruct<TestStruct<int>>), new CSharpType[] { typeof(TestStruct<int>) }, false
},
new object[]
{
typeof(TestStruct<TestStruct<int>>?), new CSharpType[] { typeof(TestStruct<int>) }, true
},
new object[]
{
typeof(TestStruct<TestStruct<int>?>), new CSharpType[] { typeof(TestStruct<int>?) }, false
},
new object[]
{
typeof(TestStruct<TestStruct<int>?>?), new CSharpType[] { typeof(TestStruct<int>?) }, true
},
};

internal struct TestStruct<T> { }
}
}

0 comments on commit afe1c87

Please sign in to comment.