使用代码修复提供程序

时间:2015-08-12 18:27:09

标签: c# algorithm roslyn

我之前的问题是为了解决局部变量/参数的状态。它工作正常,我稍微调整一下,现在看起来像这样:

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using System.Collections.Immutable;
using System.Linq;

namespace RefactoringEssentials.CSharp.Diagnostics
{
    [DiagnosticAnalyzer(LanguageNames.CSharp)]
    public class LocalVariableNotUsedAnalyzer : DiagnosticAnalyzer
    {
        private static readonly DiagnosticDescriptor descriptor = new DiagnosticDescriptor(
            CSharpDiagnosticIDs.LocalVariableNotUsedAnalyzerID,
            GettextCatalog.GetString("Local variable is never used"),
            GettextCatalog.GetString("Local variable is never used"),
            DiagnosticAnalyzerCategories.RedundanciesInDeclarations,
            DiagnosticSeverity.Warning,
            isEnabledByDefault: true,
            helpLinkUri: HelpLink.CreateFor(CSharpDiagnosticIDs.LocalVariableNotUsedAnalyzerID)
        );

        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(descriptor);

        public override void Initialize(AnalysisContext context)
        {
            context.RegisterSyntaxNodeAction(
                (nodeContext) =>
                {
                    Diagnostic diagnostic;
                    if (TryGetDiagnostic(nodeContext, out diagnostic))
                    {
                        nodeContext.ReportDiagnostic(diagnostic);
                    }
                },
                SyntaxKind.LocalDeclarationStatement
            );
        }


        private static bool TryGetDiagnostic(SyntaxNodeAnalysisContext nodeContext, out Diagnostic diagnostic)
        {
            diagnostic = default(Diagnostic);
            if (nodeContext.IsFromGeneratedCode())
                return false;

            var localDeclarationUnused = nodeContext.Node as LocalDeclarationStatementSyntax;
            var body = localDeclarationUnused?.Parent as BlockSyntax;
            if (body == null)
                return false;

            var dataFlow = nodeContext.SemanticModel.AnalyzeDataFlow(body);
            var variablesDeclared = dataFlow.VariablesDeclared;
            var variablesRead = dataFlow.ReadInside.Union(dataFlow.ReadOutside);
            var unused = variablesDeclared.Except(variablesRead).ToArray();
            if (unused == null)
                return false;

            if (localDeclarationUnused.Declaration == null || !localDeclarationUnused.Declaration.Variables.Any())
                return false; 

            var localDeclarationSymbol = nodeContext.SemanticModel.GetDeclaredSymbol(localDeclarationUnused.Declaration.Variables.FirstOrDefault());
            if (unused.Any())
            {
                if (unused.Contains(localDeclarationSymbol))
                {
                    diagnostic = Diagnostic.Create(descriptor, localDeclarationUnused.Declaration.GetLocation());
                    return true;
                }
            }
            return false;
        }
    }
}

在检查NUnit测试的成功率时,我已经构建了一个代码修复提供程序,它在40%的时间内工作。即使我知道代码是正常的,我的机器上似乎只有在运行代码修复时才会出现错误。我知道这是因为我可以调试分析仪进行测试,每一个都很好。

当代码修复提供程序正在运行时,我有这个错误,由于某种原因我无法动摇:“System.ArgumentNullException:Value不能为null。 参数名称:声明“ 我已经尝试调试代码修复提供程序,但没有任何显示我可以找到该声明参数的位置。

此外,我使用的代码修复提供程序需要替换和删除节点。但我不习惯修复错误并添加内容,我想知道如何做这样的事情。

这是我的代码修复提供程序,目前不处理添加信息:

using Microsoft.CodeAnalysis;
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CodeFixes;
using System.Threading.Tasks;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace RefactoringEssentials.CSharp.Diagnostics
{

    [ExportCodeFixProvider(LanguageNames.CSharp), System.Composition.Shared]
    public class LocalVariableNotUsedCodeFixProvider : CodeFixProvider
    {
        public override ImmutableArray<string> FixableDiagnosticIds
        {
            get
            {
                return ImmutableArray.Create(CSharpDiagnosticIDs.LocalVariableNotUsedAnalyzerID);
            }
        }

        public override FixAllProvider GetFixAllProvider()
        {
            return WellKnownFixAllProviders.BatchFixer;
        }

        public async override Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var document = context.Document;
            var cancellationToken = context.CancellationToken;
            var span = context.Span;
            var diagnostics = context.Diagnostics;
            var root = await document.GetSyntaxRootAsync(cancellationToken);
            var diagnostic = diagnostics.First();
            var node = root.FindNode(context.Span);
            if (node == null)
                return;
            var newRoot = root.RemoveNode(node, SyntaxRemoveOptions.KeepNoTrivia);
            context.RegisterCodeFix(CodeActionFactory.Create(node.Span, diagnostic.Severity, "Remove unused local variable", document.WithSyntaxRoot(newRoot)), diagnostic);
        }
    }
}

以下是我用来确保修复正常的测试。最后两个运行得很好: - )

using NUnit.Framework;
using RefactoringEssentials.CSharp.Diagnostics;

namespace RefactoringEssentials.Tests.CSharp.Diagnostics
{
    [TestFixture]
    public class LocalVariableNotUsedTests : CSharpDiagnosticTestBase
    {
        [Test]
        public void TestUnusedVariable()
        {
            var input = @"
class TestClass {
    void TestMethod ()
    {
        $int i$;
    }
}";
            var output = @"
class TestClass {
    void TestMethod ()
    {
    }
}";
            Analyze<LocalVariableNotUsedAnalyzer>(input, output);
        }

        [Test]
        public void TestUnusedVariable2()
        {
            var input2 = @"
class TestClass {
    void TestMethod ()
    {
        $int i, j$;
        j = 1;
    }
}";
            var output2 = @"
class TestClass {
    void TestMethod ()
    {
        int j;
        j = 1;
    }
}";
            Analyze<LocalVariableNotUsedAnalyzer>(input2, output2);
        }

        [Test]
        public void TestUsedVariable()
        {
            var input1 = @"
class TestClass {
    void TestMethod ()
    {
        $int i = 0$;
    }
}";
            var input2 = @"
class TestClass {
    void TestMethod ()
    {
        int i;
        i = 0;
    }
}";
            Analyze<LocalVariableNotUsedAnalyzer>(input1);
            Analyze<LocalVariableNotUsedAnalyzer>(input2);
        }

        [Test]
        public void TestUnusedForeachVariable()
        {
            var input = @"
class TestClass {
    void TestMethod ()
    {
        var array = new int[10];
        foreach (var i in array) {
        }
    }
}";
            Analyze<LocalVariableNotUsedAnalyzer>(input);
        }

        [Test]
        public void TestUsedForeachVariable()
        {
            var input = @"
class TestClass {
    void TestMethod ()
    {
        var array = new int[10];
        int j = 0;
        foreach (var i in array) {
            j += i;
        }
    }
}";
            Analyze<LocalVariableNotUsedAnalyzer>(input);
        }
    }
}

有什么不清楚的地方,我会确保适当地更新我的帖子。

0 个答案:

没有答案