ICodeDefinitionFactoryExtensions.cs 24.4 KB
Newer Older
1
// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.
P
Pilchie 已提交
2 3 4 5 6

using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
C
CyrusNajmabadi 已提交
7
using System.Threading.Tasks;
P
Pilchie 已提交
8
using Microsoft.CodeAnalysis.CodeGeneration;
9
using Microsoft.CodeAnalysis.Editing;
P
Pilchie 已提交
10
using Microsoft.CodeAnalysis.FindSymbols;
T
Tomas Matousek 已提交
11
using Microsoft.CodeAnalysis.PooledObjects;
12
using Microsoft.CodeAnalysis.Simplification;
P
Pilchie 已提交
13 14 15 16 17 18
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.Shared.Extensions
{
    internal static partial class ICodeDefinitionFactoryExtensions
    {
19
        public static SyntaxNode CreateThrowNotImplementedStatement(
20
            this SyntaxGenerator codeDefinitionFactory,
P
Pilchie 已提交
21 22
            Compilation compilation)
        {
23
            return codeDefinitionFactory.ThrowStatement(
24 25 26
               codeDefinitionFactory.ObjectCreationExpression(
                   codeDefinitionFactory.TypeExpression(compilation.NotImplementedExceptionType(), addImport: false),
                   SpecializedCollections.EmptyList<SyntaxNode>()));
P
Pilchie 已提交
27 28
        }

C
CyrusNajmabadi 已提交
29 30 31
        public static ImmutableArray<SyntaxNode> CreateThrowNotImplementedStatementBlock(
            this SyntaxGenerator codeDefinitionFactory, Compilation compilation)
            => ImmutableArray.Create(CreateThrowNotImplementedStatement(codeDefinitionFactory, compilation));
P
Pilchie 已提交
32

C
CyrusNajmabadi 已提交
33
        public static ImmutableArray<SyntaxNode> CreateArguments(
34
            this SyntaxGenerator factory,
P
Pilchie 已提交
35 36
            ImmutableArray<IParameterSymbol> parameters)
        {
C
CyrusNajmabadi 已提交
37
            return parameters.SelectAsArray(p => CreateArgument(factory, p));
P
Pilchie 已提交
38 39 40
        }

        private static SyntaxNode CreateArgument(
41
            this SyntaxGenerator factory,
P
Pilchie 已提交
42 43
            IParameterSymbol parameter)
        {
44
            return factory.Argument(parameter.RefKind, factory.IdentifierName(parameter.Name));
P
Pilchie 已提交
45 46 47
        }

        public static IMethodSymbol CreateBaseDelegatingConstructor(
48
            this SyntaxGenerator factory,
P
Pilchie 已提交
49 50 51 52 53 54
            IMethodSymbol constructor,
            string typeName)
        {
            // Create a constructor that calls the base constructor.  Note: if there are no
            // parameters then don't bother writing out "base()" it's automatically implied.
            return CodeGenerationSymbolFactory.CreateConstructorSymbol(
C
CyrusNajmabadi 已提交
55
                attributes: default,
P
Pilchie 已提交
56
                accessibility: Accessibility.Public,
57
                modifiers: new DeclarationModifiers(),
P
Pilchie 已提交
58 59
                typeName: typeName,
                parameters: constructor.Parameters,
C
CyrusNajmabadi 已提交
60
                statements: default,
C
CyrusNajmabadi 已提交
61
                baseConstructorArguments: constructor.Parameters.Length == 0
C
CyrusNajmabadi 已提交
62
                    ? default
C
CyrusNajmabadi 已提交
63
                    : factory.CreateArguments(constructor.Parameters));
P
Pilchie 已提交
64 65
        }

C
CyrusNajmabadi 已提交
66
        public static (ImmutableArray<ISymbol> fields, ISymbol constructor) CreateFieldDelegatingConstructor(
67
            this SyntaxGenerator factory,
68
            Compilation compilation,
P
Pilchie 已提交
69 70
            string typeName,
            INamedTypeSymbol containingTypeOpt,
C
CyrusNajmabadi 已提交
71
            ImmutableArray<IParameterSymbol> parameters,
P
Pilchie 已提交
72 73
            IDictionary<string, ISymbol> parameterToExistingFieldMap,
            IDictionary<string, string> parameterToNewFieldMap,
74 75
            bool addNullChecks,
            bool preferThrowExpression,
P
Pilchie 已提交
76 77 78
            CancellationToken cancellationToken)
        {
            var fields = factory.CreateFieldsForParameters(parameters, parameterToNewFieldMap);
79 80 81 82
            var statements = factory.CreateAssignmentStatements(
                compilation, parameters, parameterToExistingFieldMap, parameterToNewFieldMap, 
                addNullChecks, preferThrowExpression).SelectAsArray(
                    s => s.WithAdditionalAnnotations(Simplifier.Annotation));
P
Pilchie 已提交
83

84
            var constructor = CodeGenerationSymbolFactory.CreateConstructorSymbol(
C
CyrusNajmabadi 已提交
85
                attributes: default,
P
Pilchie 已提交
86
                accessibility: Accessibility.Public,
87
                modifiers: new DeclarationModifiers(),
P
Pilchie 已提交
88 89
                typeName: typeName,
                parameters: parameters,
90
                statements: statements,
P
Pilchie 已提交
91
                thisConstructorArguments: GetThisConstructorArguments(containingTypeOpt, parameterToExistingFieldMap));
92

C
CyrusNajmabadi 已提交
93
            return (ImmutableArray<ISymbol>.CastUp(fields), constructor);
P
Pilchie 已提交
94 95
        }

C
CyrusNajmabadi 已提交
96
        private static ImmutableArray<SyntaxNode> GetThisConstructorArguments(
P
Pilchie 已提交
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
            INamedTypeSymbol containingTypeOpt,
            IDictionary<string, ISymbol> parameterToExistingFieldMap)
        {
            if (containingTypeOpt != null && containingTypeOpt.TypeKind == TypeKind.Struct)
            {
                // Special case.  If we're generating a struct constructor, then we'll need
                // to initialize all fields in the struct, not just the ones we're creating.  To
                // do that, we call the default constructor.
                var realFields = containingTypeOpt.GetMembers()
                                     .OfType<IFieldSymbol>()
                                     .Where(f => !f.IsStatic);
                var initializedFields = parameterToExistingFieldMap.Values
                                            .OfType<IFieldSymbol>()
                                            .Where(f => !f.IsImplicitlyDeclared && !f.IsStatic);
                if (initializedFields.Count() < realFields.Count())
                {
                    // We have less field assignments than actual fields.  Generate a call to the
                    // default constructor as well.
C
CyrusNajmabadi 已提交
115
                    return ImmutableArray<SyntaxNode>.Empty;
P
Pilchie 已提交
116 117 118
                }
            }

C
CyrusNajmabadi 已提交
119
            return default;
P
Pilchie 已提交
120 121
        }

122
        public static ImmutableArray<IFieldSymbol> CreateFieldsForParameters(
123
            this SyntaxGenerator factory,
P
Pilchie 已提交
124 125 126
            IList<IParameterSymbol> parameters,
            IDictionary<string, string> parameterToNewFieldMap)
        {
127
            var result = ArrayBuilder<IFieldSymbol>.GetInstance();
P
Pilchie 已提交
128 129 130 131 132 133 134 135 136 137
            foreach (var parameter in parameters)
            {
                var refKind = parameter.RefKind;
                var parameterType = parameter.Type;
                var parameterName = parameter.Name;

                if (refKind != RefKind.Out)
                {
                    // For non-out parameters, create a field and assign the parameter to it. 
                    // TODO: I'm not sure that's what we really want for ref parameters. 
C
CyrusNajmabadi 已提交
138
                    if (TryGetValue(parameterToNewFieldMap, parameterName, out var fieldName))
P
Pilchie 已提交
139
                    {
140
                        result.Add(CodeGenerationSymbolFactory.CreateFieldSymbol(
C
CyrusNajmabadi 已提交
141
                            attributes: default,
P
Pilchie 已提交
142
                            accessibility: Accessibility.Private,
C
CyrusNajmabadi 已提交
143
                            modifiers: default,
P
Pilchie 已提交
144
                            type: parameterType,
145
                            name: parameterToNewFieldMap[parameterName]));
P
Pilchie 已提交
146 147 148
                    }
                }
            }
149 150

            return result.ToImmutableAndFree();
P
Pilchie 已提交
151 152 153 154 155 156 157 158 159 160 161 162 163
        }

        private static bool TryGetValue(IDictionary<string, string> dictionary, string key, out string value)
        {
            value = null;
            return
                dictionary != null &&
                dictionary.TryGetValue(key, out value);
        }

        private static bool TryGetValue(IDictionary<string, ISymbol> dictionary, string key, out string value)
        {
            value = null;
C
CyrusNajmabadi 已提交
164
            if (dictionary != null && dictionary.TryGetValue(key, out var symbol))
P
Pilchie 已提交
165 166 167 168 169 170 171 172
            {
                value = symbol.Name;
                return true;
            }

            return false;
        }

173
        public static SyntaxNode CreateThrowArgumentNullExpression(
174
            this SyntaxGenerator factory,
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
            Compilation compilation,
            IParameterSymbol parameter)
        {
            return factory.ThrowExpression(
                factory.ObjectCreationExpression(
                    compilation.GetTypeByMetadataName("System.ArgumentNullException"),
                    factory.NameOfExpression(
                        factory.IdentifierName(parameter.Name))));
        }

        public static SyntaxNode CreateIfNullThrowStatement(
            this SyntaxGenerator factory,
            Compilation compilation,
            IParameterSymbol parameter)
        {
            return factory.IfStatement(
                factory.ReferenceEqualsExpression(
                    factory.IdentifierName(parameter.Name),
                    factory.NullLiteralExpression()),
                SpecializedCollections.SingletonEnumerable(
                    factory.ExpressionStatement(
                        factory.CreateThrowArgumentNullExpression(compilation, parameter))));
        }

        public static ImmutableArray<SyntaxNode> CreateAssignmentStatements(
            this SyntaxGenerator factory,
            Compilation compilation,
P
Pilchie 已提交
202 203
            IList<IParameterSymbol> parameters,
            IDictionary<string, ISymbol> parameterToExistingFieldMap,
204 205 206
            IDictionary<string, string> parameterToNewFieldMap,
            bool addNullChecks,
            bool preferThrowExpression)
P
Pilchie 已提交
207
        {
208 209 210
            var nullCheckStatements = ArrayBuilder<SyntaxNode>.GetInstance();
            var assignStatements = ArrayBuilder<SyntaxNode>.GetInstance();

P
Pilchie 已提交
211 212 213 214 215 216 217 218 219
            foreach (var parameter in parameters)
            {
                var refKind = parameter.RefKind;
                var parameterType = parameter.Type;
                var parameterName = parameter.Name;

                if (refKind == RefKind.Out)
                {
                    // If it's an out param, then don't create a field for it.  Instead, assign
220
                    // the default value for that type (i.e. "default(...)") to it.
221 222 223 224
                    var assignExpression = factory.AssignmentStatement(
                        factory.IdentifierName(parameterName),
                        factory.DefaultExpression(parameterType));
                    var statement = factory.ExpressionStatement(assignExpression);
225
                    assignStatements.Add(statement);
P
Pilchie 已提交
226 227 228 229 230
                }
                else
                {
                    // For non-out parameters, create a field and assign the parameter to it. 
                    // TODO: I'm not sure that's what we really want for ref parameters. 
C
CyrusNajmabadi 已提交
231
                    if (TryGetValue(parameterToExistingFieldMap, parameterName, out var fieldName) ||
P
Pilchie 已提交
232 233
                        TryGetValue(parameterToNewFieldMap, parameterName, out fieldName))
                    {
234 235
                        var fieldAccess = factory.MemberAccessExpression(factory.ThisExpression(), factory.IdentifierName(fieldName))
                                                 .WithAdditionalAnnotations(Simplifier.Annotation);
236

C
CyrusNajmabadi 已提交
237 238 239 240
                        factory.AddAssignmentStatements(
                            compilation, parameter, fieldAccess,
                            addNullChecks, preferThrowExpression,
                            nullCheckStatements, assignStatements);
P
Pilchie 已提交
241 242 243
                    }
                }
            }
244 245 246 247

            return nullCheckStatements.ToImmutableAndFree().Concat(assignStatements.ToImmutableAndFree());
        }

C
CyrusNajmabadi 已提交
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
        public static void AddAssignmentStatements(
             this SyntaxGenerator factory,
             Compilation compilation,
             IParameterSymbol parameter,
             SyntaxNode fieldAccess,
             bool addNullChecks,
             bool preferThrowExpression,
             ArrayBuilder<SyntaxNode> nullCheckStatements,
             ArrayBuilder<SyntaxNode> assignStatements)
        {
            var shouldAddNullCheck = addNullChecks && parameter.Type.CanAddNullCheck();
            if (shouldAddNullCheck && preferThrowExpression)
            {
                // Generate: this.x = x ?? throw ...
                assignStatements.Add(CreateAssignWithNullCheckStatement(
                    factory, compilation, parameter, fieldAccess));
            }
            else
            {
                if (shouldAddNullCheck)
                {
                    // generate: if (x == null) throw ...
                    nullCheckStatements.Add(
                        factory.CreateIfNullThrowStatement(compilation, parameter));
                }

                // generate: this.x = x;
                assignStatements.Add(
                    factory.ExpressionStatement(
                        factory.AssignmentStatement(
                            fieldAccess,
                            factory.IdentifierName(parameter.Name))));
            }
        }

283 284 285 286 287 288 289 290
        public static SyntaxNode CreateAssignWithNullCheckStatement(
            this SyntaxGenerator factory, Compilation compilation, IParameterSymbol parameter, SyntaxNode fieldAccess)
        {
            return factory.ExpressionStatement(factory.AssignmentStatement(
                fieldAccess,
                factory.CoalesceExpression(
                    factory.IdentifierName(parameter.Name),
                    factory.CreateThrowArgumentNullExpression(compilation, parameter))));
P
Pilchie 已提交
291 292
        }

C
CyrusNajmabadi 已提交
293
        public static async Task<IPropertySymbol> OverridePropertyAsync(
294
            this SyntaxGenerator codeFactory,
P
Pilchie 已提交
295
            IPropertySymbol overriddenProperty,
C
CyrusNajmabadi 已提交
296
            DeclarationModifiers modifiers,
P
Pilchie 已提交
297 298
            INamedTypeSymbol containingType,
            Document document,
C
CyrusNajmabadi 已提交
299
            CancellationToken cancellationToken)
P
Pilchie 已提交
300 301 302 303 304 305 306 307 308 309
        {
            var getAccessibility = overriddenProperty.GetMethod.ComputeResultantAccessibility(containingType);
            var setAccessibility = overriddenProperty.SetMethod.ComputeResultantAccessibility(containingType);

            SyntaxNode getBody = null;
            SyntaxNode setBody = null;

            // Implement an abstract property by throwing not implemented in accessors.
            if (overriddenProperty.IsAbstract)
            {
C
CyrusNajmabadi 已提交
310
                var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
311 312 313 314
                var statement = codeFactory.CreateThrowNotImplementedStatement(compilation);

                getBody = statement;
                setBody = statement;
P
Pilchie 已提交
315 316 317 318
            }
            else if (overriddenProperty.IsIndexer() && document.Project.Language == LanguageNames.CSharp)
            {
                // Indexer: return or set base[]. Only in C#, since VB must refer to these by name.
319

C
CyrusNajmabadi 已提交
320
                getBody = codeFactory.ReturnStatement(
C
CyrusNajmabadi 已提交
321
                    WrapWithRefIfNecessary(codeFactory, overriddenProperty,
C
CyrusNajmabadi 已提交
322 323 324
                        codeFactory.ElementAccessExpression(
                            codeFactory.BaseExpression(),
                            codeFactory.CreateArguments(overriddenProperty.Parameters))));
P
Pilchie 已提交
325

326 327 328 329
                setBody = codeFactory.ExpressionStatement(
                    codeFactory.AssignmentStatement(
                    codeFactory.ElementAccessExpression(
                        codeFactory.BaseExpression(),
P
Pilchie 已提交
330
                        codeFactory.CreateArguments(overriddenProperty.Parameters)),
331
                    codeFactory.IdentifierName("value")));
P
Pilchie 已提交
332 333 334 335 336
            }
            else if (overriddenProperty.GetParameters().Any())
            {
                // Call accessors directly if C# overriding VB
                if (document.Project.Language == LanguageNames.CSharp
C
CyrusNajmabadi 已提交
337 338
                    && (await SymbolFinder.FindSourceDefinitionAsync(overriddenProperty, document.Project.Solution, cancellationToken).ConfigureAwait(false))
                        .Language == LanguageNames.VisualBasic)
P
Pilchie 已提交
339
                {
340 341
                    var getName = overriddenProperty.GetMethod?.Name;
                    var setName = overriddenProperty.SetMethod?.Name;
P
Pilchie 已提交
342 343 344

                    getBody = getName == null
                        ? null
345 346 347 348 349
                        : codeFactory.ReturnStatement(
                    codeFactory.InvocationExpression(
                        codeFactory.MemberAccessExpression(
                            codeFactory.BaseExpression(),
                            codeFactory.IdentifierName(getName)),
P
Pilchie 已提交
350 351 352 353
                        codeFactory.CreateArguments(overriddenProperty.Parameters)));

                    setBody = setName == null
                        ? null
354 355 356 357 358
                        : codeFactory.ExpressionStatement(
                        codeFactory.InvocationExpression(
                            codeFactory.MemberAccessExpression(
                                codeFactory.BaseExpression(),
                                codeFactory.IdentifierName(setName)),
P
Pilchie 已提交
359 360 361 362
                            codeFactory.CreateArguments(overriddenProperty.SetMethod.GetParameters())));
                }
                else
                {
C
CyrusNajmabadi 已提交
363
                    getBody = codeFactory.ReturnStatement(
C
CyrusNajmabadi 已提交
364
                        WrapWithRefIfNecessary(codeFactory, overriddenProperty,
C
CyrusNajmabadi 已提交
365 366 367 368
                            codeFactory.InvocationExpression(
                                codeFactory.MemberAccessExpression(
                                    codeFactory.BaseExpression(),
                                    codeFactory.IdentifierName(overriddenProperty.Name)), codeFactory.CreateArguments(overriddenProperty.Parameters))));
369

370 371 372 373 374 375 376
                    setBody = codeFactory.ExpressionStatement(
                        codeFactory.AssignmentStatement(
                            codeFactory.InvocationExpression(
                            codeFactory.MemberAccessExpression(
                            codeFactory.BaseExpression(),
                        codeFactory.IdentifierName(overriddenProperty.Name)), codeFactory.CreateArguments(overriddenProperty.Parameters)),
                        codeFactory.IdentifierName("value")));
P
Pilchie 已提交
377 378 379 380 381
                }
            }
            else
            {
                // Regular property: return or set the base property
382

C
CyrusNajmabadi 已提交
383 384 385 386 387
                getBody = codeFactory.ReturnStatement(
                    WrapWithRefIfNecessary(codeFactory, overriddenProperty,
                        codeFactory.MemberAccessExpression(
                            codeFactory.BaseExpression(),
                            codeFactory.IdentifierName(overriddenProperty.Name))));
388

389 390 391 392 393 394
                setBody = codeFactory.ExpressionStatement(
                    codeFactory.AssignmentStatement(
                        codeFactory.MemberAccessExpression(
                        codeFactory.BaseExpression(),
                    codeFactory.IdentifierName(overriddenProperty.Name)),
                    codeFactory.IdentifierName("value")));
P
Pilchie 已提交
395 396 397 398 399 400 401 402 403
            }

            // Only generate a getter if the base getter is accessible.
            IMethodSymbol accessorGet = null;
            if (overriddenProperty.GetMethod != null && overriddenProperty.GetMethod.IsAccessibleWithin(containingType))
            {
                accessorGet = CodeGenerationSymbolFactory.CreateMethodSymbol(
                    overriddenProperty.GetMethod,
                    accessibility: getAccessibility,
C
CyrusNajmabadi 已提交
404
                    statements: ImmutableArray.Create(getBody),
P
Pilchie 已提交
405 406 407 408 409 410 411 412 413 414 415 416
                    modifiers: modifiers);
            }

            // Only generate a setter if the base setter is accessible.
            IMethodSymbol accessorSet = null;
            if (overriddenProperty.SetMethod != null &&
                overriddenProperty.SetMethod.IsAccessibleWithin(containingType) &&
                overriddenProperty.SetMethod.DeclaredAccessibility != Accessibility.Private)
            {
                accessorSet = CodeGenerationSymbolFactory.CreateMethodSymbol(
                    overriddenProperty.SetMethod,
                    accessibility: setAccessibility,
C
CyrusNajmabadi 已提交
417
                    statements: ImmutableArray.Create(setBody),
P
Pilchie 已提交
418 419 420 421 422 423 424 425 426 427 428 429 430
                    modifiers: modifiers);
            }

            return CodeGenerationSymbolFactory.CreatePropertySymbol(
                overriddenProperty,
                accessibility: overriddenProperty.ComputeResultantAccessibility(containingType),
                modifiers: modifiers,
                name: overriddenProperty.Name,
                isIndexer: overriddenProperty.IsIndexer(),
                getMethod: accessorGet,
                setMethod: accessorSet);
        }

C
CyrusNajmabadi 已提交
431 432 433 434 435
        private static SyntaxNode WrapWithRefIfNecessary(SyntaxGenerator codeFactory, IPropertySymbol overriddenProperty, SyntaxNode body)
            => overriddenProperty.ReturnsByRef
                ? codeFactory.RefExpression(body)
                : body;

P
Pilchie 已提交
436
        public static IEventSymbol OverrideEvent(
437
            this SyntaxGenerator codeFactory,
P
Pilchie 已提交
438
            IEventSymbol overriddenEvent,
C
CyrusNajmabadi 已提交
439 440
            DeclarationModifiers modifiers,
            INamedTypeSymbol newContainingType)
P
Pilchie 已提交
441 442 443
        {
            return CodeGenerationSymbolFactory.CreateEventSymbol(
                overriddenEvent,
C
CyrusNajmabadi 已提交
444
                attributes: default,
P
Pilchie 已提交
445 446
                accessibility: overriddenEvent.ComputeResultantAccessibility(newContainingType),
                modifiers: modifiers,
447
                explicitInterfaceImplementations: default,
P
Pilchie 已提交
448 449 450
                name: overriddenEvent.Name);
        }

451 452 453 454 455 456
        public static async Task<ISymbol> OverrideAsync(
            this SyntaxGenerator generator,
            ISymbol symbol,
            INamedTypeSymbol containingType,
            Document document,
            DeclarationModifiers? modifiersOpt = null,
C
CyrusNajmabadi 已提交
457
            CancellationToken cancellationToken = default)
458
        {
459
            var modifiers = modifiersOpt ?? GetOverrideModifiers(symbol);
460 461 462 463

            if (symbol is IMethodSymbol method)
            {
                return await generator.OverrideMethodAsync(method,
C
CyrusNajmabadi 已提交
464
                    modifiers, containingType, document, cancellationToken).ConfigureAwait(false);
465 466 467 468
            }
            else if (symbol is IPropertySymbol property)
            {
                return await generator.OverridePropertyAsync(property,
C
CyrusNajmabadi 已提交
469
                    modifiers, containingType, document, cancellationToken).ConfigureAwait(false);
470 471 472
            }
            else if (symbol is IEventSymbol ev)
            {
C
CyrusNajmabadi 已提交
473
                return generator.OverrideEvent(ev, modifiers, containingType);
474 475 476
            }
            else
            {
C
CyrusNajmabadi 已提交
477
                throw ExceptionUtilities.Unreachable;
478 479 480
            }
        }

481 482 483 484 485 486
        private static DeclarationModifiers GetOverrideModifiers(ISymbol symbol)
            => symbol.GetSymbolModifiers()
                     .WithIsOverride(true)
                     .WithIsAbstract(false)
                     .WithIsVirtual(false);

C
CyrusNajmabadi 已提交
487
        private static async Task<IMethodSymbol> OverrideMethodAsync(
488
            this SyntaxGenerator codeFactory,
P
Pilchie 已提交
489
            IMethodSymbol overriddenMethod,
C
CyrusNajmabadi 已提交
490
            DeclarationModifiers modifiers,
P
Pilchie 已提交
491 492
            INamedTypeSymbol newContainingType,
            Document newDocument,
C
CyrusNajmabadi 已提交
493
            CancellationToken cancellationToken)
P
Pilchie 已提交
494 495 496 497
        {
            // Abstract: Throw not implemented
            if (overriddenMethod.IsAbstract)
            {
C
CyrusNajmabadi 已提交
498
                var compilation = await newDocument.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
499 500
                var statement = codeFactory.CreateThrowNotImplementedStatement(compilation);

P
Pilchie 已提交
501 502 503 504
                return CodeGenerationSymbolFactory.CreateMethodSymbol(
                    overriddenMethod,
                    accessibility: overriddenMethod.ComputeResultantAccessibility(newContainingType),
                    modifiers: modifiers,
C
CyrusNajmabadi 已提交
505
                    statements: ImmutableArray.Create(statement));
P
Pilchie 已提交
506 507 508 509 510
            }
            else
            {
                // Otherwise, call the base method with the same parameters
                var typeParams = overriddenMethod.GetTypeArguments();
511 512
                var body = codeFactory.InvocationExpression(
                    codeFactory.MemberAccessExpression(codeFactory.BaseExpression(),
P
Pilchie 已提交
513
                    typeParams.IsDefaultOrEmpty
514 515
                        ? codeFactory.IdentifierName(overriddenMethod.Name)
                        : codeFactory.GenericName(overriddenMethod.Name, typeParams)),
P
Pilchie 已提交
516 517
                    codeFactory.CreateArguments(overriddenMethod.GetParameters()));

518 519 520 521 522
                if (overriddenMethod.ReturnsByRef)
                {
                    body = codeFactory.RefExpression(body);
                }

P
Pilchie 已提交
523 524 525 526
                return CodeGenerationSymbolFactory.CreateMethodSymbol(
                    method: overriddenMethod,
                    accessibility: overriddenMethod.ComputeResultantAccessibility(newContainingType),
                    modifiers: modifiers,
C
Cyrus Najmabadi 已提交
527
                    statements: overriddenMethod.ReturnsVoid
C
CyrusNajmabadi 已提交
528 529
                        ? ImmutableArray.Create(codeFactory.ExpressionStatement(body))
                        : ImmutableArray.Create(codeFactory.ReturnStatement(body)));
P
Pilchie 已提交
530 531 532
            }
        }
    }
T
Tomas Matousek 已提交
533
}