diff --git a/src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI/INamedTypeSymbolExtensions.cs b/src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI/INamedTypeSymbolExtensions.cs index fdbee7992df1..6d5d6ec8e054 100644 --- a/src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI/INamedTypeSymbolExtensions.cs +++ b/src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI/INamedTypeSymbolExtensions.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -224,7 +223,7 @@ static bool IncludeInternalSymbols(ISymbolFilter filter) => yield return constructor; } - // Synthesize a base class initializer. + // Synthesize a base class initializer. public static ConstructorInitializerSyntax GenerateBaseConstructorInitializer(this IMethodSymbol baseTypeConstructor) { return SyntaxFactory.ConstructorInitializer(SyntaxKind.BaseConstructorInitializer, baseTypeConstructor.CreateDefaultArgumentList()); @@ -248,33 +247,5 @@ public static ArgumentListSyntax CreateDefaultArgumentList(this IMethodSymbol me return argumentList; } - - // Locates constructor generated by the compiler for `record Foo(...)` syntax - // If the type is a record and the compiler generated constructor is found it will be returned, otherwise null. - // The compiler will not generate a constructor in the case where the user defined it themself without using an argument list - // in the record declaration, or if the record has no parameters. - public static bool TryGetRecordConstructor(this INamedTypeSymbol type, [NotNullWhen(true)] out IMethodSymbol? recordConstructor) - { - if (!type.IsRecord) - { - recordConstructor = null; - return false; - } - - // Locate the compiler generated Deconstruct method. - var deconstructMethod = (IMethodSymbol?)type.GetMembers("Deconstruct") - .FirstOrDefault(m => m is IMethodSymbol && m.IsCompilerGenerated()); - - // Locate the compiler generated constructor by matching parameters to Deconstruct - since we cannot locate it with an attribute. - recordConstructor = (IMethodSymbol?)type.GetMembers(".ctor") - .FirstOrDefault(m => m is IMethodSymbol method && - method.MethodKind == MethodKind.Constructor && - (deconstructMethod == null ? - method.Parameters.IsEmpty : - method.Parameters.Select(p => p.Type).SequenceEqual( - deconstructMethod.Parameters.Select(p => p.Type), SymbolEqualityComparer.Default))); - - return recordConstructor != null; - } } } diff --git a/src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI/Microsoft.DotNet.GenAPI.csproj b/src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI/Microsoft.DotNet.GenAPI.csproj index 1966bb66ab05..0c382c85d75f 100644 --- a/src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI/Microsoft.DotNet.GenAPI.csproj +++ b/src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI/Microsoft.DotNet.GenAPI.csproj @@ -4,10 +4,6 @@ $(NetToolMinimum);$(NetFrameworkToolCurrent) - - - - diff --git a/src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI/SyntaxGeneratorExtensions.cs b/src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI/SyntaxGeneratorExtensions.cs index 1201e4db2336..6618d47a20b1 100644 --- a/src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI/SyntaxGeneratorExtensions.cs +++ b/src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI/SyntaxGeneratorExtensions.cs @@ -6,6 +6,7 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; +using Microsoft.DotNet.ApiSymbolExtensions; using Microsoft.DotNet.ApiSymbolExtensions.Filtering; namespace Microsoft.DotNet.GenAPI diff --git a/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Microsoft.DotNet.ApiSymbolExtensions.csproj b/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Microsoft.DotNet.ApiSymbolExtensions.csproj index c531b3bd79a7..c9d256170375 100644 --- a/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Microsoft.DotNet.ApiSymbolExtensions.csproj +++ b/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Microsoft.DotNet.ApiSymbolExtensions.csproj @@ -19,6 +19,7 @@ + diff --git a/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/SymbolExtensions.cs b/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/SymbolExtensions.cs index 8e7e44b929bc..b37fde068940 100644 --- a/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/SymbolExtensions.cs +++ b/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/SymbolExtensions.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis; namespace Microsoft.DotNet.ApiSymbolExtensions @@ -126,5 +127,37 @@ public static bool IsEventAdderOrRemover(this IMethodSymbol method) => method.MethodKind == MethodKind.EventRemove || method.Name.StartsWith("add_", StringComparison.Ordinal) || method.Name.StartsWith("remove_", StringComparison.Ordinal); + + /// + /// Attempts to locate and return the constructor generated by the compiler for `record Foo(...)` syntax. + /// The compiler will not generate a constructor in the case where the user defined it themself without using an argument list + /// in the record declaration, or if the record has no parameters. + /// + /// The type to check for a compiler generated constructor. + /// When this method returns , then the compiler generated constructor for the record is stored in this out parameter, otherwise it becomes . + /// if the type is a record and the compiler generated constructor is found, otherwise . + public static bool TryGetRecordConstructor(this INamedTypeSymbol type, [NotNullWhen(true)] out IMethodSymbol? recordConstructor) + { + if (!type.IsRecord) + { + recordConstructor = null; + return false; + } + + // Locate the compiler generated Deconstruct method. + var deconstructMethod = (IMethodSymbol?)type.GetMembers("Deconstruct") + .FirstOrDefault(m => m is IMethodSymbol && m.IsCompilerGenerated()); + + // Locate the compiler generated constructor by matching parameters to Deconstruct - since we cannot locate it with an attribute. + recordConstructor = (IMethodSymbol?)type.GetMembers(".ctor") + .FirstOrDefault(m => m is IMethodSymbol method && + method.MethodKind == MethodKind.Constructor && + (deconstructMethod == null ? + method.Parameters.IsEmpty : + method.Parameters.Select(p => p.Type).SequenceEqual( + deconstructMethod.Parameters.Select(p => p.Type), SymbolEqualityComparer.Default))); + + return recordConstructor != null; + } } }