Skip to content

Commit 442dd53

Browse files
committed
Наработки по фиксеру FileServiceInterfaceInjectionCodeFix
1 parent a051297 commit 442dd53

9 files changed

Lines changed: 193 additions & 4 deletions

File tree

Roslyn.Testing/Analyzer/CSharpDiagnosticAnalyzerTest.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Collections.Generic;
2+
using System.Linq;
23
using Microsoft.CodeAnalysis;
34
using Microsoft.CodeAnalysis.Diagnostics;
45
using Roslyn.Testing.Model;
@@ -24,7 +25,7 @@ protected CSharpDiagnosticAnalyzerTest()
2425

2526
protected virtual IEnumerable<MetadataReference> GetAdditionalReferences()
2627
{
27-
return null;
28+
return Enumerable.Empty<MetadataReference>();
2829
}
2930

3031
/// <summary>

Roslyn.Testing/CodeFix/CSharpCodeFixProviderTest.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Collections.Generic;
2+
using System.Linq;
23
using Microsoft.CodeAnalysis;
34
using Microsoft.CodeAnalysis.CodeFixes;
45
using Microsoft.CodeAnalysis.Diagnostics;
@@ -13,14 +14,20 @@ public abstract class CSharpCodeFixProviderTest<TDiagnosticAnalyzer, TCodeFixPro
1314
{
1415
#region To be implemented by Test classes
1516

17+
/// <inheritdoc />
18+
public override string Filepath => _codeFixProvider.GetType().Name;
19+
20+
/// <inheritdoc />
21+
public override string PathToTestData => "./TestData/CodeFix/";
22+
1623
protected virtual IEnumerable<MetadataReference> GetAdditionalReferences()
1724
{
18-
return null;
25+
return Enumerable.Empty<MetadataReference>();
1926
}
2027

2128
#endregion
2229

23-
private readonly CodeFixProvider _codeFixProvider;
30+
private readonly TCodeFixProvider _codeFixProvider;
2431

2532
private readonly TDiagnosticAnalyzer _diagnosticAnalyzer;
2633

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System.Collections.Generic;
2+
using System.IO.Abstractions.Analyzers.Analyzers;
3+
using System.IO.Abstractions.Analyzers.CodeFixes;
4+
using Microsoft.CodeAnalysis;
5+
using Roslyn.Testing.CodeFix;
6+
using Xunit;
7+
8+
namespace System.IO.Abstractions.Analyzers.Tests.CodeFixes
9+
{
10+
public class FileServiceInterfaceInjectionCodeFixTests :
11+
CSharpCodeFixProviderTest<FileServiceInterfaceInjectionAnalyzer, FileServiceInterfaceInjectionCodeFix>
12+
{
13+
[Theory]
14+
[InlineData("BeforeFix.txt", "AfterFix.txt")]
15+
public void CodeFix(string sourceBefore, string sourceAfter)
16+
{
17+
var sourceBeforeFix = ReadFile(sourceBefore);
18+
var sourceAfterFix = ReadFile(sourceAfter);
19+
VerifyFix(sourceBeforeFix, sourceAfterFix, 0, true);
20+
}
21+
22+
protected override IEnumerable<MetadataReference> GetAdditionalReferences() => new[]
23+
{
24+
MetadataReference.CreateFromFile(typeof(IFileSystem).Assembly.Location)
25+
};
26+
}
27+
}

System.IO.Abstractions.Analyzers.Tests/System.IO.Abstractions.Analyzers.Tests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
<ItemGroup>
1010
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
11-
<PackageReference Include="xunit" Version="2.4.0" />
11+
<PackageReference Include="xunit" Version="2.4.1" />
1212
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
1313
</ItemGroup>
1414

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System.IO.Abstractions;
2+
3+
namespace SomeNameSpace
4+
{
5+
public class WithOutFileSystem
6+
{
7+
private readonly IFileSystem _fileSystem;
8+
9+
public WithOutFileSystem(IFileSystem fileSystem)
10+
{
11+
_fileSystem = fileSystem;
12+
}
13+
14+
public void SomeMethod()
15+
{
16+
const string filePath = "C:\\temp.txt";
17+
18+
if (File.Exists(filePath))
19+
{
20+
File.Delete(filePath);
21+
}
22+
}
23+
}
24+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using System.IO;
2+
3+
namespace SomeNameSpace
4+
{
5+
public class WithOutFileSystem
6+
{
7+
public WithOutFileSystem()
8+
{
9+
}
10+
11+
public void SomeMethod()
12+
{
13+
const string filePath = "C:\\temp.txt";
14+
15+
if (File.Exists(filePath))
16+
{
17+
File.Delete(filePath);
18+
}
19+
}
20+
}
21+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using System.Linq;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
using Microsoft.CodeAnalysis;
5+
using Microsoft.CodeAnalysis.CodeActions;
6+
using Microsoft.CodeAnalysis.CSharp;
7+
using Microsoft.CodeAnalysis.CSharp.Syntax;
8+
using Microsoft.CodeAnalysis.Editing;
9+
using Microsoft.CodeAnalysis.Formatting;
10+
using Microsoft.CodeAnalysis.Simplification;
11+
using SF = Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
12+
13+
namespace System.IO.Abstractions.Analyzers.CodeActions
14+
{
15+
/// <inheritdoc />
16+
public class FileServiceInterfaceInjectionCodeAction : CodeAction
17+
{
18+
private readonly ConstructorDeclarationSyntax _constructor;
19+
20+
private readonly Document _document;
21+
22+
public FileServiceInterfaceInjectionCodeAction(string title, Document document, ConstructorDeclarationSyntax constructor)
23+
{
24+
_constructor = constructor;
25+
_document = document;
26+
Title = title;
27+
}
28+
29+
public override string Title { get; }
30+
31+
public override string EquivalenceKey => Title;
32+
33+
protected override async Task<Document> GetChangedDocumentAsync(CancellationToken cancellationToken)
34+
{
35+
var editor = await DocumentEditor.CreateAsync(_document, cancellationToken).ConfigureAwait(false);
36+
37+
var parameter = SF.Parameter(SF.Identifier("fileSystem"))
38+
.WithType(SF.ParseTypeName(nameof(IFileSystem)))
39+
.WithAdditionalAnnotations(Formatter.Annotation, Simplifier.Annotation)
40+
.NormalizeWhitespace();
41+
42+
if (!(_constructor.Parent is ClassDeclarationSyntax classDeclarationSyntax))
43+
{
44+
editor.AddParameter(_constructor, parameter);
45+
46+
return editor.GetChangedDocument();
47+
}
48+
49+
var fileSystem = classDeclarationSyntax.Members
50+
.OfType<FieldDeclarationSyntax>()
51+
.FirstOrDefault(x => x.NormalizeWhitespace().ToFullString().Equals(nameof(IFileSystem)));
52+
53+
if (fileSystem != null)
54+
{
55+
return editor.GetChangedDocument();
56+
}
57+
58+
var fileSystemPropertyDeclaration = SF.FieldDeclaration(SF.VariableDeclaration(SF.IdentifierName(nameof(IFileSystem)))
59+
.WithVariables(SF.SingletonSeparatedList(SF.VariableDeclarator(SF.Identifier("_fileSystem")))))
60+
.WithModifiers(SF.TokenList(SF.Token(SyntaxKind.PrivateKeyword),
61+
SF.Token(SyntaxKind.ReadOnlyKeyword)));
62+
63+
editor.InsertMembers(classDeclarationSyntax,
64+
0,
65+
new SyntaxNode[]
66+
{ fileSystemPropertyDeclaration });
67+
68+
editor.AddParameter(_constructor, parameter);
69+
70+
return editor.GetChangedDocument();
71+
}
72+
}
73+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System.Collections.Immutable;
2+
using System.Composition;
3+
using System.IO.Abstractions.Analyzers.Analyzers;
4+
using System.IO.Abstractions.Analyzers.CodeActions;
5+
using System.Threading.Tasks;
6+
using Microsoft.CodeAnalysis;
7+
using Microsoft.CodeAnalysis.CodeFixes;
8+
using Microsoft.CodeAnalysis.CSharp.Syntax;
9+
10+
namespace System.IO.Abstractions.Analyzers.CodeFixes
11+
{
12+
[Shared]
13+
[ExportCodeFixProvider(LanguageNames.CSharp)]
14+
public class FileServiceInterfaceInjectionCodeFix : CodeFixProvider
15+
{
16+
private const string Title = "Use System.IO.Abstractions";
17+
18+
public sealed override ImmutableArray<string> FixableDiagnosticIds { get; } =
19+
ImmutableArray.Create(FileServiceInterfaceInjectionAnalyzer.DiagnosticId);
20+
21+
public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;
22+
23+
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
24+
{
25+
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
26+
var constructorDeclarationSyntax = root.FindNode(context.Span).FirstAncestorOrSelf<ConstructorDeclarationSyntax>();
27+
28+
context.RegisterCodeFix(new FileServiceInterfaceInjectionCodeAction(Title,
29+
context.Document,
30+
constructorDeclarationSyntax),
31+
context.Diagnostics);
32+
}
33+
}
34+
}

System.IO.Abstractions.Analyzers/System.IO.Abstractions.Analyzers.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="2.6.3" />
1010
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.10.0" PrivateAssets="all" />
1111
<PackageReference Update="NETStandard.Library" PrivateAssets="all" />
12+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="2.10.0" />
13+
<PackageReference Include="Roslyn.Diagnostics.Analyzers" Version="2.6.3" />
1214
<PackageReference Include="System.ComponentModel.Composition" Version="4.5.0" />
1315
<PackageReference Include="System.IO.Abstractions" Version="3.0.10" />
1416
</ItemGroup>

0 commit comments

Comments
 (0)