Skip to content

Commit

Permalink
refactor to breakingchangeresolver so that it is now just giving us t…
Browse files Browse the repository at this point in the history
…he final list of methods
  • Loading branch information
ArcturusZhang committed Feb 4, 2024
1 parent cc504d3 commit fa9971f
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 49 deletions.
4 changes: 2 additions & 2 deletions src/AutoRest.CSharp/Common/Input/Source/SourceTypeMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ private static bool IsPropertyOrFieldSymbol(ISymbol member)

private static bool IsMethodSymbol(ISymbol member)
{
// here we exclude those "CompilerGenerated" members
return !member.IsImplicitlyDeclared && member is IMethodSymbol;
// here we exclude those "CompilerGenerated" members and ctor symbols
return !member.IsImplicitlyDeclared && member is IMethodSymbol method && method.MethodKind != MethodKind.Constructor;
}

public ISymbol? GetMemberByOriginalName(string name)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
Expand All @@ -18,18 +17,12 @@
namespace AutoRest.CSharp.Output.Models.Types
{
/// <summary>
/// This type holds three portions of codes:
/// - current
/// - custom
/// - baseline contract
/// current union custom compare with baseline contract outputs the changeset, we can apply different rules with it.
/// The <see cref="BreakingChangeResolver"/> class consumes the generated methods and resolves the methods in customization and baseline contract to produce a full list of the methods we should generate.
/// </summary>
internal class BreakingChangeResolver
{
private readonly SignatureType _customizationType;
private readonly SignatureType _baselineContractType;
private IEnumerable<MethodSignature>? _generatedMethods;
private MethodChangeset? _methodChangeset;

/// <summary>
/// Tracks the changeset of methods between the currently generated methods, and the methods read from the baseline contract
Expand All @@ -51,25 +44,31 @@ public BreakingChangeResolver(TypeFactory typeFactory, SourceTypeMapping? source
_baselineContractType = new SignatureType(typeFactory, contractTypeMapping);
}

public void Build(IEnumerable<MethodSignature> generatedMethods)
public IEnumerable<Method> Resolve(IEnumerable<Method> generatedMethods)
{
if (_generatedMethods is not null)
var generatedMethodSignatures = generatedMethods.Select(m => (MethodSignature)m.Signature);
var methodChangeset = CompareMethods(generatedMethodSignatures.Union(_customizationType.Methods, MethodSignature.ParameterAndReturnTypeEqualityComparer), _baselineContractType.Methods);

var methodToSkip = generatedMethodSignatures.Intersect(_customizationType.Methods, MethodSignature.ParameterAndReturnTypeEqualityComparer).ToHashSet(MethodSignature.ParameterAndReturnTypeEqualityComparer);
foreach (var method in generatedMethods)
{
throw new InvalidOperationException($"{nameof(BreakingChangeResolver)} could only be built once.");
if (methodToSkip.Contains((MethodSignature)method.Signature))
continue;

yield return method;
}
_generatedMethods = generatedMethods;
_methodChangeset = CompareMethods(generatedMethods.Union(_customizationType.Methods, MethodSignature.ParameterAndReturnTypeEqualityComparer), _baselineContractType.Methods);
}

private IReadOnlyList<Method>? _overloadMethods;
public IReadOnlyList<Method> OverloadMethods => _overloadMethods ??= EnsureOverloadMethods();
foreach (var method in BuildOverloadMethods(methodChangeset))
{
yield return method;
}
}

private IReadOnlyList<Method> EnsureOverloadMethods()
private IEnumerable<Method> BuildOverloadMethods(MethodChangeset methodChangeset)
{
var overloadMethods = new List<Method>();
if (_methodChangeset?.Updated is not { } updated)
if (methodChangeset.Updated is not { } updated)
{
return Array.Empty<Method>();
yield break;
}

foreach (var (current, previous) in updated)
Expand All @@ -78,10 +77,10 @@ private IReadOnlyList<Method> EnsureOverloadMethods()
{
var overloadMethodSignature = new OverloadMethodSignature(currentMethodToCall, previous.WithParametersRequired(), missingParameters, previous.Description);
var previousMethodSignature = overloadMethodSignature.PreviousMethodSignature with { Attributes = new CSharpAttribute[] { new CSharpAttribute(typeof(EditorBrowsableAttribute), FrameworkEnumValue(EditorBrowsableState.Never)) } };
overloadMethods.Add(new Method(previousMethodSignature, BuildOverloadMethodBody(overloadMethodSignature)));

yield return new Method(previousMethodSignature, BuildOverloadMethodBody(overloadMethodSignature));
}
}
return overloadMethods;
}

private MethodBodyStatement BuildOverloadMethodBody(OverloadMethodSignature overloadMethodSignature)
Expand All @@ -103,17 +102,6 @@ private IReadOnlyList<ValueExpression> BuildOverloadMethodParameters(OverloadMet
return parameters;
}

private IReadOnlySet<MethodSignature>? _methodsToSkip;
public IReadOnlySet<MethodSignature> MethodsToSkip => _methodsToSkip ??= EnsureMethodsToSkip();
private IReadOnlySet<MethodSignature> EnsureMethodsToSkip()
{
if (_generatedMethods == null)
{
throw new InvalidOperationException($"{nameof(BreakingChangeResolver)} has not been built yet.");
}
return _generatedMethods.Intersect(_customizationType.Methods, MethodSignature.ParameterAndReturnTypeEqualityComparer).ToHashSet(MethodSignature.ParameterAndReturnTypeEqualityComparer);
}

private bool TryGetPreviousMethodWithLessOptionalParameters(IReadOnlyList<MethodSignature> currentMethods, MethodSignature previousMethod, [NotNullWhen(true)] out MethodSignature? currentMethodToCall, [NotNullWhen(true)] out IReadOnlyList<Parameter>? missingParameters)
{
foreach (var item in currentMethods)
Expand Down Expand Up @@ -165,12 +153,8 @@ private bool CurrentContainAllPreviousParameters(MethodSignature previousMethod,
return true;
}

private static MethodChangeset? CompareMethods(IEnumerable<MethodSignature> currentMethods, IEnumerable<MethodSignature>? previousMethods)
private static MethodChangeset CompareMethods(IEnumerable<MethodSignature> currentMethods, IEnumerable<MethodSignature> previousMethods)
{
if (previousMethods is null)
{
return null;
}
var missing = new List<MethodSignature>();
var updated = new List<UpdatedMethod>();
var set = currentMethods.ToHashSet(MethodSignature.ParameterAndReturnTypeEqualityComparer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,8 @@ private IEnumerable<Method> BuildMethods()
// The overloading feature is not enabled, we jsut return the original methods
return generatedMethods;
}
// build the resolver
BreakingChangeResolver.Build(generatedMethods.Select(x => (MethodSignature)x.Signature));
// filter out duplicate methods in custom code and combine overload methods
return generatedMethods.Where(m => !BreakingChangeResolver.MethodsToSkip.Contains(m.Signature)).Concat(BreakingChangeResolver.OverloadMethods);

return BreakingChangeResolver.Resolve(generatedMethods);
}

public FormattableString Description => $"Model factory for models.";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,7 @@
namespace AutoRest.CSharp.Output.Models.Types
{
/// <summary>
/// This type holds three portions of codes:
/// - current
/// - custom
/// - baseline contract
/// current union custom compare with baseline contract outputs the changeset, we can apply different rules with it.
/// The <see cref="SignatureType"/> resolves the symbol to produce the MethodSignatures on the symbol
/// </summary>
internal class SignatureType
{
Expand Down

0 comments on commit fa9971f

Please sign in to comment.