Skip to content

Commit b7159b0

Browse files
Merge branch 'main' into useAutoPropResolution
2 parents f75dade + 6c67a00 commit b7159b0

File tree

152 files changed

+2657
-1159
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

152 files changed

+2657
-1159
lines changed

eng/Directory.Packages.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@
273273
<PackageVersion Include="xunit.core" Version="$(_xunitVersion)" />
274274
<PackageVersion Include="Xunit.Combinatorial" Version="1.6.24" />
275275
<PackageVersion Include="xunit.extensibility.core" Version="$(_xunitVersion)" />
276-
<PackageVersion Include="xunit.runner.visualstudio" Version="2.4.5 " />
276+
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.1" />
277277
<PackageVersion Include="xunit.runner.utility" Version="$(_xunitVersion)" />
278278
<PackageVersion Include="xunit.abstractions" Version="2.0.3" />
279279
<PackageVersion Include="xunit.extensibility.execution" Version="$(_xunitVersion)" />

eng/Versions.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,6 @@
155155
in Directory.Packages.props - Microsoft.TestPlatform.TranslationLayer and Microsoft.TestPlatform.ObjectModel.
156156
This version needs to match the Test SDK version consumed by Arcade.
157157
-->
158-
<MicrosoftNETTestSdkVersion>17.5.0</MicrosoftNETTestSdkVersion>
158+
<MicrosoftNETTestSdkVersion>17.13.0</MicrosoftNETTestSdkVersion>
159159
</PropertyGroup>
160160
</Project>

src/Analyzers/CSharp/CodeFixes/ImplementInterface/CSharpImplementInterfaceCodeFixProvider.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,4 @@ internal sealed class CSharpImplementInterfaceCodeFixProvider()
2424

2525
public sealed override ImmutableArray<string> FixableDiagnosticIds { get; }
2626
= [CS0535, CS0737, CS0738];
27-
28-
protected override bool IsTypeInInterfaceBaseList(TypeSyntax type)
29-
=> type.Parent is BaseTypeSyntax { Parent: BaseListSyntax } baseTypeParent && baseTypeParent.Type == type;
3027
}

src/Analyzers/CSharp/CodeFixes/ImplementInterface/CSharpImplementInterfaceService.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@
1616
using Microsoft.CodeAnalysis.Formatting;
1717
using Microsoft.CodeAnalysis.Host.Mef;
1818
using Microsoft.CodeAnalysis.ImplementInterface;
19+
using Microsoft.CodeAnalysis.PooledObjects;
1920
using Microsoft.CodeAnalysis.Shared.Extensions;
2021

2122
namespace Microsoft.CodeAnalysis.CSharp.ImplementInterface;
2223

2324
[ExportLanguageService(typeof(IImplementInterfaceService), LanguageNames.CSharp), Shared]
2425
[method: ImportingConstructor]
2526
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
26-
internal sealed class CSharpImplementInterfaceService() : AbstractImplementInterfaceService
27+
internal sealed class CSharpImplementInterfaceService() : AbstractImplementInterfaceService<TypeDeclarationSyntax>
2728
{
2829
protected override ISyntaxFormatting SyntaxFormatting
2930
=> CSharpSyntaxFormatting.Instance;
@@ -37,6 +38,18 @@ protected override string ToDisplayString(IMethodSymbol disposeImplMethod, Symbo
3738
protected override bool AllowDelegateAndEnumConstraints(ParseOptions options)
3839
=> options.LanguageVersion() >= LanguageVersion.CSharp7_3;
3940

41+
protected override bool IsTypeInInterfaceBaseList(SyntaxNode? type)
42+
=> type?.Parent is BaseTypeSyntax { Parent: BaseListSyntax } baseTypeParent && baseTypeParent.Type == type;
43+
44+
protected override void AddInterfaceTypes(TypeDeclarationSyntax typeDeclaration, ArrayBuilder<SyntaxNode> result)
45+
{
46+
if (typeDeclaration.BaseList != null)
47+
{
48+
foreach (var baseType in typeDeclaration.BaseList.Types)
49+
result.Add(baseType.Type);
50+
}
51+
}
52+
4053
protected override bool TryInitializeState(
4154
Document document, SemanticModel model, SyntaxNode node, CancellationToken cancellationToken,
4255
[NotNullWhen(true)] out SyntaxNode? classOrStructDecl,

src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@
4343
<Compile Include="$(MSBuildThisFileDirectory)ImplementAbstractClass\ImplementAbstractClassTests.cs" />
4444
<Compile Include="$(MSBuildThisFileDirectory)ImplementAbstractClass\ImplementAbstractClassTests_FixAllTests.cs" />
4545
<Compile Include="$(MSBuildThisFileDirectory)ImplementAbstractClass\ImplementAbstractClassTests_ThroughMember.cs" />
46-
<Compile Include="$(MSBuildThisFileDirectory)ImplementInterface\ImplementInterfaceTests.cs" />
47-
<Compile Include="$(MSBuildThisFileDirectory)ImplementInterface\ImplementInterfaceTests_FixAllTests.cs" />
46+
<Compile Include="$(MSBuildThisFileDirectory)ImplementInterface\ImplementInterfaceCodeFixTests.cs" />
47+
<Compile Include="$(MSBuildThisFileDirectory)ImplementInterface\ImplementInterfaceCodeFixTests_FixAllTests.cs" />
4848
<Compile Include="$(MSBuildThisFileDirectory)Iterator\AddYieldTests.cs" />
4949
<Compile Include="$(MSBuildThisFileDirectory)Iterator\ChangeToIEnumerableTests.cs" />
5050
<Compile Include="$(MSBuildThisFileDirectory)MakeAnonymousFunctionStatic\MakeAnonymousFunctionStaticTests.cs" />

src/Analyzers/CSharp/Tests/ImplementInterface/ImplementInterfaceTests.cs renamed to src/Analyzers/CSharp/Tests/ImplementInterface/ImplementInterfaceCodeFixTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ImplementInterface;
2323
CSharpImplementInterfaceCodeFixProvider>;
2424

2525
[Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)]
26-
public sealed class ImplementInterfaceTests
26+
public sealed class ImplementInterfaceCodeFixTests
2727
{
2828
private readonly NamingStylesTestOptionSets _options = new(LanguageNames.CSharp);
2929

src/Analyzers/CSharp/Tests/ImplementInterface/ImplementInterfaceTests_FixAllTests.cs renamed to src/Analyzers/CSharp/Tests/ImplementInterface/ImplementInterfaceCodeFixTests_FixAllTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ImplementInterface;
1515
EmptyDiagnosticAnalyzer,
1616
CSharpImplementInterfaceCodeFixProvider>;
1717

18-
public sealed class ImplementInterfaceTests_FixAllTests
18+
public sealed class ImplementInterfaceCodeFixTests_FixAllTests
1919
{
2020
#region "Fix all occurrences tests"
2121

src/Analyzers/Core/CodeFixes/ImplementInterface/AbstractImplementInterfaceCodeFixProvider.cs

Lines changed: 4 additions & 178 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,16 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5-
using System.Collections.Generic;
6-
using System.Collections.Immutable;
75
using System.Linq;
8-
using System.Runtime.CompilerServices;
9-
using System.Threading;
106
using System.Threading.Tasks;
11-
using Microsoft.CodeAnalysis.CodeActions;
127
using Microsoft.CodeAnalysis.CodeFixes;
13-
using Microsoft.CodeAnalysis.ImplementType;
14-
using Microsoft.CodeAnalysis.LanguageService;
15-
using Microsoft.CodeAnalysis.PooledObjects;
168
using Microsoft.CodeAnalysis.Shared.Extensions;
179

1810
namespace Microsoft.CodeAnalysis.ImplementInterface;
1911

20-
using static ImplementHelpers;
21-
2212
internal abstract class AbstractImplementInterfaceCodeFixProvider<TTypeSyntax> : CodeFixProvider
2313
where TTypeSyntax : SyntaxNode
2414
{
25-
protected abstract bool IsTypeInInterfaceBaseList(TTypeSyntax type);
26-
2715
public sealed override FixAllProvider GetFixAllProvider()
2816
=> WellKnownFixAllProviders.BatchFixer;
2917

@@ -39,173 +27,11 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
3927
if (!token.Span.IntersectsWith(span))
4028
return;
4129

42-
var options = await document.GetImplementTypeOptionsAsync(cancellationToken).ConfigureAwait(false);
43-
44-
foreach (var type in token.Parent.GetAncestorsOrThis<TTypeSyntax>())
45-
{
46-
if (this.IsTypeInInterfaceBaseList(type))
47-
{
48-
var service = document.GetRequiredLanguageService<IImplementInterfaceService>();
49-
50-
var info = await service.AnalyzeAsync(
51-
document, type, cancellationToken).ConfigureAwait(false);
52-
if (info is not null)
53-
{
54-
using var _ = ArrayBuilder<CodeAction>.GetInstance(out var codeActions);
55-
await foreach (var implementOptions in GetImplementOptionsAsync(document, info, cancellationToken))
56-
{
57-
var title = GetTitle(implementOptions);
58-
var equivalenceKey = GetEquivalenceKey(info, implementOptions);
59-
codeActions.Add(CodeAction.Create(
60-
title,
61-
cancellationToken => service.ImplementInterfaceAsync(
62-
document, info, options, implementOptions, cancellationToken),
63-
equivalenceKey));
64-
}
65-
66-
context.RegisterFixes(codeActions, context.Diagnostics);
67-
}
68-
69-
break;
70-
}
71-
}
72-
}
73-
74-
private static string GetTitle(ImplementInterfaceConfiguration options)
75-
{
76-
if (options.ImplementDisposePattern)
77-
{
78-
return options.Explicitly
79-
? CodeFixesResources.Implement_interface_explicitly_with_Dispose_pattern
80-
: CodeFixesResources.Implement_interface_with_Dispose_pattern;
81-
}
82-
else if (options.Explicitly)
83-
{
84-
return options.OnlyRemaining
85-
? CodeFixesResources.Implement_remaining_members_explicitly
86-
: CodeFixesResources.Implement_all_members_explicitly;
87-
}
88-
else if (options.Abstractly)
89-
{
90-
return CodeFixesResources.Implement_interface_abstractly;
91-
}
92-
else if (options.ThroughMember != null)
93-
{
94-
return string.Format(CodeFixesResources.Implement_interface_through_0, options.ThroughMember.Name);
95-
}
96-
else
97-
{
98-
return CodeFixesResources.Implement_interface;
99-
}
100-
}
101-
102-
private static string GetEquivalenceKey(
103-
ImplementInterfaceInfo state,
104-
ImplementInterfaceConfiguration options)
105-
{
106-
var interfaceType = state.InterfaceTypes.First();
107-
var typeName = interfaceType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
108-
109-
// Legacy part of the equivalence key. Kept the same to avoid test churn.
110-
var codeActionTypeName = options.ImplementDisposePattern
111-
? "Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction"
112-
: "Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction";
113-
114-
// Consider code actions equivalent if they correspond to the same interface being implemented elsewhere
115-
// in the same manner. Note: 'implement through member' means implementing the same interface through
116-
// an applicable member with the same name in the destination.
117-
return options.Explicitly.ToString() + ";" +
118-
options.Abstractly.ToString() + ";" +
119-
options.OnlyRemaining.ToString() + ":" +
120-
typeName + ";" +
121-
codeActionTypeName + ";" +
122-
options.ThroughMember?.Name;
123-
}
124-
125-
private static async IAsyncEnumerable<ImplementInterfaceConfiguration> GetImplementOptionsAsync(
126-
Document document, ImplementInterfaceInfo state, [EnumeratorCancellation] CancellationToken cancellationToken)
127-
{
128-
var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false);
129-
var syntaxFacts = document.GetRequiredLanguageService<ISyntaxFactsService>();
130-
var supportsImplicitImplementationOfNonPublicInterfaceMembers = syntaxFacts.SupportsImplicitImplementationOfNonPublicInterfaceMembers(document.Project.ParseOptions!);
131-
if (state.MembersWithoutExplicitOrImplicitImplementationWhichCanBeImplicitlyImplemented.Length > 0)
132-
{
133-
var totalMemberCount = 0;
134-
var inaccessibleMemberCount = 0;
135-
136-
foreach (var (_, members) in state.MembersWithoutExplicitOrImplicitImplementationWhichCanBeImplicitlyImplemented)
137-
{
138-
foreach (var member in members)
139-
{
140-
totalMemberCount++;
141-
142-
if (ContainsTypeLessAccessibleThan(member, state.ClassOrStructType, supportsImplicitImplementationOfNonPublicInterfaceMembers))
143-
inaccessibleMemberCount++;
144-
}
145-
}
146-
147-
// If all members to implement are inaccessible, then "Implement interface" codeaction
148-
// will be the same as "Implement interface explicitly", so there is no point in having both of them
149-
if (totalMemberCount != inaccessibleMemberCount)
150-
yield return new() { OnlyRemaining = true };
151-
152-
if (ShouldImplementDisposePattern(compilation, state, explicitly: false))
153-
yield return new() { OnlyRemaining = true, ImplementDisposePattern = true, };
154-
155-
var delegatableMembers = GetDelegatableMembers(document, state, cancellationToken);
156-
foreach (var member in delegatableMembers)
157-
yield return new() { ThroughMember = member };
30+
var type = token.Parent.GetAncestorsOrThis<TTypeSyntax>().LastOrDefault();
15831

159-
if (state.ClassOrStructType.IsAbstract)
160-
yield return new() { OnlyRemaining = true, Abstractly = true };
161-
}
162-
163-
if (state.MembersWithoutExplicitImplementation.Length > 0)
164-
{
165-
yield return new() { Explicitly = true };
166-
167-
if (ShouldImplementDisposePattern(compilation, state, explicitly: true))
168-
yield return new() { ImplementDisposePattern = true, Explicitly = true };
169-
}
170-
171-
if (AnyImplementedImplicitly(state))
172-
yield return new() { OnlyRemaining = true, Explicitly = true };
173-
}
174-
175-
private static bool AnyImplementedImplicitly(ImplementInterfaceInfo state)
176-
{
177-
if (state.MembersWithoutExplicitOrImplicitImplementation.Length != state.MembersWithoutExplicitImplementation.Length)
178-
{
179-
return true;
180-
}
181-
182-
for (var i = 0; i < state.MembersWithoutExplicitOrImplicitImplementation.Length; i++)
183-
{
184-
var (typeA, membersA) = state.MembersWithoutExplicitOrImplicitImplementation[i];
185-
var (typeB, membersB) = state.MembersWithoutExplicitImplementation[i];
186-
if (!typeA.Equals(typeB))
187-
{
188-
return true;
189-
}
190-
191-
if (!membersA.SequenceEqual(membersB))
192-
{
193-
return true;
194-
}
195-
}
196-
197-
return false;
198-
}
199-
200-
private static ImmutableArray<ISymbol> GetDelegatableMembers(
201-
Document document, ImplementInterfaceInfo state, CancellationToken cancellationToken)
202-
{
203-
var firstInterfaceType = state.InterfaceTypes.First();
32+
var service = document.GetRequiredLanguageService<IImplementInterfaceService>();
33+
var codeActions = await service.GetCodeActionsAsync(document, type, cancellationToken).ConfigureAwait(false);
20434

205-
return ImplementHelpers.GetDelegatableMembers(
206-
document,
207-
state.ClassOrStructType,
208-
t => t.GetAllInterfacesIncludingThis().Contains(firstInterfaceType),
209-
cancellationToken);
35+
context.RegisterFixes(codeActions, context.Diagnostics);
21036
}
21137
}

src/Analyzers/Core/CodeFixes/ImplementInterface/AbstractImplementInterfaceService.State.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
namespace Microsoft.CodeAnalysis.ImplementInterface;
1111

12-
internal abstract partial class AbstractImplementInterfaceService
12+
internal abstract partial class AbstractImplementInterfaceService<TTypeDeclarationSyntax>
1313
{
1414
internal sealed class State(
1515
Document document,
@@ -40,7 +40,7 @@ internal sealed class State(
4040
public ImmutableArray<(INamedTypeSymbol type, ImmutableArray<ISymbol> members)> MembersWithoutExplicitImplementation => Info.MembersWithoutExplicitImplementation;
4141

4242
public static State? Generate(
43-
AbstractImplementInterfaceService service,
43+
AbstractImplementInterfaceService<TTypeDeclarationSyntax> service,
4444
Document document,
4545
SemanticModel model,
4646
SyntaxNode interfaceNode,

0 commit comments

Comments
 (0)