2014-04-22 2 views
2

코드의 일부 구문을 변경하는 Visual Studio 용 확장 프로그램을 만들려고합니다. 사실, 나는이 이름이 회사에서 사용하는 규칙에 맞지 않으면 변수의 이름을 변경하는 첫 번째 단계를 수행했습니다. 예를 들어하십시오 MultiLineCommentC# Roslyn이 주석 유형 변경

/*Here it's a MultiLine one*/ 
속으로 (SingleLineComment)

//this is a single line Comment 

:

int iNewVariable; 
double dblTest; 

가 지금은 이러한 종류의 주석을 변경해야합니다 :

int newVariable; 
double test; 

는로 변경됩니다

Roslyn Sy를 사용합니다. ntax Visualiser는 올바른 코드를 만들 수있는 종류와 종류를 찾지 만 아무 것도 작동하지 않습니다. 은 여기 내가 진단을 위해 무슨 짓을했는지의 :

여기
using System; 
using System.Collections.Generic; 
using System.Collections.Immutable; 
using System.Linq; 
using System.Threading; 
using Microsoft.CodeAnalysis; 
using Microsoft.CodeAnalysis.Diagnostics; 
using Microsoft.CodeAnalysis.CSharp; 
using Microsoft.CodeAnalysis.CSharp.Syntax; 

namespace CodeFix 
{ 
    [DiagnosticAnalyzer] 
    [ExportDiagnosticAnalyzer(DiagnosticId, LanguageNames.CSharp)] 
    public class DiagnosticAnalyzer : ISyntaxNodeAnalyzer<SyntaxKind> 
    { 
     internal const string DiagnosticId = "CodeFix"; 
     internal const string Description = "Mauvais formattage"; 
     internal const string MessageFormat = "'{0}'"; 
     internal const string Category = "Correction"; 

     internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Description, MessageFormat, Category, DiagnosticSeverity.Warning); 

     public ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics 
     { 
      get { return ImmutableArray.Create(Rule); } 
     } 
     public ImmutableArray<SyntaxKind> SyntaxKindsOfInterest //Ce qui nous intéresse 
     { 
      get 
      { 
       return ImmutableArray.Create(SyntaxKind.IfStatement, SyntaxKind.ElseClause, SyntaxKind.LocalDeclarationStatement, SyntaxKind.ConstKeyword, SyntaxKind.SingleLineCommentTrivia, SyntaxKind.SimpleAssignmentExpression); 
      } 
     } 
     public void AnalyzeNode(SyntaxNode node, SemanticModel model, Action<Diagnostic> addDiagnostic, CancellationToken cancellationToken) //Analyse des Nodes 
     { 

      var ifStatement = node as IfStatementSyntax; //Récupération des IfStatement parmis tous les nodes 
      if (ifStatement != null && 
       ifStatement.Statement != null && 
       !ifStatement.Statement.IsKind(SyntaxKind.Block)) 
      { 
       addDiagnostic(Diagnostic.Create(Rule, ifStatement.IfKeyword.GetLocation(), "Le if require des crochets")); 
      } 

      var elseClause = node as ElseClauseSyntax; //Récupération des Else parmis tous les nodes 
      if (elseClause != null && 
       elseClause.Statement != null && 
       !elseClause.Statement.IsKind(SyntaxKind.Block) && //Pas que ce soit déjà un block avec {} 
       !elseClause.Statement.IsKind(SyntaxKind.IfStatement)) //A cause des else if 
      { 
       addDiagnostic(Diagnostic.Create(Rule, elseClause.ElseKeyword.GetLocation(), "le else require des crochets")); 
      } 

     } 
    } 
    internal class IDiagnosticAnalyzer : ISyntaxTreeAnalyzer 
    { 
     internal const string DiagnosticIdComment = "CommentChanger"; 
     internal const string DescriptionComment = "Les commentaires doivent être en format /* */"; 
     internal const string MessageFormatComment = "'{0}' doit être en multiline"; 
     internal const string CategoryComment = "Renommage"; 

     internal static DiagnosticDescriptor RuleComment = new DiagnosticDescriptor(DiagnosticIdComment, DescriptionComment, MessageFormatComment, CategoryComment, DiagnosticSeverity.Warning); 

     public ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics 
     { 
      get { return ImmutableArray.Create(RuleComment); } 
     } 

     public void AnalyzeSyntaxTree(SyntaxTree tree, Action<Diagnostic> addDiagnostic, CancellationToken cancellationToken) 
     { 
      var root = tree.GetRoot(); 
      var trivia = root.DescendantTrivia(); 
      var a = trivia.Where(x => x.IsKind(SyntaxKind.SingleLineCommentTrivia)).ToList(); 

      foreach (var b in a) 
      { 
       addDiagnostic(Diagnostic.Create(RuleComment, b.GetLocation(), "Commentaire sur une ligne")); 
      } 
     } 
    } 

} 

가 CodeFix입니다 :

using System.Collections.Generic; 
using System.Linq; 
using System.Threading; 
using System.Threading.Tasks; 
using Microsoft.CodeAnalysis; 
using Microsoft.CodeAnalysis.CodeFixes; 
using Microsoft.CodeAnalysis.CodeActions; 
using Microsoft.CodeAnalysis.CSharp; 
using Microsoft.CodeAnalysis.CSharp.Syntax; 
using Microsoft.CodeAnalysis.Rename; 
using Microsoft.CodeAnalysis.Text; 
using Microsoft.CodeAnalysis.Formatting; 
using System; 

namespace CodeFix 
{ 
    [ExportCodeFixProvider(DiagnosticAnalyzer.DiagnosticId, LanguageNames.CSharp)] 
    internal class CodeFixProvider : ICodeFixProvider 
    { 
     public IEnumerable<string> GetFixableDiagnosticIds() 
     { 
      return new[] { DiagnosticAnalyzer.DiagnosticId }; 
     } 

     public async Task<IEnumerable<CodeAction>> GetFixesAsync(Document document, TextSpan span, IEnumerable<Diagnostic> diagnostics, CancellationToken cancellationToken) 
     { 
      var root = await document.GetSyntaxRootAsync(cancellationToken); //Document à utiliser (root) 
      var token = root.FindToken(span.Start); // 


      if (token.IsKind(SyntaxKind.IfKeyword)) 
      { 
       var ifStatement = (IfStatementSyntax)token.Parent; 
       var newIfStatement = ifStatement 
        .WithStatement(SyntaxFactory.Block(ifStatement.Statement)) 
        .WithAdditionalAnnotations(Formatter.Annotation); //Pour que ce soit indenté juste 

       var newRoot = root.ReplaceNode(ifStatement, newIfStatement); 

       return new[] { CodeAction.Create("Ajouter des crochets", document.WithSyntaxRoot(newRoot)) }; 
      } 

      if (token.IsKind(SyntaxKind.ElseKeyword)) 
      { 
       var elseClause = (ElseClauseSyntax)token.Parent; 
       var newElseClause = elseClause 
        .WithStatement(SyntaxFactory.Block(elseClause.Statement)) 
        .WithAdditionalAnnotations(Formatter.Annotation); 

       var newRoot = root.ReplaceNode(elseClause, newElseClause); 

       return new[] { CodeAction.Create("Ajouter des crochets", document.WithSyntaxRoot(newRoot)) }; 
      } 

      if (token.IsKind(SyntaxKind.SingleLineCommentTrivia)) 
      { 

       var root1 = await document.GetSyntaxRootAsync(cancellationToken); 
       var token1 = root1.FindToken(span.Start); 
       var allTrivia = token1.GetAllTrivia(); 
       foreach (var singleTrivia in allTrivia) 
       { 
        if (singleTrivia.IsKind(SyntaxKind.SingleLineCommentTrivia)) 
        { 
         var commentContent = singleTrivia.ToString().Replace("//", string.Empty); 
         var newComment = SyntaxFactory.Comment(string.Format("/*{0}*/", commentContent)); 
         var newRoot = root.ReplaceTrivia(singleTrivia, newComment); 
         return new[] { CodeAction.Create("Convert to multiline", document.WithSyntaxRoot(newRoot)) }; 
        } 
       } 

      }  

      return null; 
     }  
    } 

} 

사용자는 내 프로그램을 제공하고 주석이 변경 될 광고를 클릭한다.

그러나 프로그램을 호출해야하는 곳에서는 프로그램이 실행되지 않습니다.

내가 로슬린 내 첫 번째 단계를하고 있어요, 그래서 이미 많은 것들을 모르겠지만, 나는 그것에 대해 배우고 ..

편집 :

모든 코드 덧붙여서

답변

7

한 줄 주석을 여러 줄 주석으로 대체하는 Diagnostic과 함께 CodeFix를 사용하는 예제를 작성했습니다. 여기에 몇 가지 코드가 있습니다. 그것을 많이는 한 줄을 찾아 ISyntaxTreeAnalyzer에서 http://channel9.msdn.com/Events/Build/2014/2-577

AnalyzeSyntaxTree 구현에서 볼 수있는 빌드에서 더스틴 캠벨의 로슬린 데모를 기반으로하는 코멘트 : ICodeFixProvider에서

[DiagnosticAnalyzer] 
[ExportDiagnosticAnalyzer(DiagnosticId, LanguageNames.CSharp)] 
internal class DiagnosticAnalyzer : ISyntaxTreeAnalyzer 
{ 
    internal const string DiagnosticId = "CommentChanger"; 
    internal const string Description = "Single comments should be multiline comments"; 
    internal const string MessageFormat = "'{0}' should be multiline"; 
    internal const string Category = "Naming"; 

    internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Description, MessageFormat, Category, DiagnosticSeverity.Warning); 

    public ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics 
    { 
     get { return ImmutableArray.Create(Rule); } 
    } 

    public void AnalyzeSyntaxTree(SyntaxTree tree, Action<Diagnostic> addDiagnostic, CancellationToken cancellationToken) 
    { 
     var root = tree.GetRoot(); 
     var trivia = root.DescendantTrivia(); 
     var a = trivia.Where(x => x.IsKind(SyntaxKind.SingleLineCommentTrivia)).ToList(); 

     foreach(var b in a) 
     { 
      addDiagnostic(Diagnostic.Create(Rule, b.GetLocation(), "Single comment")); 
     } 
    } 
} 

GetFixesAsync 구현 :

public async Task<IEnumerable<CodeAction>> GetFixesAsync(Document document, TextSpan span, IEnumerable<Diagnostic> diagnostics, CancellationToken cancellationToken) 
    { 
     var root = await document.GetSyntaxRootAsync(cancellationToken); 
     var token = root.FindToken(span.Start); 
     var allTrivia = token.GetAllTrivia(); 
     foreach(var singleTrivia in allTrivia) 
     { 
      if (singleTrivia.IsKind(SyntaxKind.SingleLineCommentTrivia)) 
      { 
       var commentContent = singleTrivia.ToString().Replace("//", string.Empty); 
       var newComment = SyntaxFactory.Comment(string.Format("/*{0}*/", commentContent)); 
       var newRoot = root.ReplaceTrivia(singleTrivia, newComment); 
       return new[] { CodeAction.Create("Convert to multiline", document.WithSyntaxRoot(newRoot)) }; 
      } 
     }   
     return null; 
    } 
+0

을 감사! 하지만 질문이 있습니다. 공용 클래스 DiagnosticAnalyzer : {} 또는이 하나 개 공용 클래스 IDiagnosticAnalyzer 같은 다른 클래스 ISyntaxNodeAnalyzer : ISyntaxTreeAnalyzer 느린 응답에 대한 {} – Maloz

+0

사과를 나는에 코드를 삽입해야합니다. 이 예제에서는 ISyntaxTreeAnalyzer를 사용합니다. 클래스의 나머지 코드를 위 코드에 추가했습니다. AnaylzeSyntaxTree 메서드는 ISyntaxTreeAnalyzer 인터페이스에 의해 구현되었습니다. – rh072005

+0

그래서, 이미 시도한 바입니다.하지만 DiagnosticAnalyzer에서 2 클래스를 사용하는 것이 문제 일 수 있습니까? 왜냐하면 나는 어떤 진단도 없기 때문에 ... 당신의 코드를 가져가더라도, 같은 것을 붙여 넣습니다. 오류는 없지만 진단은 없습니다. 유일한 차이점은 내 DiagnosticAnalyzer에 다른 클래스가 있다는 점입니다.일부 노드를 분석하는 데 사용되는 cs입니다. public class DiagnosticAnalyzer : ISyntaxNodeAnalyzer {} – Maloz