public static async Task <CompilationUnitSyntax> Generate(Document sourceDocument, CancellationToken cancellationToken)
        {
            Compilation compilation = await sourceDocument.Project.GetCompilationAsync(cancellationToken);

            CompilationUnitSyntax compilationUnit = await sourceDocument.GetSyntaxRootAsync() as CompilationUnitSyntax;

            ClientProxyGenerator generator = new ClientProxyGenerator();

            CompilationUnitSyntax targetCompilationUnit = SyntaxFactory.CompilationUnit(compilationUnit.Externs, compilationUnit.Usings, SyntaxFactory.List <AttributeListSyntax>(), SyntaxFactory.List <MemberDeclarationSyntax>());

            targetCompilationUnit = targetCompilationUnit.AddMembers((await GenerateProxyInterfaces(sourceDocument, generator, cancellationToken)).ToArray());
            sourceDocument        = AddCompilationUnitToProject(sourceDocument, targetCompilationUnit);
            targetCompilationUnit = targetCompilationUnit.AddMembers((await GenerateProxyClasses(sourceDocument, generator, cancellationToken)).ToArray());
            return(targetCompilationUnit);
        }
Beispiel #2
0
        protected override Task <CompilationUnitSyntax> GenerateCompilationUnit(Document sourceDocument)
        {
            EnvDTE.ProjectItem projItem = GetService(typeof(EnvDTE.ProjectItem)) as EnvDTE.ProjectItem;

            // Remove any previously generated documents first, since we may otherwise get those as well during
            // parsing, leading to duplicate method generations.
            foreach (EnvDTE.ProjectItem item in projItem.ProjectItems)
            {
                if (item.FileCount > 0 && item.FileNames[0].EndsWith(GetDefaultExtension()))
                {
                    var docToRemove = sourceDocument.Project.Documents.FirstOrDefault(doc => doc.FilePath == item.FileNames[0]);
                    if (docToRemove != null)
                    {
                        sourceDocument = sourceDocument.Project.RemoveDocument(docToRemove.Id).GetDocument(sourceDocument.Id);
                    }
                }
            }

            return(ClientProxyGenerator.Generate(sourceDocument, CancellationToken.None));
        }
        private static async Task <ImmutableList <MemberDeclarationSyntax> > GenerateProxyInterfaces(Document sourceDocument, ClientProxyGenerator generator, CancellationToken cancellationToken)
        {
            CompilationUnitSyntax compilationUnit = await sourceDocument.GetCompilationUnitRootAsync(cancellationToken);

            IEnumerable <InterfaceDeclarationSyntax> sourceInterfaces = compilationUnit.DescendantNodes().OfType <InterfaceDeclarationSyntax>();

            ImmutableList <MemberDeclarationSyntax> members = ImmutableList <MemberDeclarationSyntax> .Empty;
            SemanticModel semanticModel = await sourceDocument.GetSemanticModelAsync(cancellationToken);

            SyntaxGenerator syntaxGenerator = SyntaxGenerator.GetGenerator(sourceDocument);

            foreach (var sourceInterface in sourceInterfaces)
            {
                ITypeSymbol sourceInterfaceSymbol = semanticModel.GetDeclaredSymbol(sourceInterface);

                var options = GetGenerationOptionsFromAttribute <ProxyGenerationOptions>(sourceInterfaceSymbol, ProxyGenerationOptions.GenerateProxyAttributeName);
                if (options != null)
                {
                    INamedTypeSymbol serviceInterfaceSymbol;
                    serviceInterfaceSymbol = ResolveServiceInterface(semanticModel.Compilation, sourceInterfaceSymbol, options);

                    if (!sourceInterface.IsPartial())
                    {
                        throw new CodeGeneratorException(sourceInterface, $"The interface {sourceInterfaceSymbol.Name} must be partial to participate in generation.");
                    }

                    bool implementsSourceInterface = sourceInterfaceSymbol.AllInterfaces.Any(i => i.Equals(serviceInterfaceSymbol));

                    InterfaceDeclarationSyntax targetInterface = generator.GenerateProxyInterface(semanticModel, syntaxGenerator, serviceInterfaceSymbol, sourceInterfaceSymbol.Name, sourceInterfaceSymbol.DeclaredAccessibility, implementsSourceInterface, options.SuppressAsyncMethods, options.SuppressWarningComments);

                    targetInterface = syntaxGenerator.AddModifiers(targetInterface, DeclarationModifiers.Partial);

                    members = members.Add(CreateEnclosingMembers(semanticModel, syntaxGenerator, sourceInterface, targetInterface));
                }
            }

            return(members);
        }
        private static async Task <IReadOnlyList <MemberDeclarationSyntax> > GenerateProxyClasses(Document sourceDocument, ClientProxyGenerator generator, CancellationToken cancellationToken)
        {
            CompilationUnitSyntax compilationUnit = await sourceDocument.GetSyntaxRootAsync() as CompilationUnitSyntax;

            SemanticModel semanticModel = await sourceDocument.GetSemanticModelAsync(cancellationToken);

            SyntaxGenerator syntaxGenerator = SyntaxGenerator.GetGenerator(sourceDocument);

            var sourceClasses = compilationUnit.DescendantNodes().OfType <ClassDeclarationSyntax>();

            ImmutableList <MemberDeclarationSyntax> members = ImmutableList <MemberDeclarationSyntax> .Empty;

            foreach (var sourceClass in sourceClasses)
            {
                var sourceClassSymbol = semanticModel.GetDeclaredSymbol(sourceClass);

                ProxyGenerationOptions options = GetGenerationOptionsFromAttribute <ProxyGenerationOptions>(sourceClassSymbol, ProxyGenerationOptions.GenerateProxyAttributeName, ProxyGenerationOptions.GenerateErrorHandlingProxyAttributeName, ProxyGenerationOptions.GenerateErrorHandlingProxyWrapperAttributeName);

                if (options != null)
                {
                    INamedTypeSymbol serviceInterfaceSymbol;
                    serviceInterfaceSymbol = ResolveServiceInterface(semanticModel.Compilation, sourceClassSymbol, options);

                    if (!sourceClass.IsPartial())
                    {
                        throw new CodeGeneratorException(sourceClass, $"The class {sourceClassSymbol.Name} must be partial to participate in generation.");
                    }

                    ClassDeclarationSyntax      targetClass;
                    IEnumerable <IMethodSymbol> dummy;
                    if (options.AttributeName == ProxyGenerationOptions.GenerateProxyAttributeName)
                    {
                        targetClass = generator.GenerateProxyClass(semanticModel, syntaxGenerator, serviceInterfaceSymbol, sourceClassSymbol.Name, sourceClassSymbol.DeclaredAccessibility, options.SuppressWarningComments, options.ConstructorVisibility, out dummy);
                    }
                    else
                    {
                        targetClass = await generator.GenerateClientClass(semanticModel, syntaxGenerator, serviceInterfaceSymbol, sourceClassSymbol.Name, sourceClassSymbol.DeclaredAccessibility, true, options.SuppressWarningComments, options.ConstructorVisibility, options.AttributeName == ProxyGenerationOptions.GenerateErrorHandlingProxyAttributeName);
                    }

                    targetClass = syntaxGenerator.AddModifiers(targetClass, DeclarationModifiers.Partial);

                    members = members.Add(CreateEnclosingMembers(semanticModel, syntaxGenerator, sourceClass, targetClass));
                }
            }

            return(members);
        }