Skip to content

Commit babe4bd

Browse files
authored
ApiDiff: Move TryGetRecordConstructor from GenAPI.INamedTypeSymbolExtensions up to ApiSymbolExtensions.SymbolExtensions (#45801)
1 parent a84ed46 commit babe4bd

File tree

5 files changed

+36
-34
lines changed

5 files changed

+36
-34
lines changed

src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI/INamedTypeSymbolExtensions.cs

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using System.Diagnostics.CodeAnalysis;
54
using Microsoft.CodeAnalysis;
65
using Microsoft.CodeAnalysis.CSharp;
76
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -224,7 +223,7 @@ static bool IncludeInternalSymbols(ISymbolFilter filter) =>
224223
yield return constructor;
225224
}
226225

227-
// Synthesize a base class initializer.
226+
// Synthesize a base class initializer.
228227
public static ConstructorInitializerSyntax GenerateBaseConstructorInitializer(this IMethodSymbol baseTypeConstructor)
229228
{
230229
return SyntaxFactory.ConstructorInitializer(SyntaxKind.BaseConstructorInitializer, baseTypeConstructor.CreateDefaultArgumentList());
@@ -248,33 +247,5 @@ public static ArgumentListSyntax CreateDefaultArgumentList(this IMethodSymbol me
248247

249248
return argumentList;
250249
}
251-
252-
// Locates constructor generated by the compiler for `record Foo(...)` syntax
253-
// If the type is a record and the compiler generated constructor is found it will be returned, otherwise null.
254-
// The compiler will not generate a constructor in the case where the user defined it themself without using an argument list
255-
// in the record declaration, or if the record has no parameters.
256-
public static bool TryGetRecordConstructor(this INamedTypeSymbol type, [NotNullWhen(true)] out IMethodSymbol? recordConstructor)
257-
{
258-
if (!type.IsRecord)
259-
{
260-
recordConstructor = null;
261-
return false;
262-
}
263-
264-
// Locate the compiler generated Deconstruct method.
265-
var deconstructMethod = (IMethodSymbol?)type.GetMembers("Deconstruct")
266-
.FirstOrDefault(m => m is IMethodSymbol && m.IsCompilerGenerated());
267-
268-
// Locate the compiler generated constructor by matching parameters to Deconstruct - since we cannot locate it with an attribute.
269-
recordConstructor = (IMethodSymbol?)type.GetMembers(".ctor")
270-
.FirstOrDefault(m => m is IMethodSymbol method &&
271-
method.MethodKind == MethodKind.Constructor &&
272-
(deconstructMethod == null ?
273-
method.Parameters.IsEmpty :
274-
method.Parameters.Select(p => p.Type).SequenceEqual(
275-
deconstructMethod.Parameters.Select(p => p.Type), SymbolEqualityComparer.Default)));
276-
277-
return recordConstructor != null;
278-
}
279250
}
280251
}

src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI/Microsoft.DotNet.GenAPI.csproj

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,6 @@
44
<TargetFrameworks>$(NetToolMinimum);$(NetFrameworkToolCurrent)</TargetFrameworks>
55
</PropertyGroup>
66

7-
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'">
8-
<Compile Include="$(RepoRoot)src\Common\NullableAttributes.cs" LinkBase="Common" />
9-
</ItemGroup>
10-
117
<ItemGroup>
128
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" />
139
<ProjectReference Include="..\..\Microsoft.DotNet.ApiSymbolExtensions\Microsoft.DotNet.ApiSymbolExtensions.csproj" />

src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI/SyntaxGeneratorExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Microsoft.CodeAnalysis.CSharp;
77
using Microsoft.CodeAnalysis.CSharp.Syntax;
88
using Microsoft.CodeAnalysis.Editing;
9+
using Microsoft.DotNet.ApiSymbolExtensions;
910
using Microsoft.DotNet.ApiSymbolExtensions.Filtering;
1011

1112
namespace Microsoft.DotNet.GenAPI

src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Microsoft.DotNet.ApiSymbolExtensions.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'">
2121
<Reference Include="System.IO.Compression" />
22+
<Compile Include="$(RepoRoot)src\Common\NullableAttributes.cs" LinkBase="Common" />
2223
</ItemGroup>
2324

2425
</Project>

src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/SymbolExtensions.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Diagnostics.CodeAnalysis;
45
using Microsoft.CodeAnalysis;
56

67
namespace Microsoft.DotNet.ApiSymbolExtensions
@@ -126,5 +127,37 @@ public static bool IsEventAdderOrRemover(this IMethodSymbol method) =>
126127
method.MethodKind == MethodKind.EventRemove ||
127128
method.Name.StartsWith("add_", StringComparison.Ordinal) ||
128129
method.Name.StartsWith("remove_", StringComparison.Ordinal);
130+
131+
/// <summary>
132+
/// Attempts to locate and return the constructor generated by the compiler for `record Foo(...)` syntax.
133+
/// The compiler will not generate a constructor in the case where the user defined it themself without using an argument list
134+
/// in the record declaration, or if the record has no parameters.
135+
/// </summary>
136+
/// <param name="type">The type to check for a compiler generated constructor.</param>
137+
/// <param name="recordConstructor">When this method returns <see langword="true"/>, then the compiler generated constructor for the record is stored in this out parameter, otherwise it becomes <see langword="null" />.</param>
138+
/// <returns><see langword="true" /> if the type is a record and the compiler generated constructor is found, otherwise <see langword="false"/>.</returns>
139+
public static bool TryGetRecordConstructor(this INamedTypeSymbol type, [NotNullWhen(true)] out IMethodSymbol? recordConstructor)
140+
{
141+
if (!type.IsRecord)
142+
{
143+
recordConstructor = null;
144+
return false;
145+
}
146+
147+
// Locate the compiler generated Deconstruct method.
148+
var deconstructMethod = (IMethodSymbol?)type.GetMembers("Deconstruct")
149+
.FirstOrDefault(m => m is IMethodSymbol && m.IsCompilerGenerated());
150+
151+
// Locate the compiler generated constructor by matching parameters to Deconstruct - since we cannot locate it with an attribute.
152+
recordConstructor = (IMethodSymbol?)type.GetMembers(".ctor")
153+
.FirstOrDefault(m => m is IMethodSymbol method &&
154+
method.MethodKind == MethodKind.Constructor &&
155+
(deconstructMethod == null ?
156+
method.Parameters.IsEmpty :
157+
method.Parameters.Select(p => p.Type).SequenceEqual(
158+
deconstructMethod.Parameters.Select(p => p.Type), SymbolEqualityComparer.Default)));
159+
160+
return recordConstructor != null;
161+
}
129162
}
130163
}

0 commit comments

Comments
 (0)