メソッドにxmlに<createddate>
タグが含まれていないかどうかを検出するアナライザを作成しました。それは正常に動作し、タグを挿入しますが、ルールが修正されていてもビルドエラーが返されます。おそらく意味モデルを使う必要があると思いますか?Roslynはコードフィックスの後にソリューションを更新できません
これは私が持っているものです:タグがxmlの中に存在する場合、ビルドが通るようにする方法として CodeFixProvider.cs
using System;
using System.Collections.Immutable;
using System.Composition;
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.Formatting;
using Microsoft.CodeAnalysis.Simplification;
using Microsoft.CodeAnalysis.Rename;
namespace NewAnalyzer
{
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(NewAnalyzerCodeFixProvider)), Shared]
public class NewAnalyzerCodeFixProvider : CodeFixProvider
{
private const string title = "Add Createddate";
public sealed override ImmutableArray<string> FixableDiagnosticIds
{
get { return ImmutableArray.Create(NewAnalyzerAnalyzer.DiagnosticId); }
}
public sealed override FixAllProvider GetFixAllProvider()
{
// See https://github.com/dotnet/roslyn/blob/master/docs/analyzers/FixAllProvider.md for more information on Fix All Providers
return WellKnownFixAllProviders.BatchFixer;
}
public sealed override Task RegisterCodeFixesAsync(CodeFixContext context)
{
var diagnostic = context.Diagnostics.First();
var diagnosticSpan = diagnostic.Location.SourceSpan;
SyntaxNode root;
context.Document.TryGetSyntaxRoot(out root);
var syntax = root.FindNode(diagnostic.Location.SourceSpan);
var methodDeclarationSyntax = syntax.FirstAncestorOrSelf<MethodDeclarationSyntax>();
var description = "Add created datetime for API endpoint.";
var equivalenceKey = "empty string";
context.RegisterCodeFix(CodeAction.Create(description, cancellationToken => CreateChangedDocument(context, methodDeclarationSyntax, cancellationToken), equivalenceKey), diagnostic);
return Task.FromResult(0);
}
/// <summary>
/// Create a new method that will contain the changes required to insert a createddate tag into the comments.
/// </summary>
/// <param name="context">context</param>
/// <param name="methodDeclarationSyntax">method declaration syntax</param>
/// <param name="cancellationToken">cancellation token</param>
/// <returns>new method that contains createddate in the comments</returns>
private static async Task<Document> CreateChangedDocument(CodeFixContext context, MethodDeclarationSyntax methodDeclarationSyntax, CancellationToken cancellationToken)
{
var originalTree = await context.Document.GetSyntaxTreeAsync(cancellationToken);
var newTree = await context.Document.GetSyntaxTreeAsync(cancellationToken);
var root = await newTree.GetRootAsync(cancellationToken);
var documentationComment = methodDeclarationSyntax.GetLeadingTrivia().Select(i => i.GetStructure()).OfType<DocumentationCommentTriviaSyntax>().FirstOrDefault();
var summaryElement = (XmlElementSyntax)documentationComment.Content.FirstOrDefault(x => x is XmlElementSyntax); // works
if (documentationComment == null)
return context.Document;
var newLineText = SyntaxFactory.XmlTextNewLine(SyntaxFactory.TriviaList(), Environment.NewLine, Environment.NewLine, SyntaxFactory.TriviaList());
var createdDateText =
SyntaxFactory.XmlText(SyntaxFactory.TokenList(
SyntaxFactory.XmlTextLiteral(
SyntaxFactory.TriviaList(),
DateTime.UtcNow.ToString("d"),
DateTime.UtcNow.ToString("d"),
SyntaxFactory.TriviaList())
));
var textList = SyntaxFactory.List<XmlNodeSyntax>(new[] { createdDateText });
var createdDateNode = new XmlNodeSyntax[]
{
SyntaxFactory.XmlText().AddTextTokens(SyntaxFactory.XmlTextNewLine(SyntaxFactory.TriviaList(), Environment.NewLine, Environment.NewLine, SyntaxFactory.TriviaList())),
SyntaxFactory.XmlElement(SyntaxFactory.XmlElementStartTag(SyntaxFactory.XmlName("createddate")).WithLeadingTrivia(SyntaxFactory.DocumentationCommentExterior("/// ")),
textList,
SyntaxFactory.XmlElementEndTag(SyntaxFactory.XmlName("createddate"))).WithAdditionalAnnotations(Formatter.Annotation, Simplifier.Annotation)
};
var list = SyntaxFactory.List<XmlNodeSyntax>(createdDateNode);
SyntaxNode tempNode = documentationComment.InsertNodesAfter(summaryElement, list);
var newRoot = root.ReplaceNode(documentationComment, tempNode);
var semanticModel = await context.Document.GetSemanticModelAsync(cancellationToken);
var typeSymbol = semanticModel.GetDeclaredSymbol(methodDeclarationSyntax, cancellationToken);
var semModel = await context.Document.GetSemanticModelAsync();
var compilation = semModel.Compilation.ReplaceSyntaxTree(originalTree, newTree);
var oldSemModel = await context.Document.GetSemanticModelAsync();
oldSemModel = semanticModel;
return context.Document;
}
}
}
そしてDiagnosticAnalyzer.cs
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
namespace NewAnalyzer
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class NewAnalyzerAnalyzer : DiagnosticAnalyzer
{
public const string DiagnosticId = "NA001";
// You can change these strings in the Resources.resx file. If you do not want your analyzer to be localize-able, you can use regular strings for Title and MessageFormat.
// See https://github.com/dotnet/roslyn/blob/master/docs/analyzers/Localizing%20Analyzers.md for more on localization
private static readonly LocalizableString Title = "Title: createddate is missing";
private static readonly LocalizableString MessageFormat = "Format: createddate is missing";
private static readonly LocalizableString Description = "Desc: createddate is missing";
private const string Category = "Naming";
private static DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true, description: Description);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } }
public override void Initialize(AnalysisContext context)
{
// TODO: Consider registering other actions that act on syntax instead of or in addition to symbols
// See https://github.com/dotnet/roslyn/blob/master/docs/analyzers/Analyzer%20Actions%20Semantics.md for more information
//context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.NamedType);
context.RegisterSymbolAction(AnalyzeMethod, SymbolKind.Method);
}
/// <summary>
/// Analyze method to see if it's a REST endpoint method
/// </summary>
/// <param name="context">context</param>
private static void AnalyzeMethod(SymbolAnalysisContext context)
{
var methodDeclarationNode = context.Symbol.GetDocumentationCommentXml();
if (methodDeclarationNode != null)
{
if (!methodDeclarationNode.Contains("createddate"))
{
var diagnostic = Diagnostic.Create(Rule, context.Symbol.Locations[0], methodDeclarationNode);
context.ReportDiagnostic(diagnostic);
}
}
}
}
}
任意のアイデア?実際にはソリューションを更新していないようですね。
これは機能しません。それをメソッド宣言として持つと、ビルドエラーではなくIDEエラーとして返されます。これはsemanticModelAnalysisコンテキストですか? –
申し訳ありませんが、何が動作しないのか分かりません。あなたはもう少し問題を説明できますか? – Tamas
私はあなたにコードを送るべきです、methoddeclarationsyntaxを使用してビルドエラーをスローしません。コードを共有できる方法はありますか? –