Подтвердить что ты не робот

Простой образец завершения кода в Roslyn

Я хотел бы начать с завершения кода в Roslyn, но не смог найти простых примеров, показывающих, как выполнить завершение кода.

Что было бы хорошим примером для завершения этого кода, чтобы я мог получить все возможные элементы завершения (AKA Intellisense или CTRL + Space) в caretIndex?

static void Main(string[] args)
{
    var code = @"
    using System;
    public class Test
    {
        public void TestMethod()
        {
            var now = DateTime.Now;
            now.
        }
    }";
    Console.WriteLine(code);

    var st = SyntaxTree.ParseText(code);
    var caretIndex = code.IndexOf("now.") + 4;

    //how to get possible code completions at caret index? (Intellisense)
}
4b9b3361

Ответ 1

Roslyn предоставляет услуги завершения кода через интерфейсы ICompletionService и ICompletionProvider, но они, похоже, в основном являются внутренними и предназначены для доступа при размещении в Visual Studio. Тем не менее, можно получить сцепление с типами завершения кода С#, используя пару рефлекторных хаков, как показано на рисунке ScriptCS Pad. Если вы можете заставить это работать, я ожидаю, что вы должны получить завершение кода VS-класса.

В качестве альтернативы вы можете сделать это "вручную", используя общедоступные API, предоставленные Roslyn. Я не очень разбираюсь в них, но следующее должно начинаться с перечисления членов выражения слева от точки доступа к члену. Обратите внимание, что он игнорирует методы расширения и правила видимости, не обрабатывает ошибки и, вероятно, ошибочен многими другими способами. Тем не менее сделать это надежно, возможно, не квалифицирует как "простое" завершение кода.

var code = @"
    using System;
    public class Test
    {
        public void TestMethod()
        {
            var now = DateTime.Now;
            now.
        }
    }";
Console.WriteLine(code);

var syntaxTree = CSharpSyntaxTree.ParseText(code);
var compilation = CSharpCompilation.Create("foo")
    .AddReferences(MetadataReference.CreateAssemblyReference(typeof(DateTime).Assembly.FullName))
    .AddSyntaxTrees(syntaxTree);
var semanticModel = compilation.GetSemanticModel(syntaxTree);

var dotTextSpan = new TextSpan(code.IndexOf("now.") + 3, 1);
var memberAccessNode = (MemberAccessExpressionSyntax)syntaxTree.GetRoot().DescendantNodes(dotTextSpan).Last();

var lhsType = semanticModel.GetTypeInfo(memberAccessNode.Expression).Type;

foreach (var symbol in lhsType.GetMembers())
{
    if (!symbol.CanBeReferencedByName
        || symbol.DeclaredAccessibility != Accessibility.Public
        || symbol.IsStatic)
        continue;

    Console.WriteLine(symbol.Name);
}

РЕДАКТИРОВАТЬ. Обратите внимание, что этот ответ, вероятно, был устареван новыми битами Roslyn.

Ответ 2

Если у вас есть экземпляр Workspace, вы можете использовать общедоступный API рекомендаций из пакета Microsoft.CodeAnalysys.Workspaces:

public static class Recommender
{
     public static IEnumerable<ISymbol> GetRecommendedSymbolsAtPosition(SemanticModel semanticModel, int position, Workspace workspace, OptionSet options = null, CancellationToken cancellationToken = default(CancellationToken));
}

Он возвращает символы завершения при заданном смещении. Он не возвращает ключевые слова, но по состоянию на март 2016 года ребята из Roslyn работают над улучшением public api для завершения: https://github.com/dotnet/roslyn/issues/3538