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); }
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); }