Обнаружение везде перечисление преобразуется в строку

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

Пример: я хотел бы найти код, например string str = "Value: " + SomeEnum.someValue;

Я попытался заменить сам enum классом-оболочкой, содержащим неявные преобразования в тип перечисления и переопределяя ToString() в классе-оболочке, но когда я пытаюсь выполнить поиск переопределения ToString(), он дает мне список мест в решении, где ToString() вызывается на что угодно (и только там, где он явно указан). Поиск был выполнен с помощью ReSharper в Visual Studio.

Есть ли другой способ найти эти преобразования перечислимых строк? Прохождение всего решения вручную не похоже на удовольствие.

Ответ 1

Фокус в Roslyn заключается в использовании SemanticModel.GetTypeInfo(), а затем проверьте ConvertedType, чтобы найти эти неявные преобразования.

Полный пример:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Roslyn.Compilers;
using Roslyn.Compilers.CSharp;
using Roslyn.Services;
using Roslyn.Services.CSharp;
using Roslyn.Compilers.Common;

class Program
{
    static void Main(string[] args)
    {
        var code = @"enum E { V } class { static void Main() { string s = ""Value: "" + E.V; } }";
        var doc = Solution.Create(SolutionId.CreateNewId())
            .AddCSharpProject("foo", "foo")
            .AddMetadataReference(MetadataFileReference.CreateAssemblyReference("mscorlib"))
            .AddDocument("doc.cs", code);
        var stringType = doc.Project.GetCompilation().GetSpecialType(SpecialType.System_String);
        var e = doc.Project.GetCompilation().GlobalNamespace.GetTypeMembers("E").Single();
        var v = e.GetMembers("V").Single();
        var refs = v.FindReferences(doc.Project.Solution);
        var toStrings = from referencedLocation in refs
                        from r in referencedLocation.Locations
                        let node = GetNode(doc, r.Location)
                        let convertedType = doc.GetSemanticModel().GetTypeInfo(GetNode(doc, r.Location)).ConvertedType
                        where convertedType.Equals(stringType)
                        select r.Location;
        foreach (var loc in toStrings)
        {
            Console.WriteLine(loc);
        }
    }

    static CommonSyntaxNode GetNode(IDocument doc, CommonLocation loc)
    {
        return loc.SourceTree.GetRoot().FindToken(loc.SourceSpan.Start).Parent.Parent.Parent;
    }
}