Skip to content

Commit 45cb0c8

Browse files
authored
Add extract method support for ref struct interfaces (#73619)
* Add extract method support for ref struct interfaces The method extraction code uses ITypeParameterSymbol's constraints to generate the new method's text. This codepath had not yet been modified to support ITypeParameterSymbol.AllowsRefLikeType This is in support of the "allows ref struct" on interfaces feature outlined here: #72124 This ref structs for interfaces feature was merged via this PR: #73567
1 parent 1d8582e commit 45cb0c8

File tree

6 files changed

+49
-5
lines changed

6 files changed

+49
-5
lines changed

src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.LanguageInteraction.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,39 @@ class Program
5858
await TestExtractMethodAsync(code, expected);
5959
}
6060

61+
[Fact]
62+
public async Task SelectTypeParameterWithAllowsRefStructAntiConstraint()
63+
{
64+
var code = """
65+
using System;
66+
67+
class Program
68+
{
69+
void MyMethod1<TT>(TT tt) where TT : IDisposable, allows ref struct
70+
{
71+
[|tt.Dispose();|]
72+
}
73+
}
74+
""";
75+
var expected = """
76+
using System;
77+
78+
class Program
79+
{
80+
void MyMethod1<TT>(TT tt) where TT : IDisposable, allows ref struct
81+
{
82+
NewMethod(tt);
83+
}
84+
85+
private static void NewMethod<TT>(TT tt) where TT : IDisposable, allows ref struct
86+
{
87+
tt.Dispose();
88+
}
89+
}
90+
""";
91+
92+
await TestExtractMethodAsync(code, expected);
93+
}
6194
[Fact]
6295
public async Task SelectTypeParameter()
6396
{

src/Features/Core/Portable/ExtractMethod/MethodExtractor.CodeGenerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ protected ImmutableArray<ITypeParameterSymbol> CreateMethodTypeParameters()
344344
typeParameters.Add(CodeGenerationSymbolFactory.CreateTypeParameter(
345345
parameter.GetAttributes(), parameter.Variance, parameter.Name, [], parameter.NullableAnnotation,
346346
parameter.HasConstructorConstraint, parameter.HasReferenceTypeConstraint, parameter.HasUnmanagedTypeConstraint,
347-
parameter.HasValueTypeConstraint, parameter.HasNotNullConstraint, parameter.Ordinal));
347+
parameter.HasValueTypeConstraint, parameter.HasNotNullConstraint, parameter.AllowsRefLikeType, parameter.Ordinal));
348348
}
349349

350350
return typeParameters.ToImmutableAndFree();

src/Workspaces/Core/Portable/Shared/Extensions/IMethodSymbolExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ private static ImmutableArray<ITypeParameterSymbol> RenameTypeParameters(
137137
typeParameter.HasValueTypeConstraint,
138138
typeParameter.HasUnmanagedTypeConstraint,
139139
typeParameter.HasNotNullConstraint,
140+
typeParameter.AllowsRefLikeType,
140141
typeParameter.Ordinal);
141142

142143
newTypeParameters.Add(newTypeParameter);

src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeParameterSymbolExtensions.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,12 @@ private static void AddConstraintClauses(
7474
constraints.Add(ConstructorConstraint());
7575
}
7676

77+
if (typeParameter.AllowsRefLikeType)
78+
{
79+
// "allows ref struct" anti-constraint must be last
80+
constraints.Add(AllowsConstraintClause([RefStructConstraint()]));
81+
}
82+
7783
if (constraints.Count == 0)
7884
{
7985
return;

src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeGenerationSymbolFactory.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,8 @@ public static ITypeParameterSymbol CreateTypeParameterSymbol(string name, int or
322322
attributes: default, varianceKind: VarianceKind.None,
323323
name: name, constraintTypes: [],
324324
hasConstructorConstraint: false, hasReferenceConstraint: false, hasValueConstraint: false,
325-
hasUnmanagedConstraint: false, hasNotNullConstraint: false, ordinal: ordinal);
325+
hasUnmanagedConstraint: false, hasNotNullConstraint: false, allowsRefLikeType: false,
326+
ordinal: ordinal);
326327
}
327328

328329
/// <summary>
@@ -338,9 +339,10 @@ public static ITypeParameterSymbol CreateTypeParameter(
338339
bool hasUnmanagedConstraint = false,
339340
bool hasValueConstraint = false,
340341
bool hasNotNullConstraint = false,
342+
bool allowsRefLikeType = false,
341343
int ordinal = 0)
342344
{
343-
return new CodeGenerationTypeParameterSymbol(null, attributes, varianceKind, name, nullableAnnotation, constraintTypes, hasConstructorConstraint, hasReferenceConstraint, hasValueConstraint, hasUnmanagedConstraint, hasNotNullConstraint, ordinal);
345+
return new CodeGenerationTypeParameterSymbol(null, attributes, varianceKind, name, nullableAnnotation, constraintTypes, hasConstructorConstraint, hasReferenceConstraint, hasValueConstraint, hasUnmanagedConstraint, hasNotNullConstraint, allowsRefLikeType, ordinal);
344346
}
345347

346348
/// <summary>

src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationTypeParameterSymbol.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,15 @@ internal class CodeGenerationTypeParameterSymbol(
2020
bool hasValueConstraint,
2121
bool hasUnmanagedConstraint,
2222
bool hasNotNullConstraint,
23+
bool allowsRefLikeType,
2324
int ordinal) : CodeGenerationTypeSymbol(containingType?.ContainingAssembly, containingType, attributes, Accessibility.NotApplicable, default, name, SpecialType.None, nullableAnnotation), ITypeParameterSymbol
2425
{
2526
public VarianceKind Variance { get; } = varianceKind;
2627
public ImmutableArray<ITypeSymbol> ConstraintTypes { get; internal set; } = constraintTypes;
2728
public bool HasConstructorConstraint { get; } = hasConstructorConstraint;
2829
public bool HasReferenceTypeConstraint { get; } = hasReferenceConstraint;
2930
public bool HasValueTypeConstraint { get; } = hasValueConstraint;
30-
public bool AllowsRefLikeType => false;
31+
public bool AllowsRefLikeType { get; } = allowsRefLikeType;
3132
public bool HasUnmanagedTypeConstraint { get; } = hasUnmanagedConstraint;
3233
public bool HasNotNullConstraint { get; } = hasNotNullConstraint;
3334
public int Ordinal { get; } = ordinal;
@@ -37,7 +38,8 @@ protected override CodeGenerationTypeSymbol CloneWithNullableAnnotation(Nullable
3738
return new CodeGenerationTypeParameterSymbol(
3839
this.ContainingType, this.GetAttributes(), this.Variance, this.Name, nullableAnnotation,
3940
this.ConstraintTypes, this.HasConstructorConstraint, this.HasReferenceTypeConstraint,
40-
this.HasValueTypeConstraint, this.HasUnmanagedTypeConstraint, this.HasNotNullConstraint, this.Ordinal);
41+
this.HasValueTypeConstraint, this.HasUnmanagedTypeConstraint, this.HasNotNullConstraint,
42+
this.AllowsRefLikeType, this.Ordinal);
4143
}
4244

4345
public new ITypeParameterSymbol OriginalDefinition => this;

0 commit comments

Comments
 (0)