Roslyn Analyzer - Поиск текущей конкретной реализации вызова метода интерфейса - PullRequest
0 голосов
/ 20 сентября 2018

Я пытаюсь написать анализатор Roslyn, который обнаруживает вызов метода из конкретной реализации интерфейса, но у меня возникают проблемы с определением типа реализации.

Он правильно определяет метод, когда я использую переменную, типизированную в качестве конкретной реализации, но не когда я использую переменную, типизированную в качестве интерфейса.В основном пытаемся выяснить, как получить тип базовой реализации интерфейса, используя анализ кода Roslyn Apis

Это пример кода для анализа.Он правильно обнаруживает второй Operate вызов метода, но не первый, хотя оба используют конкретную реализацию в Operable

using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            IOperable ioperable = new Operable();
            ioperable.Operate();

            Operable operable = new Operable();
            operable.Operate();
        }
    }

    public interface IOperable
    {
        void Operate();
    }

    public class Operable : IOperable
    {
        public void Operate()
        {

        }
    }
}

Это мой текущий источник:

public override void Initialize(AnalysisContext context)
{
    context.RegisterSyntaxNodeAction(AnalyzeInvocation, SyntaxKind.InvocationExpression);
}

private static void AnalyzeInvocation(SyntaxNodeAnalysisContext context)
{
    var invocation = (InvocationExpressionSyntax)context.Node;

    var memberAccess = invocation.Expression as MemberAccessExpressionSyntax;
    if (memberAccess == null || !memberAccess.IsKind(SyntaxKind.SimpleMemberAccessExpression))
    {
        return;
    }

    var ident = memberAccess.Name.Identifier;
    if (ident.ToString().ToLower() != "operate")
    {
        return;
    }

    var calledFromType = context.SemanticModel.GetTypeInfo(memberAccess.Expression).Type;
    if (calledFromType.MetadataName != "Operable")
    {
        return;
    }
    context.ReportDiagnostic(Diagnostic.Create(Rule, context.Node.GetLocation()));
}

1 Ответ

0 голосов
/ 20 сентября 2018

Я вас разочарую, но Roslyn является статическим анализатором и не имеет возможности извлекать динамическую информацию для типов, вызовов и т. Д. По умолчанию.

Чтобы достичь этого, вам нужно реализовать собственный динамический анализ в roslyn, который будет исследовать все присваивания переменной, передачу аргументов и т. Д., Чтобы определить всю информацию об объекте (тип, методы и т. Д.), Который онможет иметь текущее время в коде.

Просто для ясности в приведенном ниже примере:

public interface IOperable
{
    void Operate();
}

public class Operable : IOperable
{
   ...
}

public class OperableOther : IOperable
{
   ...
}

...

IOperable ioperable = new Operable();
ioperable.Operate(); // at this time will invoke Operable.Operate();

ioperable = new OperableOther();
ioperable.Operate(); // at this time will OperableOther.Operate();

Roslyn может получить информацию времени компиляции о переменной ioperable, что это IOperable, но не может дать, что он будет Operable с первого присваивания и OperableOther со второго.Но вы можете сделать это самостоятельно, если накопите все переменные и т. Д.

...