Skip to content

Commit

Permalink
Update to consolidate parameter validation logic (#3581)
Browse files Browse the repository at this point in the history
Fixes #3486
  • Loading branch information
m-nash authored Jun 14, 2024
1 parent 808d6fd commit df3d037
Show file tree
Hide file tree
Showing 60 changed files with 893 additions and 588 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -300,10 +300,7 @@ private List<ParameterProvider> BuildSerializationConstructorParameters()

foreach (var property in _inputModel.Properties)
{
var parameter = new ParameterProvider(property)
{
Validation = ParameterValidationType.None,
};
var parameter = new ParameterProvider(property);
constructorParameters.Add(parameter);

if (shouldAddRawDataField && string.Equals(parameter.Name, _rawDataField?.Name, StringComparison.OrdinalIgnoreCase))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,13 @@ internal class SystemModelSnippets : ModelSnippets
public override MethodProvider BuildFromOperationResponseMethod(TypeProvider typeProvider, MethodSignatureModifiers modifiers)
{
var result = new ParameterProvider("response", $"The result to deserialize the model from.", typeof(PipelineResponse));
return new MethodProvider
(
return new MethodProvider(
new MethodSignature(ClientModelPlugin.Instance.Configuration.ApiTypes.FromResponseName, null, $"Deserializes the model from a raw response.", modifiers, typeProvider.Type, null, new[] { result }),
new MethodBodyStatement[]
{
Snippet.UsingVar("document", JsonDocumentSnippet.Parse(new PipelineResponseSnippet(result).Content), out var document),
Snippet.Return(TypeProviderSnippet.Deserialize(typeProvider, document.RootElement))
},
"default"
);
});
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
// Licensed under the MIT License.

using System;
using System.IO;
using System.Reflection;
using BenchmarkDotNet.Attributes;
using Microsoft.Generator.CSharp.Input;
using Microsoft.Generator.CSharp.Providers;
Expand All @@ -16,9 +14,6 @@ public class CodeWriterBenchmark

public CodeWriterBenchmark()
{
PluginHandler pluginHandler = new PluginHandler();
pluginHandler.LoadPlugin(Path.Combine(Directory.GetParent(Assembly.GetExecutingAssembly().Location)!.FullName, "Projects", "Model"));

var properties = new[]
{
new InputModelProperty("MyProperty", "myProperty", "The property of mine", new InputPrimitiveType(InputPrimitiveTypeKind.Int32, false), true, false, false)
Expand All @@ -28,6 +23,12 @@ public CodeWriterBenchmark()
_writer = new TypeProviderWriter(modelProvider);
}

[GlobalSetup]
public void GlobalSetup()
{
PluginInitializer.Initialize();
}

[Benchmark]
public void WriteModel()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Collections.Generic;
using BenchmarkDotNet.Attributes;
using Microsoft.Generator.CSharp.Providers;
using Microsoft.Generator.CSharp.Statements;
using static Microsoft.Generator.CSharp.Snippets.Snippet;

namespace Microsoft.Generator.CSharp.Perf
{
public class MethodProviderBenchmark
{
private MethodSignature Signature { get; }
private MethodBodyStatement BodyStatement = new();
private Dictionary<ParameterValidationType, List<ParameterProvider>>? ParamHash;

public MethodProviderBenchmark()
{
var parameters = new List<ParameterProvider>
{
new ParameterProvider("param1", $"param1", typeof(int)) { Validation = ParameterValidationType.None },
new ParameterProvider("param2", $"param2", typeof(string)) { Validation = ParameterValidationType.AssertNotNull }
};
Signature = new MethodSignature("name", null, null, MethodSignatureModifiers.Public, null, null, parameters);
ParamHash = GetParamhash(false);
}

[GlobalSetup]
public void GlobalSetup()
{
PluginInitializer.Initialize();
}

[Benchmark]
[BenchmarkCategory("ValidationStatements")]
public void Yieldreturn()
{
List<MethodBodyStatement> statements = [.. GetValidationStatementsWithYield()];
statements.Add(BodyStatement);
}

[Benchmark]
[BenchmarkCategory("ValidationStatements")]
public void UseList()
{
List<MethodBodyStatement> statements = [.. GetValidationStatements()];
statements.Add(BodyStatement);
}

[Benchmark]
[BenchmarkCategory("ValidationStatements")]
public void UseSingleList()
{
MethodBodyStatement statements = GetStatementsAsSingleList(BodyStatement);
}

[Benchmark]
[BenchmarkCategory("ValidationStatements")]
public void UseArray()
{
MethodBodyStatement statements = GetStatementsWithHash(BodyStatement, ParamHash);
}

private Dictionary<ParameterValidationType, List<ParameterProvider>>? GetParamhash(bool skipParamValidation)
{
Dictionary<ParameterValidationType, List<ParameterProvider>>? paramHash = null;
if (!skipParamValidation)
{
paramHash = new();
foreach (var parameter in Signature.Parameters)
{
if (parameter.Validation == ParameterValidationType.None)
continue;

if (!paramHash.ContainsKey(parameter.Validation))
paramHash[parameter.Validation] = new List<ParameterProvider>();
paramHash[parameter.Validation].Add(parameter);
}
}
return paramHash;
}

private MethodBodyStatement GetStatementsWithHash(MethodBodyStatement bodyStatements, Dictionary<ParameterValidationType, List<ParameterProvider>>? paramHash)
{
if (paramHash is null)
return bodyStatements;

int count = 0;
foreach (var kvp in paramHash)
{
if (kvp.Key == ParameterValidationType.None)
continue;
count += kvp.Value.Count;
}

if (count == 0)
{
throw new System.Exception("count is 0");
//return bodyStatements;
}

MethodBodyStatement[] statements = new MethodBodyStatement[count + 2];
int index = 0;
foreach (var parameter in Signature.Parameters)
{
if (parameter.Validation != ParameterValidationType.None)
{
statements[index] = Argument.ValidateParameter(parameter);
index++;
}
}
statements[index] = EmptyLineStatement;
index++;

statements[index] = bodyStatements;

return statements;
}

private MethodBodyStatement GetStatementsAsSingleList(MethodBodyStatement original)
{
bool wroteValidation = false;
List<MethodBodyStatement> statements = new();
foreach (var parameter in Signature.Parameters)
{
if (parameter.Validation != ParameterValidationType.None)
{
statements.Add(Argument.ValidateParameter(parameter));
wroteValidation = true;
}
}
if (wroteValidation)
statements.Add(EmptyLineStatement);

statements.Add(original);
return statements;
}

private IEnumerable<MethodBodyStatement> GetValidationStatementsWithYield()
{
bool wroteValidation = false;
foreach (var parameter in Signature.Parameters)
{
if (parameter.Validation != ParameterValidationType.None)
{
yield return Argument.ValidateParameter(parameter);
wroteValidation = true;
}
}
if (wroteValidation)
yield return EmptyLineStatement;
}

private IReadOnlyList<MethodBodyStatement> GetValidationStatements()
{
bool wroteValidation = false;
List<MethodBodyStatement> statements = new();
foreach (var parameter in Signature.Parameters)
{
if (parameter.Validation != ParameterValidationType.None)
{
statements.Add(Argument.ValidateParameter(parameter));
wroteValidation = true;
}
}
if (wroteValidation)
statements.Add(EmptyLineStatement);
return statements;
}
}
}
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.

using System.IO;
using System.Reflection;

namespace Microsoft.Generator.CSharp.Perf
{
internal static class PluginInitializer
{
public static void Initialize()
{
PluginHandler pluginHandler = new PluginHandler();
pluginHandler.LoadPlugin(Path.Combine(Directory.GetParent(Assembly.GetExecutingAssembly().Location)!.FullName, "Projects", "Model"));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using System.Collections.Generic;
using Microsoft.Generator.CSharp.Input;
using Microsoft.Generator.CSharp.Providers;
using Microsoft.Generator.CSharp.Statements;
using Microsoft.Generator.CSharp.Snippets;

namespace Microsoft.Generator.CSharp
Expand Down Expand Up @@ -60,21 +59,18 @@ private static MethodProvider BuildCreateMessageMethod(InputOperation operation)
var methodSignature = new MethodSignature(methodSignatureName, FormattableStringHelpers.FromString(operation.Summary), FormattableStringHelpers.FromString(operation.Description), methodModifier, null, null, Parameters: methodParameters);
var methodBody = Snippet.EmptyStatement;

return new MethodProvider(methodSignature, methodBody, CSharpMethodKinds.CreateMessage);
return new MethodProvider(methodSignature, methodBody);
}

/// <summary>
/// Returns all methods in the collection of a specific kind.
/// </summary>
internal List<MethodProvider> GetMethods(CSharpMethodKinds kind)
internal List<MethodProvider> GetMethods()
{
var methods = new List<MethodProvider>();
foreach (var method in _cSharpMethods)
{
if (method.Kind == kind)
{
methods.Add(method);
}
methods.Add(method);
}

return methods;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public static partial class KnownParameters
public static ParameterProvider CancellationTokenParameter => _cancellationTokenParameter ??= new("cancellationToken", $"The cancellation token to use", new CSharpType(typeof(CancellationToken)), Snippet.DefaultOf(typeof(CancellationToken)));

private static ParameterProvider? _enumerationCancellationTokenParameter;
public static ParameterProvider EnumeratorCancellationTokenParameter => _enumerationCancellationTokenParameter ??= new("cancellationToken", $"Enumerator cancellation token", typeof(CancellationToken), Snippet.DefaultOf(typeof(CancellationToken))) { Attributes = new[] { new AttributeStatement(typeof(EnumeratorCancellationAttribute)) } };
public static ParameterProvider EnumeratorCancellationTokenParameter => _enumerationCancellationTokenParameter ??= new("cancellationToken", $"Enumerator cancellation token", typeof(CancellationToken), Snippet.DefaultOf(typeof(CancellationToken)), attributes: [new AttributeStatement(typeof(EnumeratorCancellationAttribute))]);

private static ParameterProvider? _response;
public static ParameterProvider Response => _response ??= new("response", $"Response returned from backend service", CodeModelPlugin.Instance.Configuration.ApiTypes.ResponseType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,15 +142,13 @@ private PropertyProvider BuildEnumerableValues()
{
return new PropertyProvider(null, MethodSignatureModifiers.None, new CSharpType(typeof(IEnumerable<>), _tValue), "Values", new ExpressionPropertyBody(
new MemberExpression(This, "Values")),
null,
_IReadOnlyDictionary);
}

private PropertyProvider BuildEnumerableKeys()
{
return new PropertyProvider(null, MethodSignatureModifiers.None, new CSharpType(typeof(IEnumerable<>), _tKey), "Keys", new ExpressionPropertyBody(
new MemberExpression(This, "Keys")),
null,
_IReadOnlyDictionary);
}

Expand Down
Loading

0 comments on commit df3d037

Please sign in to comment.