generated from VeyronSakai/RoslynAnalyzerTemplate
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #89 from VeyronSakai/feature/inject-attribute-code…
…-fix Add InjectAttributeCodeFixProvider
- Loading branch information
Showing
8 changed files
with
172 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
27 changes: 27 additions & 0 deletions
27
VContainerAnalyzer.Test/InjectAttributeCodeFixProviderTest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// Copyright (c) 2020-2024 VeyronSakai. | ||
// This software is released under the MIT License. | ||
|
||
using System.Threading.Tasks; | ||
using NUnit.Framework; | ||
using Verify = | ||
Microsoft.CodeAnalysis.CSharp.Testing.NUnit.CodeFixVerifier<VContainerAnalyzer.Analyzers.FieldAnalyzer, | ||
VContainerAnalyzer.CodeFixProviders.InjectAttributeCodeFixProvider>; | ||
|
||
namespace VContainerAnalyzer.Test; | ||
|
||
[TestFixture] | ||
public class InjectAttributeCodeFixProviderTest | ||
{ | ||
[Test] | ||
public async Task TypeNameContainingLowercase_CodeFixed() | ||
{ | ||
var source = Helper.GetJoinedFilesContentText("FieldInjectionClass.cs", "EmptyClassStub.cs"); | ||
var fixedSource = Helper.GetJoinedFilesContentText("FieldInjectionClassFixed.txt", "EmptyClassStub.cs"); | ||
|
||
var expected = Verify.Diagnostic() | ||
.WithSpan(22, 10, 22, 16) | ||
.WithArguments("_field1"); | ||
|
||
await Verify.VerifyCodeFixAsync(source, expected, fixedSource); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
13 changes: 13 additions & 0 deletions
13
VContainerAnalyzer.Test/TestData/FieldInjectionClassFixed.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// Copyright (c) 2020-2024 VeyronSakai. | ||
// This software is released under the MIT License. | ||
|
||
using VContainer; | ||
|
||
namespace VContainerAnalyzer.Test.TestData | ||
{ | ||
public class FieldInjectionClass | ||
{ | ||
private EmptyClassStub _field1; | ||
private EmptyClassStub _field2; | ||
} | ||
} |
Binary file modified
BIN
+5.5 KB
(140%)
VContainerAnalyzer.Unity/Assets/Plugins/VContainerAnalyzer/VContainerAnalyzer.dll
Binary file not shown.
97 changes: 97 additions & 0 deletions
97
VContainerAnalyzer/CodeFixProviders/InjectAttributeCodeFixProvider.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
// Copyright (c) 2020-2024 VeyronSakai. | ||
// This software is released under the MIT License. | ||
|
||
using System.Collections.Generic; | ||
using System.Collections.Immutable; | ||
using System.Composition; | ||
using System.Linq; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CodeActions; | ||
using Microsoft.CodeAnalysis.CodeFixes; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using SyntaxFactory = Microsoft.CodeAnalysis.CSharp.SyntaxFactory; | ||
|
||
namespace VContainerAnalyzer.CodeFixProviders; | ||
|
||
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(InjectAttributeCodeFixProvider)), Shared] | ||
public sealed class InjectAttributeCodeFixProvider : CodeFixProvider | ||
{ | ||
public override ImmutableArray<string> FixableDiagnosticIds { get; } = ImmutableArray.Create(Rules.Rule0002.Id); | ||
|
||
public override FixAllProvider GetFixAllProvider() | ||
{ | ||
return WellKnownFixAllProviders.BatchFixer; | ||
} | ||
|
||
public override async Task RegisterCodeFixesAsync(CodeFixContext context) | ||
{ | ||
var root = await context | ||
.Document | ||
.GetSyntaxRootAsync(context.CancellationToken) | ||
.ConfigureAwait(false); | ||
|
||
var diagnostic = context.Diagnostics.First(); | ||
var diagnosticSpan = diagnostic.Location.SourceSpan; | ||
var declaration = root? | ||
.FindToken(diagnosticSpan.Start) | ||
.Parent? | ||
.AncestorsAndSelf() | ||
.OfType<MemberDeclarationSyntax>() | ||
.FirstOrDefault(); | ||
|
||
if (declaration == null) | ||
{ | ||
return; | ||
} | ||
|
||
if (declaration is not FieldDeclarationSyntax && declaration is not PropertyDeclarationSyntax) | ||
{ | ||
return; | ||
} | ||
|
||
context.RegisterCodeFix( | ||
CodeAction.Create( | ||
"Remove InjectAttribute", | ||
cancellationToken => | ||
RemoveInjectAttribute(context.Document, declaration, cancellationToken), | ||
FixableDiagnosticIds.Single()), | ||
context.Diagnostics); | ||
} | ||
|
||
private static async Task<Document> RemoveInjectAttribute(Document document, MemberDeclarationSyntax declaration, | ||
CancellationToken cancellationToken) | ||
{ | ||
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); | ||
var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); | ||
var newAttributeLists = new List<AttributeListSyntax>(); | ||
|
||
foreach (var attributeList in declaration.AttributeLists) | ||
{ | ||
var nodesToRemove = new List<AttributeSyntax>(); | ||
|
||
foreach (var attribute in attributeList.Attributes) | ||
{ | ||
var attributeType = model?.GetTypeInfo(attribute).Type; | ||
if (attributeType != null && attributeType.IsVContainerInjectAttribute()) | ||
{ | ||
nodesToRemove.Add(attribute); | ||
} | ||
} | ||
|
||
var newAttributes = attributeList.RemoveNodes(nodesToRemove, SyntaxRemoveOptions.KeepNoTrivia); | ||
if (newAttributes.Attributes.Any()) | ||
{ | ||
newAttributeLists.Add(newAttributes); | ||
} | ||
} | ||
|
||
var newDeclaration = declaration | ||
.WithAttributeLists(SyntaxFactory.List(newAttributeLists)) | ||
.WithLeadingTrivia(declaration.GetLeadingTrivia()); | ||
|
||
var newRoot = root?.ReplaceNode(declaration, newDeclaration); | ||
return newRoot == null ? document : document.WithSyntaxRoot(newRoot); | ||
} | ||
} |