Example #1
0
        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));
        }
Example #2
0
        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
                );
        }