Я использую visual-studio-2015 и пытаюсь выяснить, roslyn услуги анализа кода. В моем учебном процессе я хочу создать анализатор, который вызовет появление предупреждения, если операторы using
размещены в верхней части файла кода c#, а не в объявлении пространства имен. Я также хочу, чтобы 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
внутри механизма компилятора позволяет «намекать» на редактор кода, что форматирование требуется на некоторых узлах/текстах. Исправление кода, пытающееся форматировать код дальше, вероятно, слишком много.
Если кто-то верит, что я ошибаюсь, вы очень можете позвонить. Я все еще тренирую колеса с Рослином и желаю учиться.
На каком элементе? – Crono
@Crono: Любой предок, содержащий все узлы, которые вы хотите отформатировать. – SLaks
Так что это должен быть корневой элемент, так как я хочу избавиться от верхней оставшейся линии. Но как это повлияет на неизменные узлы? Например, если у меня есть метод, объявленный внутри класса 'TypeName', он будет переформатирован? – Crono