Skip to content

Commit

Permalink
fix(http-client-csharp): fix the int/float literals are generated as …
Browse files Browse the repository at this point in the history
…strings (#3248)

Fixes Azure/autorest.csharp#4630

This PR also includes a refactor to remove the
constant/reference/ReferenceOrConstant class, because we now have
expressions and statements, we could fully express those concepts using
the expressions/statements therefore we do not need these pre-expression
era things.
  • Loading branch information
ArcturusZhang authored May 8, 2024
1 parent 6d0e2ac commit eb8e34a
Show file tree
Hide file tree
Showing 23 changed files with 98 additions and 350 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,28 +27,28 @@ public partial class RoundTripModel
public Thing RequiredModel { get; set; }

/// <summary> this is an int based extensible enum. </summary>
public string IntExtensibleEnum { get; set; }
public int IntExtensibleEnum { get; set; }

/// <summary> this is a collection of int based extensible enum. </summary>
public IList<string> IntExtensibleEnumCollection { get; }
public IList<int> IntExtensibleEnumCollection { get; }

/// <summary> this is a float based extensible enum. </summary>
public string FloatExtensibleEnum { get; set; }
public int FloatExtensibleEnum { get; set; }

/// <summary> this is a collection of float based extensible enum. </summary>
public IList<string> FloatExtensibleEnumCollection { get; }
public IList<int> FloatExtensibleEnumCollection { get; }

/// <summary> this is a float based fixed enum. </summary>
public string FloatFixedEnum { get; set; }
public float FloatFixedEnum { get; set; }

/// <summary> this is a collection of float based fixed enum. </summary>
public IList<string> FloatFixedEnumCollection { get; }
public IList<float> FloatFixedEnumCollection { get; }

/// <summary> this is a int based fixed enum. </summary>
public string IntFixedEnum { get; set; }
public int IntFixedEnum { get; set; }

/// <summary> this is a collection of int based fixed enum. </summary>
public IList<string> IntFixedEnumCollection { get; }
public IList<int> IntFixedEnumCollection { get; }

/// <summary> this is a string based fixed enum. </summary>
public string StringFixedEnum { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ public partial class Thing
public string RequiredLiteralString { get; } = "accept";

/// <summary> required literal int. </summary>
public string RequiredLiteralInt { get; set; } = "123";
public int RequiredLiteralInt { get; } = 123;

/// <summary> required literal float. </summary>
public string RequiredLiteralFloat { get; set; } = "1.23";
public float RequiredLiteralFloat { get; } = 1.23F;

/// <summary> required literal bool. </summary>
public bool RequiredLiteralBool { get; } = false;
Expand All @@ -33,10 +33,10 @@ public partial class Thing
public string OptionalLiteralString { get; set; }

/// <summary> optional literal int. </summary>
public string OptionalLiteralInt { get; set; }
public int OptionalLiteralInt { get; set; }

/// <summary> optional literal float. </summary>
public string OptionalLiteralFloat { get; set; }
public float OptionalLiteralFloat { get; set; }

/// <summary> optional literal bool. </summary>
public bool OptionalLiteralBool { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ internal class ScmTypeFactory : TypeFactory
//InputEnumType enumType => ClientModelPlugin.Instance.OutputLibrary.EnumMappings.TryGetValue(enumType, out var provider)
//? provider.Type.WithNullable(inputType.IsNullable)
//: throw new InvalidOperationException($"No {nameof(EnumType)} has been created for `{enumType.Name}` {nameof(InputEnumType)}."),
InputEnumType enumType => new CSharpType(typeof(string), inputType.IsNullable),
// TODO -- this is temporary until we have support for enums
InputEnumType enumType => CreateCSharpType(enumType.EnumValueType).WithNullable(enumType.IsNullable),
InputModelType model => ClientModelPlugin.Instance.OutputLibrary.ModelMappings.TryGetValue(model, out var provider)
? provider.Type.WithNullable(inputType.IsNullable)
: new CSharpType(typeof(object), model.IsNullable).WithNullable(inputType.IsNullable),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
Expand All @@ -25,9 +25,9 @@ public class CSharpType
private bool _isEnum;
private bool _isNullable;
private bool _isPublic;
private bool? _isUnion;
private IReadOnlyList<CSharpType> _arguments;
private IReadOnlyList<CSharpType> _unionItemTypes;
private object? _literal;
private IReadOnlyList<CSharpType>? _unionItemTypes;

private bool? _isReadOnlyMemory;
private bool? _isList;
Expand Down Expand Up @@ -143,7 +143,6 @@ internal CSharpType(TypeProvider implementation, bool isValueType = false, bool
[MemberNotNull(nameof(_namespace))]
[MemberNotNull(nameof(_arguments))]
[MemberNotNull(nameof(_isPublic))]
[MemberNotNull(nameof(_unionItemTypes))]
private void Initialize(string? name, bool isValueType, bool isEnum, bool isNullable, string? ns,
CSharpType? declaringType, IReadOnlyList<CSharpType>? args, bool isPublic)
{
Expand All @@ -155,23 +154,22 @@ private void Initialize(string? name, bool isValueType, bool isEnum, bool isNull
_declaringType = declaringType;
_arguments = args ?? Array.Empty<CSharpType>();
_isPublic = isPublic;
_unionItemTypes ??= Array.Empty<CSharpType>();
}

public string Namespace { get { return _namespace; } }
public string Name { get { return _name; } }
public CSharpType? DeclaringType { get { return _declaringType; } }
public bool IsValueType { get { return _isValueType; } }
public bool IsEnum { get { return _isEnum; } }
public bool IsLiteral => Literal is not null;
public bool IsUnion => _isUnion ??= UnionItemTypes.Count > 0;
public bool IsLiteral => _literal is not null;
public bool IsUnion => _unionItemTypes?.Count > 0;
public bool IsPublic { get { return _isPublic; } }
public bool IsFrameworkType => _type != null;
public bool IsNullable { get { return _isNullable; } }
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; }
public object Literal => _literal ?? throw new InvalidOperationException("Not a literal type");
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 All @@ -180,7 +178,7 @@ private void Initialize(string? name, bool isValueType, bool isEnum, bool isNull
public CSharpType InputType => _inputType ??= GetInputType();
public CSharpType OutputType => _outputType ??= GetOutputType();
public Type? SerializeAs { get; init; }
public IReadOnlyList<CSharpType> UnionItemTypes { get { return _unionItemTypes; } private init { _unionItemTypes = value; } }
public IReadOnlyList<CSharpType> UnionItemTypes => _unionItemTypes ?? throw new InvalidOperationException("Not a union type");

private bool TypeIsReadOnlyMemory()
=> IsFrameworkType && _type == typeof(ReadOnlyMemory<>);
Expand Down Expand Up @@ -471,11 +469,18 @@ public CSharpType GetGenericTypeDefinition()
/// </summary>
/// <param name="isNullable">Flag to determine if the new type is nullable.</param>
/// <returns>The existing <see cref="CSharpType"/> if it is nullable, otherwise a new instance of <see cref="CSharpType"/>.</returns>
public CSharpType WithNullable(bool isNullable) =>
isNullable == IsNullable ? this : IsFrameworkType
public CSharpType WithNullable(bool isNullable)
{
var type = isNullable == IsNullable ? this : IsFrameworkType
? new CSharpType(FrameworkType, Arguments, isNullable)
: new CSharpType(Implementation, isValueType: IsValueType, isEnum: IsEnum, isNullable: isNullable, arguments: Arguments, declaringType: DeclaringType, ns: Namespace, name: Name);

type._literal = _literal;
type._unionItemTypes = _unionItemTypes;

return type;
}

public static implicit operator CSharpType(Type type) => new CSharpType(type);

public sealed override string ToString()
Expand Down Expand Up @@ -541,20 +546,10 @@ public static CSharpType FromLiteral(CSharpType type, object literalValue)
{
if (type.IsFrameworkType)
{
Constant? literal;
try
{
literal = new Constant(literalValue, type);
}
catch
{
literal = null;
}
var literalType = new CSharpType(type.FrameworkType, type.IsNullable);
literalType._literal = literalValue;

return new CSharpType(type.FrameworkType, type.IsNullable)
{
Literal = literal
};
return literalType;
}

throw new NotSupportedException("Literals are not supported in non-framework type");
Expand All @@ -568,10 +563,10 @@ public static CSharpType FromLiteral(CSharpType type, object literalValue)
/// <returns>A <see cref="CSharpType"/> instance representing those unioned types.</returns>
public static CSharpType FromUnion(IReadOnlyList<CSharpType> unionItemTypes, bool isNullable)
{
return new CSharpType(typeof(BinaryData), isNullable)
{
UnionItemTypes = unionItemTypes
};
var type = new CSharpType(typeof(BinaryData), isNullable);
type._unionItemTypes = unionItemTypes;

return type;
}

public CSharpType MakeGenericType(IReadOnlyList<CSharpType> arguments)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

namespace Microsoft.Generator.CSharp.Expressions
{
public sealed record DiagnosticScopeMethodBodyBlock(Diagnostic Diagnostic, Reference ClientDiagnosticsReference, MethodBodyStatement InnerStatement) : MethodBodyStatement;
public sealed record DiagnosticScopeMethodBodyBlock(Diagnostic Diagnostic, ValueExpression ClientDiagnosticsReference, MethodBodyStatement InnerStatement) : MethodBodyStatement;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
Expand All @@ -14,15 +14,18 @@ public static partial class Snippets
public static MethodBodyStatement AsStatement(this IEnumerable<MethodBodyStatement> statements) => statements.ToArray();

public static ValueExpression Dash { get; } = new KeywordExpression("_", null);

public static ValueExpression DefaultOf(CSharpType type) => type is { IsValueType: true, IsNullable: false } ? Default.CastTo(type) : Null.CastTo(type);

public static ValueExpression Default { get; } = new KeywordExpression("default", null);
public static ValueExpression Null { get; } = new KeywordExpression("null", null);
public static ValueExpression This { get; } = new KeywordExpression("this", null);
public static BoolExpression True { get; } = new(new KeywordExpression("true", null));
public static BoolExpression False { get; } = new(new KeywordExpression("false", null));

public static BoolExpression Bool(bool value) => value ? True : False;
public static IntExpression Int(int value) => new IntExpression(Literal(value));
public static LongExpression Long(long value) => new LongExpression(Literal(value));
public static IntExpression Int(int value) => new(Literal(value));
public static LongExpression Long(long value) => new(Literal(value));
public static ValueExpression Float(float value) => new FormattableStringToExpression($"{value}f");
public static ValueExpression Double(double value) => new FormattableStringToExpression($"{value}d");

Expand All @@ -46,7 +49,7 @@ public static ValueExpression RemoveAllNullConditional(ValueExpression expressio
public static TypedValueExpression RemoveAllNullConditional(TypedValueExpression expression)
=> expression with { Untyped = RemoveAllNullConditional(expression.Untyped) };

public static ValueExpression Literal(object? value) => new FormattableStringToExpression($"{value:L}");
public static ValueExpression Literal(object? value) => new LiteralExpression(value);

public static StringExpression Literal(string? value) => new(value is null ? Null : new StringLiteralExpression(value, false));
public static StringExpression LiteralU8(string value) => new(new StringLiteralExpression(value, true));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

namespace Microsoft.Generator.CSharp.Expressions
Expand All @@ -9,9 +9,9 @@ public sealed record BoolExpression(ValueExpression Untyped) : TypedValueExpress

public BoolExpression And(ValueExpression other) => new(new BinaryOperatorExpression(" && ", this, other));

public static BoolExpression True => new(new ConstantExpression(new Constant(true, typeof(bool))));
public static BoolExpression True { get; } = Snippets.True;

public static BoolExpression False => new(new ConstantExpression(new Constant(false, typeof(bool))));
public static BoolExpression False { get; } = Snippets.False;

public static BoolExpression Is(ValueExpression untyped, CSharpType comparisonType) => new(new BinaryOperatorExpression("is", untyped, comparisonType));

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

namespace Microsoft.Generator.CSharp.Expressions
{
/// <summary>
/// Represents a literal expression.
/// </summary>
/// <param name="Literal">The literal value.</param>
public sealed record LiteralExpression(object? Literal) : ValueExpression
{
public override void Write(CodeWriter writer)
{
writer.WriteLiteral(Literal);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
Expand All @@ -17,7 +17,7 @@ public abstract record TypedValueExpression(CSharpType Type, ValueExpression Unt
public static implicit operator TypedValueExpression(FieldDeclaration name) => new VariableReference(name.Type, name.Declaration);
public static implicit operator TypedValueExpression(Parameter parameter) => new ParameterReference(parameter);

public TypedValueExpression NullableStructValue() => this is not ConstantExpression && Type is { IsNullable: true, IsValueType: true } ? new TypedMemberExpression(this, nameof(Nullable<int>.Value), Type.WithNullable(false)) : this;
public TypedValueExpression NullableStructValue() => Type is { IsNullable: true, IsValueType: true } ? new TypedMemberExpression(this, nameof(Nullable<int>.Value), Type.WithNullable(false)) : this;

public TypedValueExpression NullConditional() => Type.IsNullable ? new TypedNullConditionalExpression(this) : this;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
Expand All @@ -20,7 +20,7 @@ public virtual void Write(CodeWriter writer) { }
public static implicit operator ValueExpression(FieldDeclaration name) => new VariableReference(name.Type, name.Declaration);
public static implicit operator ValueExpression(PropertyDeclaration name) => new VariableReference(name.PropertyType, name.Declaration);

public ValueExpression NullableStructValue(CSharpType candidateType) => this is not ConstantExpression && candidateType is { IsNullable: true, IsValueType: true } ? new MemberExpression(this, nameof(Nullable<int>.Value)) : this;
public ValueExpression NullableStructValue(CSharpType candidateType) => candidateType is { IsNullable: true, IsValueType: true } ? new MemberExpression(this, nameof(Nullable<int>.Value)) : this;
public StringExpression InvokeToString() => new(Invoke(nameof(ToString)));
public ValueExpression InvokeGetType() => Invoke(nameof(GetType));

Expand Down
Loading

0 comments on commit eb8e34a

Please sign in to comment.