CSharpCodeGenerationService.cs 41.3 KB
Newer Older
J
Jonathon Marolf 已提交
1 2 3
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
P
Pilchie 已提交
4 5 6 7 8 9

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
10
using System.Threading.Tasks;
P
Pilchie 已提交
11 12 13 14
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeGeneration;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
15
using Microsoft.CodeAnalysis.Host;
P
Pilchie 已提交
16
using Microsoft.CodeAnalysis.LanguageServices;
17
using Microsoft.CodeAnalysis.PooledObjects;
P
Pilchie 已提交
18 19 20 21 22 23 24
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.CodeGeneration
{
    internal partial class CSharpCodeGenerationService : AbstractCodeGenerationService
    {
25
        public CSharpCodeGenerationService(HostLanguageServices languageServices)
D
dotnet-bot 已提交
26
            : base(languageServices.GetService<ISymbolDeclarationService>(),
27
                   languageServices.WorkspaceServices.Workspace)
P
Pilchie 已提交
28 29 30
        {
        }

31 32 33 34 35
        public override CodeGenerationDestination GetDestination(SyntaxNode node)
        {
            return CSharpCodeGenerationHelpers.GetDestination(node);
        }

36
        protected override IComparer<SyntaxNode> GetMemberComparer()
C
CyrusNajmabadi 已提交
37
            => CSharpDeclarationComparer.WithoutNamesInstance;
38

P
Pilchie 已提交
39 40
        protected override IList<bool> GetAvailableInsertionIndices(SyntaxNode destination, CancellationToken cancellationToken)
        {
C
CyrusNajmabadi 已提交
41
            if (destination is TypeDeclarationSyntax typeDeclaration)
P
Pilchie 已提交
42
            {
C
CyrusNajmabadi 已提交
43
                return GetInsertionIndices(typeDeclaration, cancellationToken);
P
Pilchie 已提交
44 45 46 47 48 49 50 51 52 53 54 55 56
            }

            // TODO(cyrusn): This will make is so that we can't generate into an enum, namespace, or
            // compilation unit, if it overlaps a hidden region.  We can consider relaxing that
            // restriction in the future.
            return null;
        }

        private IList<bool> GetInsertionIndices(TypeDeclarationSyntax destination, CancellationToken cancellationToken)
        {
            return destination.GetInsertionIndices(cancellationToken);
        }

57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
        public override async Task<Document> AddEventAsync(
            Solution solution, INamedTypeSymbol destination, IEventSymbol @event,
            CodeGenerationOptions options, CancellationToken cancellationToken)
        {
            var newDocument = await base.AddEventAsync(
                solution, destination, @event, options, cancellationToken).ConfigureAwait(false);

            var namedType = @event.Type as INamedTypeSymbol;
            if (namedType?.AssociatedSymbol != null)
            {
                // This is a VB event that declares its own type.  i.e. "Public Event E(x As Object)"
                // We also have to generate "public void delegate EEventHandler(object x)"
                var compilation = await newDocument.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
                var newDestinationSymbol = destination.GetSymbolKey().Resolve(compilation).Symbol;

                if (newDestinationSymbol?.ContainingType != null)
                {
                    return await this.AddNamedTypeAsync(
D
dotnet-bot 已提交
75
                        newDocument.Project.Solution, newDestinationSymbol.ContainingType,
76 77 78 79 80 81 82 83 84 85 86 87 88
                        namedType, options, cancellationToken).ConfigureAwait(false);
                }
                else if (newDestinationSymbol?.ContainingNamespace != null)
                {
                    return await this.AddNamedTypeAsync(
                        newDocument.Project.Solution, newDestinationSymbol.ContainingNamespace,
                        namedType, options, cancellationToken).ConfigureAwait(false);
                }
            }

            return newDocument;
        }

P
Pilchie 已提交
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
        protected override TDeclarationNode AddEvent<TDeclarationNode>(TDeclarationNode destination, IEventSymbol @event, CodeGenerationOptions options, IList<bool> availableIndices)
        {
            CheckDeclarationNode<TypeDeclarationSyntax>(destination);

            return Cast<TDeclarationNode>(EventGenerator.AddEventTo(Cast<TypeDeclarationSyntax>(destination), @event, options, availableIndices));
        }

        protected override TDeclarationNode AddField<TDeclarationNode>(TDeclarationNode destination, IFieldSymbol field, CodeGenerationOptions options, IList<bool> availableIndices)
        {
            CheckDeclarationNode<EnumDeclarationSyntax, TypeDeclarationSyntax, CompilationUnitSyntax>(destination);

            if (destination is EnumDeclarationSyntax)
            {
                return Cast<TDeclarationNode>(EnumMemberGenerator.AddEnumMemberTo(Cast<EnumDeclarationSyntax>(destination), field, options));
            }
            else if (destination is TypeDeclarationSyntax)
            {
                return Cast<TDeclarationNode>(FieldGenerator.AddFieldTo(Cast<TypeDeclarationSyntax>(destination), field, options, availableIndices));
            }
            else
            {
                return Cast<TDeclarationNode>(FieldGenerator.AddFieldTo(Cast<CompilationUnitSyntax>(destination), field, options, availableIndices));
            }
        }

        protected override TDeclarationNode AddMethod<TDeclarationNode>(TDeclarationNode destination, IMethodSymbol method, CodeGenerationOptions options, IList<bool> availableIndices)
        {
A
Allison Chou 已提交
116
            CheckDeclarationNode<TypeDeclarationSyntax, CompilationUnitSyntax, NamespaceDeclarationSyntax>(destination);
P
Pilchie 已提交
117

A
Allison Chou 已提交
118
            options = options.With(options: options.Options ?? Workspace.Options);
119

P
Pilchie 已提交
120 121
            // Synthesized methods for properties/events are not things we actually generate 
            // declarations for.
122
            if (method.AssociatedSymbol is IEventSymbol)
P
Pilchie 已提交
123 124 125
            {
                return destination;
            }
C
CyrusNajmabadi 已提交
126
            // we will ignore the method if the associated property can be generated.
P
Pilchie 已提交
127

C
CyrusNajmabadi 已提交
128
            if (method.AssociatedSymbol is IPropertySymbol property)
P
Pilchie 已提交
129 130 131 132 133 134 135
            {
                if (PropertyGenerator.CanBeGenerated(property))
                {
                    return destination;
                }
            }

C
CyrusNajmabadi 已提交
136
            if (destination is TypeDeclarationSyntax typeDeclaration)
P
Pilchie 已提交
137 138 139
            {
                if (method.IsConstructor())
                {
140 141
                    return Cast<TDeclarationNode>(ConstructorGenerator.AddConstructorTo(
                        typeDeclaration, method, Workspace, options, availableIndices));
P
Pilchie 已提交
142 143 144 145 146 147 148 149 150
                }

                if (method.IsDestructor())
                {
                    return Cast<TDeclarationNode>(DestructorGenerator.AddDestructorTo(typeDeclaration, method, options, availableIndices));
                }

                if (method.MethodKind == MethodKind.Conversion)
                {
151 152
                    return Cast<TDeclarationNode>(ConversionGenerator.AddConversionTo(
                        typeDeclaration, method, Workspace, options, availableIndices));
P
Pilchie 已提交
153 154 155 156
                }

                if (method.MethodKind == MethodKind.UserDefinedOperator)
                {
157 158
                    return Cast<TDeclarationNode>(OperatorGenerator.AddOperatorTo(
                        typeDeclaration, method, Workspace, options, availableIndices));
P
Pilchie 已提交
159 160
                }

161
                return Cast<TDeclarationNode>(MethodGenerator.AddMethodTo(
162
                    typeDeclaration, method, options, availableIndices));
P
Pilchie 已提交
163 164 165 166 167 168 169 170
            }

            if (method.IsConstructor() ||
                method.IsDestructor())
            {
                return destination;
            }

C
CyrusNajmabadi 已提交
171
            if (destination is CompilationUnitSyntax compilationUnit)
P
Pilchie 已提交
172
            {
173
                return Cast<TDeclarationNode>(
174
                    MethodGenerator.AddMethodTo(compilationUnit, method, options, availableIndices));
P
Pilchie 已提交
175 176 177
            }

            var ns = Cast<NamespaceDeclarationSyntax>(destination);
178
            return Cast<TDeclarationNode>(
179
                MethodGenerator.AddMethodTo(ns, method, options, availableIndices));
P
Pilchie 已提交
180 181 182 183 184 185 186 187 188 189 190 191 192 193
        }

        protected override TDeclarationNode AddProperty<TDeclarationNode>(TDeclarationNode destination, IPropertySymbol property, CodeGenerationOptions options, IList<bool> availableIndices)
        {
            CheckDeclarationNode<TypeDeclarationSyntax, CompilationUnitSyntax>(destination);

            // Can't generate a property with parameters.  So generate the setter/getter individually.
            if (!PropertyGenerator.CanBeGenerated(property))
            {
                var members = new List<ISymbol>();
                if (property.GetMethod != null)
                {
                    var getMethod = property.GetMethod;

C
CyrusNajmabadi 已提交
194
                    if (property is CodeGenerationSymbol codeGenSymbol)
P
Pilchie 已提交
195
                    {
C
CyrusNajmabadi 已提交
196
                        foreach (var annotation in codeGenSymbol.GetAnnotations())
P
Pilchie 已提交
197 198 199 200 201 202 203 204 205 206 207 208
                        {
                            getMethod = annotation.AddAnnotationToSymbol(getMethod);
                        }
                    }

                    members.Add(getMethod);
                }

                if (property.SetMethod != null)
                {
                    var setMethod = property.SetMethod;

C
CyrusNajmabadi 已提交
209
                    if (property is CodeGenerationSymbol codeGenSymbol)
P
Pilchie 已提交
210
                    {
C
CyrusNajmabadi 已提交
211
                        foreach (var annotation in codeGenSymbol.GetAnnotations())
P
Pilchie 已提交
212 213 214 215 216 217 218 219 220 221 222 223 224
                        {
                            setMethod = annotation.AddAnnotationToSymbol(setMethod);
                        }
                    }

                    members.Add(setMethod);
                }

                if (members.Count > 1)
                {
                    options = CreateOptionsForMultipleMembers(options);
                }

225
                return AddMembers(destination, members, availableIndices, options, CancellationToken.None);
P
Pilchie 已提交
226 227 228 229
            }

            if (destination is TypeDeclarationSyntax)
            {
230 231
                return Cast<TDeclarationNode>(PropertyGenerator.AddPropertyTo(
                    Cast<TypeDeclarationSyntax>(destination), property, Workspace, options, availableIndices));
P
Pilchie 已提交
232 233 234
            }
            else
            {
235 236
                return Cast<TDeclarationNode>(PropertyGenerator.AddPropertyTo(
                    Cast<CompilationUnitSyntax>(destination), property, Workspace, options, availableIndices));
P
Pilchie 已提交
237 238 239
            }
        }

240
        protected override TDeclarationNode AddNamedType<TDeclarationNode>(TDeclarationNode destination, INamedTypeSymbol namedType, CodeGenerationOptions options, IList<bool> availableIndices, CancellationToken cancellationToken)
P
Pilchie 已提交
241 242 243 244 245
        {
            CheckDeclarationNode<TypeDeclarationSyntax, NamespaceDeclarationSyntax, CompilationUnitSyntax>(destination);

            if (destination is TypeDeclarationSyntax)
            {
246
                return Cast<TDeclarationNode>(NamedTypeGenerator.AddNamedTypeTo(this, Cast<TypeDeclarationSyntax>(destination), namedType, options, availableIndices, cancellationToken));
P
Pilchie 已提交
247 248 249
            }
            else if (destination is NamespaceDeclarationSyntax)
            {
250
                return Cast<TDeclarationNode>(NamedTypeGenerator.AddNamedTypeTo(this, Cast<NamespaceDeclarationSyntax>(destination), namedType, options, availableIndices, cancellationToken));
P
Pilchie 已提交
251 252 253
            }
            else
            {
254
                return Cast<TDeclarationNode>(NamedTypeGenerator.AddNamedTypeTo(this, Cast<CompilationUnitSyntax>(destination), namedType, options, availableIndices, cancellationToken));
P
Pilchie 已提交
255 256 257
            }
        }

258
        protected override TDeclarationNode AddNamespace<TDeclarationNode>(TDeclarationNode destination, INamespaceSymbol @namespace, CodeGenerationOptions options, IList<bool> availableIndices, CancellationToken cancellationToken)
P
Pilchie 已提交
259 260 261 262 263
        {
            CheckDeclarationNode<CompilationUnitSyntax, NamespaceDeclarationSyntax>(destination);

            if (destination is CompilationUnitSyntax)
            {
264
                return Cast<TDeclarationNode>(NamespaceGenerator.AddNamespaceTo(this, Cast<CompilationUnitSyntax>(destination), @namespace, options, availableIndices, cancellationToken));
P
Pilchie 已提交
265 266 267
            }
            else
            {
268
                return Cast<TDeclarationNode>(NamespaceGenerator.AddNamespaceTo(this, Cast<NamespaceDeclarationSyntax>(destination), @namespace, options, availableIndices, cancellationToken));
P
Pilchie 已提交
269 270 271 272
            }
        }

        public override TDeclarationNode AddParameters<TDeclarationNode>(
273
            TDeclarationNode destination,
P
Pilchie 已提交
274 275 276 277
            IEnumerable<IParameterSymbol> parameters,
            CodeGenerationOptions options,
            CancellationToken cancellationToken)
        {
278
            var currentParameterList = destination.GetParameterList();
P
Pilchie 已提交
279 280 281

            if (currentParameterList == null)
            {
282
                return destination;
P
Pilchie 已提交
283 284
            }

C
Cyrus Najmabadi 已提交
285 286 287
            var currentParamsCount = currentParameterList.Parameters.Count;
            var seenOptional = currentParamsCount > 0 && currentParameterList.Parameters[currentParamsCount - 1].Default != null;
            var isFirstParam = currentParamsCount == 0;
L
Lavanya 已提交
288
            var newParams = ArrayBuilder<SyntaxNode>.GetInstance();
P
Pilchie 已提交
289 290 291 292

            foreach (var parameter in parameters)
            {
                var parameterSyntax = ParameterGenerator.GetParameter(parameter, options, isExplicit: false, isFirstParam: isFirstParam, seenOptional: seenOptional);
L
Lavanya 已提交
293

P
Pilchie 已提交
294 295
                isFirstParam = false;
                seenOptional = seenOptional || parameterSyntax.Default != null;
L
Lavanya 已提交
296
                newParams.Add(parameterSyntax);
P
Pilchie 已提交
297 298
            }

299
            var finalMember = CSharpSyntaxGenerator.Instance.AddParameters(destination, newParams.ToImmutableAndFree());
P
Pilchie 已提交
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317

            return Cast<TDeclarationNode>(finalMember);
        }

        public override TDeclarationNode AddAttributes<TDeclarationNode>(
            TDeclarationNode destination,
            IEnumerable<AttributeData> attributes,
            SyntaxToken? target,
            CodeGenerationOptions options,
            CancellationToken cancellationToken)
        {
            if (target.HasValue && !target.Value.IsValidAttributeTarget())
            {
                throw new ArgumentException("target");
            }

            var attributeSyntaxList = AttributeGenerator.GenerateAttributeLists(attributes.ToImmutableArray(), options, target).ToArray();

C
Cyrus Najmabadi 已提交
318
            return destination switch
C
CyrusNajmabadi 已提交
319
            {
C
Cyrus Najmabadi 已提交
320 321 322 323 324 325 326
                MemberDeclarationSyntax member => Cast<TDeclarationNode>(member.AddAttributeLists(attributeSyntaxList)),
                AccessorDeclarationSyntax accessor => Cast<TDeclarationNode>(accessor.AddAttributeLists(attributeSyntaxList)),
                CompilationUnitSyntax compilationUnit => Cast<TDeclarationNode>(compilationUnit.AddAttributeLists(attributeSyntaxList)),
                ParameterSyntax parameter => Cast<TDeclarationNode>(parameter.AddAttributeLists(attributeSyntaxList)),
                TypeParameterSyntax typeParameter => Cast<TDeclarationNode>(typeParameter.AddAttributeLists(attributeSyntaxList)),
                _ => destination,
            };
P
Pilchie 已提交
327 328
        }

329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
        protected override TDeclarationNode AddMembers<TDeclarationNode>(TDeclarationNode destination, IEnumerable<SyntaxNode> members)
        {
            CheckDeclarationNode<EnumDeclarationSyntax, TypeDeclarationSyntax, NamespaceDeclarationSyntax, CompilationUnitSyntax>(destination);

            if (destination is EnumDeclarationSyntax)
            {
                return Cast<TDeclarationNode>(Cast<EnumDeclarationSyntax>(destination)
                    .AddMembers(members.Cast<EnumMemberDeclarationSyntax>().ToArray()));
            }
            else if (destination is TypeDeclarationSyntax)
            {
                return Cast<TDeclarationNode>(Cast<TypeDeclarationSyntax>(destination)
                    .AddMembers(members.Cast<MemberDeclarationSyntax>().ToArray()));
            }
            else if (destination is NamespaceDeclarationSyntax)
            {
                return Cast<TDeclarationNode>(Cast<NamespaceDeclarationSyntax>(destination)
                    .AddMembers(members.Cast<MemberDeclarationSyntax>().ToArray()));
            }
            else
            {
                return Cast<TDeclarationNode>(Cast<CompilationUnitSyntax>(destination)
                    .AddMembers(members.Cast<MemberDeclarationSyntax>().ToArray()));
            }
        }

P
Pilchie 已提交
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
        public override TDeclarationNode RemoveAttribute<TDeclarationNode>(
            TDeclarationNode destination,
            AttributeData attributeToRemove,
            CodeGenerationOptions options,
            CancellationToken cancellationToken)
        {
            if (attributeToRemove.ApplicationSyntaxReference == null)
            {
                throw new ArgumentException("attributeToRemove");
            }

            var attributeSyntaxToRemove = attributeToRemove.ApplicationSyntaxReference.GetSyntax(cancellationToken);
            return RemoveAttribute(destination, attributeSyntaxToRemove, options, cancellationToken);
        }

        public override TDeclarationNode RemoveAttribute<TDeclarationNode>(
            TDeclarationNode destination,
            SyntaxNode attributeToRemove,
            CodeGenerationOptions options,
            CancellationToken cancellationToken)
        {
            if (attributeToRemove == null)
            {
                throw new ArgumentException("attributeToRemove");
            }

            // Removed node could be AttributeSyntax or AttributeListSyntax.
            int positionOfRemovedNode;
            SyntaxTriviaList triviaOfRemovedNode;

C
CyrusNajmabadi 已提交
385
            switch (destination)
P
Pilchie 已提交
386
            {
C
CyrusNajmabadi 已提交
387 388 389 390 391 392 393
                case MemberDeclarationSyntax member:
                    {
                        // Handle all members including types.
                        var newAttributeLists = RemoveAttributeFromAttributeLists(member.GetAttributes(), attributeToRemove, options, out positionOfRemovedNode, out triviaOfRemovedNode);
                        var newMember = member.WithAttributeLists(newAttributeLists);
                        return Cast<TDeclarationNode>(AppendTriviaAtPosition(newMember, positionOfRemovedNode - destination.FullSpan.Start, triviaOfRemovedNode));
                    }
P
Pilchie 已提交
394

C
CyrusNajmabadi 已提交
395 396 397 398 399 400 401
                case AccessorDeclarationSyntax accessor:
                    {
                        // Handle accessors
                        var newAttributeLists = RemoveAttributeFromAttributeLists(accessor.AttributeLists, attributeToRemove, options, out positionOfRemovedNode, out triviaOfRemovedNode);
                        var newAccessor = accessor.WithAttributeLists(newAttributeLists);
                        return Cast<TDeclarationNode>(AppendTriviaAtPosition(newAccessor, positionOfRemovedNode - destination.FullSpan.Start, triviaOfRemovedNode));
                    }
P
Pilchie 已提交
402

C
CyrusNajmabadi 已提交
403 404 405 406 407 408 409
                case CompilationUnitSyntax compilationUnit:
                    {
                        // Handle global attributes
                        var newAttributeLists = RemoveAttributeFromAttributeLists(compilationUnit.AttributeLists, attributeToRemove, options, out positionOfRemovedNode, out triviaOfRemovedNode);
                        var newCompilationUnit = compilationUnit.WithAttributeLists(newAttributeLists);
                        return Cast<TDeclarationNode>(AppendTriviaAtPosition(newCompilationUnit, positionOfRemovedNode - destination.FullSpan.Start, triviaOfRemovedNode));
                    }
P
Pilchie 已提交
410

C
CyrusNajmabadi 已提交
411 412 413 414 415 416 417
                case ParameterSyntax parameter:
                    {
                        // Handle parameters
                        var newAttributeLists = RemoveAttributeFromAttributeLists(parameter.AttributeLists, attributeToRemove, options, out positionOfRemovedNode, out triviaOfRemovedNode);
                        var newParameter = parameter.WithAttributeLists(newAttributeLists);
                        return Cast<TDeclarationNode>(AppendTriviaAtPosition(newParameter, positionOfRemovedNode - destination.FullSpan.Start, triviaOfRemovedNode));
                    }
P
Pilchie 已提交
418

C
CyrusNajmabadi 已提交
419 420 421 422 423 424
                case TypeParameterSyntax typeParameter:
                    {
                        var newAttributeLists = RemoveAttributeFromAttributeLists(typeParameter.AttributeLists, attributeToRemove, options, out positionOfRemovedNode, out triviaOfRemovedNode);
                        var newTypeParameter = typeParameter.WithAttributeLists(newAttributeLists);
                        return Cast<TDeclarationNode>(AppendTriviaAtPosition(newTypeParameter, positionOfRemovedNode - destination.FullSpan.Start, triviaOfRemovedNode));
                    }
P
Pilchie 已提交
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
            }

            return destination;
        }

        private static SyntaxList<AttributeListSyntax> RemoveAttributeFromAttributeLists(
            SyntaxList<AttributeListSyntax> attributeLists,
            SyntaxNode attributeToRemove,
            CodeGenerationOptions options,
            out int positionOfRemovedNode,
            out SyntaxTriviaList triviaOfRemovedNode)
        {
            foreach (var attributeList in attributeLists)
            {
                var attributes = attributeList.Attributes;
                if (attributes.Contains(attributeToRemove))
                {
                    IEnumerable<SyntaxTrivia> trivia;
                    IEnumerable<AttributeListSyntax> newAttributeLists;
                    if (attributes.Count == 1)
                    {
                        // Remove the entire attribute list.
                        ComputePositionAndTriviaForRemoveAttributeList(attributeList, (SyntaxTrivia t) => t.IsKind(SyntaxKind.EndOfLineTrivia), out positionOfRemovedNode, out trivia);
                        newAttributeLists = attributeLists.Where(aList => aList != attributeList);
                    }
                    else
                    {
                        // Remove just the given attribute from the attribute list.
                        ComputePositionAndTriviaForRemoveAttributeFromAttributeList(attributeToRemove, (SyntaxToken t) => t.IsKind(SyntaxKind.CommaToken), out positionOfRemovedNode, out trivia);
                        var newAttributes = SyntaxFactory.SeparatedList(attributes.Where(a => a != attributeToRemove));
                        var newAttributeList = attributeList.WithAttributes(newAttributes);
                        newAttributeLists = attributeLists.Select(attrList => attrList == attributeList ? newAttributeList : attrList);
                    }

                    triviaOfRemovedNode = trivia.ToSyntaxTriviaList();
                    return newAttributeLists.ToSyntaxList();
                }
            }

            throw new ArgumentException("attributeToRemove");
        }

        public override TDeclarationNode AddStatements<TDeclarationNode>(
            TDeclarationNode destinationMember,
            IEnumerable<SyntaxNode> statements,
            CodeGenerationOptions options,
            CancellationToken cancellationToken)
        {
A
Allison Chou 已提交
473 474 475 476 477
            if (destinationMember is MemberDeclarationSyntax memberDeclaration)
            {
                return AddStatementsToMemberDeclaration<TDeclarationNode>(destinationMember, statements, memberDeclaration);
            }
            else if (destinationMember is LocalFunctionStatementSyntax localFunctionDeclaration)
A
Allison Chou 已提交
478
            {
A
Allison Chou 已提交
479 480 481 482 483
                return (localFunctionDeclaration.Body == null) ? destinationMember : Cast<TDeclarationNode>(localFunctionDeclaration.AddBodyStatements(StatementGenerator.GenerateStatements(statements).ToArray()));
            }
            else if (destinationMember is AccessorDeclarationSyntax accessorDeclaration)
            {
                return (accessorDeclaration.Body == null) ? destinationMember : Cast<TDeclarationNode>(accessorDeclaration.AddBodyStatements(StatementGenerator.GenerateStatements(statements).ToArray()));
A
Allison Chou 已提交
484
            }
P
Pilchie 已提交
485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
            else
            {
                return AddStatementsWorker(destinationMember, statements, options, cancellationToken);
            }
        }

        private TDeclarationNode AddStatementsWorker<TDeclarationNode>(
            TDeclarationNode destinationMember,
            IEnumerable<SyntaxNode> statements,
            CodeGenerationOptions options,
            CancellationToken cancellationToken) where TDeclarationNode : SyntaxNode
        {
            var location = options.BestLocation;
            CheckLocation<TDeclarationNode>(destinationMember, location);

            var token = location.FindToken(cancellationToken);

            var block = token.Parent.GetAncestorsOrThis<BlockSyntax>().FirstOrDefault();
            if (block != null)
            {
                var blockStatements = block.Statements.ToSet();
                var containingStatement = token.GetAncestors<StatementSyntax>().Single(blockStatements.Contains);
                var index = block.Statements.IndexOf(containingStatement);

                var newStatements = statements.OfType<StatementSyntax>().ToArray();
                BlockSyntax newBlock;
                if (options.BeforeThisLocation != null)
                {
C
CyrusNajmabadi 已提交
513
                    var newContainingStatement = containingStatement.GetNodeWithoutLeadingBannerAndPreprocessorDirectives(out var strippedTrivia);
P
Pilchie 已提交
514 515 516

                    newStatements[0] = newStatements[0].WithLeadingTrivia(strippedTrivia);

517 518
                    newBlock = block.ReplaceNode(containingStatement, newContainingStatement);
                    newBlock = newBlock.WithStatements(newBlock.Statements.InsertRange(index, newStatements));
P
Pilchie 已提交
519 520 521 522 523 524 525 526 527
                }
                else
                {
                    newBlock = block.WithStatements(block.Statements.InsertRange(index + 1, newStatements));
                }

                return destinationMember.ReplaceNode(block, newBlock);
            }

528
            throw new ArgumentException(CSharpWorkspaceResources.No_available_location_found_to_add_statements_to);
P
Pilchie 已提交
529 530
        }

A
Allison Chou 已提交
531
        private static TDeclarationNode AddStatementsToMemberDeclaration<TDeclarationNode>(TDeclarationNode destinationMember, IEnumerable<SyntaxNode> statements, MemberDeclarationSyntax memberDeclaration) where TDeclarationNode : SyntaxNode
A
Allison Chou 已提交
532
        {
A
Allison Chou 已提交
533
            var body = memberDeclaration.GetBody();
A
Allison Chou 已提交
534 535
            if (body == null)
            {
A
Allison Chou 已提交
536
                return destinationMember;
A
Allison Chou 已提交
537
            }
A
Allison Chou 已提交
538 539 540 541

            var statementNodes = body.Statements.ToList();
            statementNodes.AddRange(StatementGenerator.GenerateStatements(statements));

A
Allison Chou 已提交
542 543 544 545
            var finalBody = body.WithStatements(SyntaxFactory.List<StatementSyntax>(statementNodes));
            var finalMember = memberDeclaration.WithBody(finalBody);

            return Cast<TDeclarationNode>(finalMember);
A
Allison Chou 已提交
546 547
        }

P
Pilchie 已提交
548 549 550 551 552 553 554 555 556
        public override SyntaxNode CreateEventDeclaration(
            IEventSymbol @event, CodeGenerationDestination destination, CodeGenerationOptions options)
        {
            return EventGenerator.GenerateEventDeclaration(@event, destination, options);
        }

        public override SyntaxNode CreateFieldDeclaration(IFieldSymbol field, CodeGenerationDestination destination, CodeGenerationOptions options)
        {
            return destination == CodeGenerationDestination.EnumType
C
Cyrus Najmabadi 已提交
557
                ? EnumMemberGenerator.GenerateEnumMemberDeclaration(field, null, options)
P
Pilchie 已提交
558 559 560 561
                : (SyntaxNode)FieldGenerator.GenerateFieldDeclaration(field, destination, options);
        }

        public override SyntaxNode CreateMethodDeclaration(
A
Allison Chou 已提交
562
            IMethodSymbol method, CodeGenerationDestination destination, CodeGenerationOptions options)
P
Pilchie 已提交
563
        {
564 565 566 567 568 569
            // Synthesized methods for properties/events are not things we actually generate 
            // declarations for.
            if (method.AssociatedSymbol is IEventSymbol)
            {
                return null;
            }
C
CyrusNajmabadi 已提交
570
            // we will ignore the method if the associated property can be generated.
571

C
CyrusNajmabadi 已提交
572
            if (method.AssociatedSymbol is IPropertySymbol property)
573 574 575 576 577 578 579
            {
                if (PropertyGenerator.CanBeGenerated(property))
                {
                    return null;
                }
            }

A
Allison Chou 已提交
580
            if (method.IsDestructor())
581
            {
A
Allison Chou 已提交
582
                return DestructorGenerator.GenerateDestructorDeclaration(method, destination, options);
583 584
            }

A
Allison Chou 已提交
585
            options = options.With(options: options.Options ?? Workspace.Options);
A
Allison Chou 已提交
586

P
Pilchie 已提交
587 588
            if (method.IsConstructor())
            {
589
                return ConstructorGenerator.GenerateConstructorDeclaration(
590
                    method, destination, Workspace, options, options.ParseOptions);
P
Pilchie 已提交
591
            }
592 593
            else if (method.IsUserDefinedOperator())
            {
594 595
                return OperatorGenerator.GenerateOperatorDeclaration(
                    method, destination, Workspace, options, options.ParseOptions);
596 597 598
            }
            else if (method.IsConversion())
            {
599 600
                return ConversionGenerator.GenerateConversionDeclaration(
                    method, destination, Workspace, options, options.ParseOptions);
601
            }
A
Allison Chou 已提交
602
            else if (method.IsLocalFunction())
A
Allison Chou 已提交
603
            {
604 605
                return MethodGenerator.GenerateLocalFunctionDeclaration(
                    method, destination, options, options.ParseOptions);
A
Allison Chou 已提交
606
            }
P
Pilchie 已提交
607 608
            else
            {
A
Allison Chou 已提交
609
                return MethodGenerator.GenerateMethodDeclaration(
610
                    method, destination, options, options.ParseOptions);
P
Pilchie 已提交
611 612 613 614 615 616
            }
        }

        public override SyntaxNode CreatePropertyDeclaration(
            IPropertySymbol property, CodeGenerationDestination destination, CodeGenerationOptions options)
        {
617 618
            return PropertyGenerator.GeneratePropertyOrIndexer(
                property, destination, Workspace, options, options.ParseOptions);
P
Pilchie 已提交
619 620 621
        }

        public override SyntaxNode CreateNamedTypeDeclaration(
622
            INamedTypeSymbol namedType, CodeGenerationDestination destination, CodeGenerationOptions options, CancellationToken cancellationToken)
P
Pilchie 已提交
623
        {
624
            return NamedTypeGenerator.GenerateNamedTypeDeclaration(this, namedType, destination, options, cancellationToken);
P
Pilchie 已提交
625 626 627
        }

        public override SyntaxNode CreateNamespaceDeclaration(
628
            INamespaceSymbol @namespace, CodeGenerationDestination destination, CodeGenerationOptions options, CancellationToken cancellationToken)
P
Pilchie 已提交
629
        {
630
            return NamespaceGenerator.GenerateNamespaceDeclaration(this, @namespace, options, cancellationToken);
P
Pilchie 已提交
631 632
        }

C
Cyrus Najmabadi 已提交
633
        private static TDeclarationNode UpdateDeclarationModifiers<TDeclarationNode>(TDeclarationNode declaration, Func<SyntaxTokenList, SyntaxTokenList> computeNewModifiersList, CodeGenerationOptions options)
C
Cyrus Najmabadi 已提交
634 635 636 637 638 639 640 641
            => declaration switch
            {
                BaseTypeDeclarationSyntax typeDeclaration => Cast<TDeclarationNode>(typeDeclaration.WithModifiers(computeNewModifiersList(typeDeclaration.Modifiers))),
                BaseFieldDeclarationSyntax fieldDeclaration => Cast<TDeclarationNode>(fieldDeclaration.WithModifiers(computeNewModifiersList(fieldDeclaration.Modifiers))),
                BaseMethodDeclarationSyntax methodDeclaration => Cast<TDeclarationNode>(methodDeclaration.WithModifiers(computeNewModifiersList(methodDeclaration.Modifiers))),
                BasePropertyDeclarationSyntax propertyDeclaration => Cast<TDeclarationNode>(propertyDeclaration.WithModifiers(computeNewModifiersList(propertyDeclaration.Modifiers))),
                _ => declaration,
            };
P
Pilchie 已提交
642 643 644

        public override TDeclarationNode UpdateDeclarationModifiers<TDeclarationNode>(TDeclarationNode declaration, IEnumerable<SyntaxToken> newModifiers, CodeGenerationOptions options, CancellationToken cancellationToken)
        {
C
CyrusNajmabadi 已提交
645
            SyntaxTokenList computeNewModifiersList(SyntaxTokenList modifiersList) => newModifiers.ToSyntaxTokenList();
C
Cyrus Najmabadi 已提交
646
            return UpdateDeclarationModifiers(declaration, computeNewModifiersList, options);
P
Pilchie 已提交
647 648
        }

C
Charles Stoner 已提交
649
        public override TDeclarationNode UpdateDeclarationAccessibility<TDeclarationNode>(TDeclarationNode declaration, Accessibility newAccessibility, CodeGenerationOptions options, CancellationToken cancellationToken)
P
Pilchie 已提交
650
        {
C
CyrusNajmabadi 已提交
651
            SyntaxTokenList computeNewModifiersList(SyntaxTokenList modifiersList) => UpdateDeclarationAccessibility(modifiersList, newAccessibility, options);
C
Cyrus Najmabadi 已提交
652
            return UpdateDeclarationModifiers(declaration, computeNewModifiersList, options);
P
Pilchie 已提交
653 654
        }

C
Charles Stoner 已提交
655
        private static SyntaxTokenList UpdateDeclarationAccessibility(SyntaxTokenList modifiersList, Accessibility newAccessibility, CodeGenerationOptions options)
P
Pilchie 已提交
656
        {
657
            using var _ = ArrayBuilder<SyntaxToken>.GetInstance(out var newModifierTokens);
C
Charles Stoner 已提交
658
            CSharpCodeGenerationHelpers.AddAccessibilityModifiers(newAccessibility, newModifierTokens, options, Accessibility.NotApplicable);
P
Pilchie 已提交
659 660 661 662 663
            if (newModifierTokens.Count == 0)
            {
                return modifiersList;
            }

664 665 666 667
            // TODO: Move more APIs to use pooled ArrayBuilder
            // https://github.com/dotnet/roslyn/issues/34960
            var list = newModifierTokens.ToList();
            return GetUpdatedDeclarationAccessibilityModifiers(list, modifiersList, (SyntaxToken modifier) => SyntaxFacts.IsAccessibilityModifier(modifier.Kind()))
P
Pilchie 已提交
668 669 670 671 672
                .ToSyntaxTokenList();
        }

        public override TDeclarationNode UpdateDeclarationType<TDeclarationNode>(TDeclarationNode declaration, ITypeSymbol newType, CodeGenerationOptions options, CancellationToken cancellationToken)
        {
C
Cyrus Najmabadi 已提交
673
            if (!(declaration is CSharpSyntaxNode syntaxNode))
P
Pilchie 已提交
674 675 676 677 678
            {
                return declaration;
            }

            TypeSyntax newTypeSyntax;
679
            switch (syntaxNode.Kind())
P
Pilchie 已提交
680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
            {
                case SyntaxKind.DelegateDeclaration:
                    // Handle delegate declarations.
                    var delegateDeclarationSyntax = declaration as DelegateDeclarationSyntax;
                    newTypeSyntax = newType.GenerateTypeSyntax()
                        .WithLeadingTrivia(delegateDeclarationSyntax.ReturnType.GetLeadingTrivia())
                        .WithTrailingTrivia(delegateDeclarationSyntax.ReturnType.GetTrailingTrivia());
                    return Cast<TDeclarationNode>(delegateDeclarationSyntax.WithReturnType(newTypeSyntax));

                case SyntaxKind.MethodDeclaration:
                    // Handle method declarations.
                    var methodDeclarationSyntax = declaration as MethodDeclarationSyntax;
                    newTypeSyntax = newType.GenerateTypeSyntax()
                        .WithLeadingTrivia(methodDeclarationSyntax.ReturnType.GetLeadingTrivia())
                        .WithTrailingTrivia(methodDeclarationSyntax.ReturnType.GetTrailingTrivia());
                    return Cast<TDeclarationNode>(methodDeclarationSyntax.WithReturnType(newTypeSyntax));

                case SyntaxKind.OperatorDeclaration:
                    // Handle operator declarations.
                    var operatorDeclarationSyntax = declaration as OperatorDeclarationSyntax;
                    newTypeSyntax = newType.GenerateTypeSyntax()
                        .WithLeadingTrivia(operatorDeclarationSyntax.ReturnType.GetLeadingTrivia())
                        .WithTrailingTrivia(operatorDeclarationSyntax.ReturnType.GetTrailingTrivia());
                    return Cast<TDeclarationNode>(operatorDeclarationSyntax.WithReturnType(newTypeSyntax));

                case SyntaxKind.ConversionOperatorDeclaration:
                    // Handle conversion operator declarations.
                    var conversionOperatorDeclarationSyntax = declaration as ConversionOperatorDeclarationSyntax;
                    newTypeSyntax = newType.GenerateTypeSyntax()
                        .WithLeadingTrivia(conversionOperatorDeclarationSyntax.Type.GetLeadingTrivia())
                        .WithTrailingTrivia(conversionOperatorDeclarationSyntax.Type.GetTrailingTrivia());
                    return Cast<TDeclarationNode>(conversionOperatorDeclarationSyntax.WithType(newTypeSyntax));

                case SyntaxKind.PropertyDeclaration:
                    // Handle properties.
                    var propertyDeclaration = declaration as PropertyDeclarationSyntax;
                    newTypeSyntax = newType.GenerateTypeSyntax()
                        .WithLeadingTrivia(propertyDeclaration.Type.GetLeadingTrivia())
                        .WithTrailingTrivia(propertyDeclaration.Type.GetTrailingTrivia());
                    return Cast<TDeclarationNode>(propertyDeclaration.WithType(newTypeSyntax));

                case SyntaxKind.EventDeclaration:
                    // Handle events.
                    var eventDeclarationSyntax = declaration as EventDeclarationSyntax;
                    newTypeSyntax = newType.GenerateTypeSyntax()
                        .WithLeadingTrivia(eventDeclarationSyntax.Type.GetLeadingTrivia())
                        .WithTrailingTrivia(eventDeclarationSyntax.Type.GetTrailingTrivia());
                    return Cast<TDeclarationNode>(eventDeclarationSyntax.WithType(newTypeSyntax));

                case SyntaxKind.IndexerDeclaration:
                    // Handle indexers.
                    var indexerDeclarationSyntax = declaration as IndexerDeclarationSyntax;
                    newTypeSyntax = newType.GenerateTypeSyntax()
                        .WithLeadingTrivia(indexerDeclarationSyntax.Type.GetLeadingTrivia())
                        .WithTrailingTrivia(indexerDeclarationSyntax.Type.GetTrailingTrivia());
                    return Cast<TDeclarationNode>(indexerDeclarationSyntax.WithType(newTypeSyntax));

                case SyntaxKind.Parameter:
                    // Handle parameters.
                    var parameterSyntax = declaration as ParameterSyntax;
                    newTypeSyntax = newType.GenerateTypeSyntax()
                        .WithLeadingTrivia(parameterSyntax.Type.GetLeadingTrivia())
                        .WithTrailingTrivia(parameterSyntax.Type.GetTrailingTrivia());
                    return Cast<TDeclarationNode>(parameterSyntax.WithType(newTypeSyntax));

                case SyntaxKind.IncompleteMember:
                    // Handle incomplete members.
                    var incompleteMemberSyntax = declaration as IncompleteMemberSyntax;
                    newTypeSyntax = newType.GenerateTypeSyntax()
                        .WithLeadingTrivia(incompleteMemberSyntax.Type.GetLeadingTrivia())
                        .WithTrailingTrivia(incompleteMemberSyntax.Type.GetTrailingTrivia());
                    return Cast<TDeclarationNode>(incompleteMemberSyntax.WithType(newTypeSyntax));

                case SyntaxKind.ArrayType:
                    // Handle array type.
                    var arrayTypeSyntax = declaration as ArrayTypeSyntax;
                    newTypeSyntax = newType.GenerateTypeSyntax()
                        .WithLeadingTrivia(arrayTypeSyntax.ElementType.GetLeadingTrivia())
                        .WithTrailingTrivia(arrayTypeSyntax.ElementType.GetTrailingTrivia());
                    return Cast<TDeclarationNode>(arrayTypeSyntax.WithElementType(newTypeSyntax));

                case SyntaxKind.PointerType:
                    // Handle pointer type.
                    var pointerTypeSyntax = declaration as PointerTypeSyntax;
                    newTypeSyntax = newType.GenerateTypeSyntax()
                        .WithLeadingTrivia(pointerTypeSyntax.ElementType.GetLeadingTrivia())
                        .WithTrailingTrivia(pointerTypeSyntax.ElementType.GetTrailingTrivia());
                    return Cast<TDeclarationNode>(pointerTypeSyntax.WithElementType(newTypeSyntax));

                case SyntaxKind.VariableDeclaration:
                    // Handle variable declarations.
                    var variableDeclarationSyntax = declaration as VariableDeclarationSyntax;
                    newTypeSyntax = newType.GenerateTypeSyntax()
                        .WithLeadingTrivia(variableDeclarationSyntax.Type.GetLeadingTrivia())
                        .WithTrailingTrivia(variableDeclarationSyntax.Type.GetTrailingTrivia());
                    return Cast<TDeclarationNode>(variableDeclarationSyntax.WithType(newTypeSyntax));

                case SyntaxKind.CatchDeclaration:
                    // Handle catch declarations.
                    var catchDeclarationSyntax = declaration as CatchDeclarationSyntax;
                    newTypeSyntax = newType.GenerateTypeSyntax()
                        .WithLeadingTrivia(catchDeclarationSyntax.Type.GetLeadingTrivia())
                        .WithTrailingTrivia(catchDeclarationSyntax.Type.GetTrailingTrivia());
                    return Cast<TDeclarationNode>(catchDeclarationSyntax.WithType(newTypeSyntax));

                default:
                    return declaration;
            }
        }

C
CyrusNajmabadi 已提交
790
        public override TDeclarationNode UpdateDeclarationMembers<TDeclarationNode>(TDeclarationNode declaration, IList<ISymbol> newMembers, CodeGenerationOptions options = null, CancellationToken cancellationToken = default)
P
Pilchie 已提交
791
        {
C
CyrusNajmabadi 已提交
792
            if (declaration is MemberDeclarationSyntax memberDeclaration)
P
Pilchie 已提交
793 794 795 796
            {
                return Cast<TDeclarationNode>(NamedTypeGenerator.UpdateNamedTypeDeclaration(this, memberDeclaration, newMembers, options, cancellationToken));
            }

C
CyrusNajmabadi 已提交
797
            if (declaration is CSharpSyntaxNode syntaxNode)
P
Pilchie 已提交
798
            {
799
                switch (syntaxNode.Kind())
P
Pilchie 已提交
800 801 802 803 804 805 806 807 808 809
                {
                    case SyntaxKind.CompilationUnit:
                    case SyntaxKind.NamespaceDeclaration:
                        return Cast<TDeclarationNode>(NamespaceGenerator.UpdateCompilationUnitOrNamespaceDeclaration(this, syntaxNode, newMembers, options, cancellationToken));
                }
            }

            return declaration;
        }
    }
810
}