2015-08-24 1 views
1

Я использую и пытаюсь выяснить, услуги анализа кода. В моем учебном процессе я хочу создать анализатор, который вызовет появление предупреждения, если операторы using размещены в верхней части файла кода , а не в объявлении пространства имен. Я также хочу, чтобы IDE предоставила мне быстрый ярлык, позволяющий легко фиксировать код сбоя.CodeFixProvider-производный класс: как правильно форматировать код, который перемещается в новом блоке?

Например, всякий раз, когда инструмент анализа кода видит это:

using System; 
using System.Collections.Generic; 

namespace MyNamespace 
{ 
    class TypeName 
    { 
    } 
} 

... Я хочу, чтобы показать предупреждение и предложить, чтобы превратить его в этом:

namespace MyNamespace 
{ 
    using System; 
    using System.Collections.Generic; 

    class TypeName 
    { 
    } 
} 

мне удалось получите мой класс анализатора (полученный от DiagnosticAnalyzer), работающий, как я хочу. Моя основная проблема прямо сейчас с классом CodeFixProvider.

Технически, прямо сейчас, это работает; операторы : переместились в объявления пространства имен. Однако форматирование не так хорошо. Вот то, что я на самом деле получить при попытке зафиксировать первый блок кода выше:

* 
namespace ConsoleApplication1 
{ 

    using System; 
    using System.Collections.Generic; 
    class TypeName 
    { 
    } 
} 

Звездочка символ представляет остаточную возврат каретки. Также обратите внимание на то, как происходит линейная разметка сразу после первой скобки пространства имен, и нет между использованием операторов и объявления класса. Я хочу, чтобы эта линия была перемещена вниз и сидела поверх класса.

Здесь (части интереса в пределах) мой CodeFixProvider -derived код класса:

public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) 
{ 
    foreach (var diagnostic in context.Diagnostics) 
    { 
     context.RegisterCodeFix(
      CodeAction.Create(
       title: Title, 
       createChangedDocument: c => ProvideDocumentAsync(context.Document, c), 
       equivalenceKey: Title), 
      diagnostic); 
    } 
} 

private async Task<Document> ProvideDocumentAsync(Document document, CancellationToken cancellationToken) 
{ 
    var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false) as CompilationUnitSyntax; 

    if (root == null) return null; 

    var newRootUsings = new SyntaxList<UsingDirectiveSyntax>(); 
    var newRoot = root.WithUsings(newRootUsings); 

    foreach (var namespaceDecl in newRoot.Members.OfType<NamespaceDeclarationSyntax>()) 
    { 
     NamespaceDeclarationSyntax newNsDecl = namespaceDecl; 

     foreach (var statement in root.Usings) 
     { 
      var newStatement = statement.WithLeadingTrivia(statement.GetLeadingTrivia().Union(new[] { Microsoft.CodeAnalysis.CSharp.SyntaxFactory.Whitespace(" ") })); 

      newNsDecl = newNsDecl.AddUsings(newStatement); 
     } 

     newRoot = newRoot.ReplaceNode(namespaceDecl, newNsDecl); 
    } 

    return document.WithSyntaxRoot(newRoot); 
} 

Как вы можете видеть, что я сделал выяснить, как добавить дополнительный отступ (с GetLeadingTrivia методом). Я полагаю, что я могу сделать то же самое для дополнительных строк, но почему-то я чувствую, что, вероятно, лучший способ, о котором я еще не знаю, довольно зеленый с этими новыми инструментами анализа/рефакторинга кода.

Итак, какие-либо рекомендации относительно того, как сделать форматирование - или что-нибудь еще в этом отношении - лучше?

UPDATE:

Это просто произошло со мной сегодня, что «право» форматирование для применения в поставщика кода исправления Рослин должен быть один применен в редакторе кода по умолчанию (в моем случае, Visual Studio 2015), с собственным набором правил.

Я понимаю, что класс Formatter внутри механизма компилятора позволяет «намекать» на редактор кода, что форматирование требуется на некоторых узлах/текстах. Исправление кода, пытающееся форматировать код дальше, вероятно, слишком много.

Если кто-то верит, что я ошибаюсь, вы очень можете позвонить. Я все еще тренирую колеса с Рослином и желаю учиться.

ответ

2

Добавить .WithAdditionalAnnotations(Formatter.Annotation), чтобы сообщить Roslyn, чтобы автоматически форматировать ваши изменения.

+0

На каком элементе? – Crono

+0

@Crono: Любой предок, содержащий все узлы, которые вы хотите отформатировать. – SLaks

+0

Так что это должен быть корневой элемент, так как я хочу избавиться от верхней оставшейся линии. Но как это повлияет на неизменные узлы? Например, если у меня есть метод, объявленный внутри класса 'TypeName', он будет переформатирован? – Crono

Смежные вопросы