public ImmutableArray <string> Collect() { var typeDecls = Root .DescendantNodesAndSelf() .OfType <TypeDeclarationSyntax>() .ToImmutableArray(); var items = new List <(TypeDeclarationSyntax typeDecl, ImmutableArray <string> deriveNames)>(); foreach (var typeDecl in typeDecls) { var typeSym = (ITypeSymbol)Model.GetDeclaredSymbol(typeDecl); if (!TryAnalyzeTypeDeclWithDeriveAttribute(typeDecl, out var deriveNames)) { continue; } items.Add((typeDecl, deriveNames)); } if (items.Count == 0) { return(ImmutableArray <string> .Empty); } // Render: var sf = new MySyntaxFactory(LanguageVersion.CSharp5); var partialTypeDecls = new List <MemberDeclarationSyntax>(); foreach (var(typeDecl, deriveNames) in items) { Logger.WriteLine($"#![derive({string.Join(", ", deriveNames)})]"); Logger.WriteLine($"class {typeDecl.Identifier.ToString()};"); var varMembers = new VariableMemberCollector(Model).Collect(typeDecl); var ctor = sf.CompleteConstructor(Model, typeDecl, varMembers); var partialTypeDecl = typeDecl .WithLeadingTrivia(SyntaxFactory.TriviaList()) .WithTrailingTrivia(SyntaxFactory.TriviaList()) .WithAttributeLists(SyntaxFactory.List <AttributeListSyntax>()) .WithModifiers(SyntaxFactory.TokenList( SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.PartialKeyword) )) .WithMembers(new SyntaxList <MemberDeclarationSyntax>(new[] { ctor, })); partialTypeDecls.Add(partialTypeDecl); } var ns = SyntaxFactory.NamespaceDeclaration(SyntaxFactory.ParseName("Examples.Ast")) .WithUsings(SyntaxFactory.List <UsingDirectiveSyntax>(new[] { SyntaxFactory.UsingDirective(SyntaxFactory.ParseName("System")) })) .WithMembers(SyntaxFactory.List(partialTypeDecls)); var generatedModule = SyntaxFactory .CompilationUnit() .WithMembers(SyntaxFactory.List <MemberDeclarationSyntax>(new[] { ns })) .WithAdditionalAnnotations( Formatter.Annotation, Simplifier.Annotation ); var formatted = Formatter.Format(generatedModule, Workspace); var generatedDoc = Project.AddDocument("Sharperform.g.cs", formatted); var simplified = Simplifier.ReduceAsync(generatedDoc).Result; var generatedCode = simplified.GetTextAsync().Result.ToString(); Logger.WriteLine(generatedCode); // Logger.WriteLine(formatted.ToString()); return(ImmutableArray.Create(generatedCode)); }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { var diagnostic = context.Diagnostics.FirstOrDefault(); if (diagnostic == null) { return; } var document = context.Document; var ct = context.CancellationToken; var root = await document.GetSyntaxRootAsync(ct).ConfigureAwait(false); if (root == null) { return; } var typeDecl = root .FindToken(diagnostic.Location.SourceSpan.Start) .Parent .AncestorsAndSelf() .OfType <TypeDeclarationSyntax>() .FirstOrDefault(); if (typeDecl == null) { return; } var semanticModel = await document.GetSemanticModelAsync(ct); if (semanticModel == null) { return; } // Generate fixing method. var varMembers = new VariableMemberCollector(semanticModel).Collect(typeDecl); if (varMembers.All(m => m.HasInitializer)) { return; } var languageVersion = (typeDecl.SyntaxTree.Options as CSharpParseOptions)?.LanguageVersion ?? LanguageVersion.CSharp6; var factory = new MySyntaxFactory(languageVersion); async Task <Document> FixAsync() { var constructor = factory.CompleteConstructor(semanticModel, typeDecl, varMembers); return (document.WithSyntaxRoot( root.ReplaceNode( typeDecl, typeDecl.AddMembers(constructor) ))); } context.RegisterCodeFix( CodeAction.Create( diagnostic.Descriptor.Title.ToString(), _ => FixAsync(), equivalenceKey: diagnostic.Id ), diagnostic ); }