Exemplo n.º 1
0
            private bool InitializeDelegatedConstructor(int argumentCount, INamedTypeSymbol namedType, CancellationToken cancellationToken)
            {
                // We can't resolve overloads across language.
                if (_document.Project.Language != namedType.Language)
                {
                    return(false);
                }

                var arguments                   = _arguments.Take(argumentCount).ToList();
                var remainingArguments          = _arguments.Skip(argumentCount).ToImmutableArray();
                var remainingAttributeArguments = _attributeArguments != null
                    ? _attributeArguments.Skip(argumentCount).ToImmutableArray()
                    : (ImmutableArray <TAttributeArgumentSyntax>?)null;

                var remainingParameterTypes = ParameterTypes.Skip(argumentCount).ToImmutableArray();

                var instanceConstructors = namedType.InstanceConstructors.Where(c => IsSymbolAccessible(c, _document)).ToSet();

                if (instanceConstructors.IsEmpty())
                {
                    return(false);
                }

                var delegatedConstructor = _service.GetDelegatingConstructor(this, _document, argumentCount, namedType, instanceConstructors, cancellationToken);

                if (delegatedConstructor == null)
                {
                    return(false);
                }

                // Map the first N parameters to the other constructor in this type.  Then
                // try to map any further parameters to existing fields.  Finally, generate
                // new fields if no such parameters exist.

                // Find the names of the parameters that will follow the parameters we're
                // delegating.
                var remainingParameterNames = _service.GenerateParameterNames(
                    _document.SemanticModel, remainingArguments,
                    delegatedConstructor.Parameters.Select(p => p.Name).ToList(),
                    _parameterNamingRule,
                    cancellationToken);

                // Can't generate the constructor if the parameter names we're copying over forcibly
                // conflict with any names we generated.
                if (delegatedConstructor.Parameters.Select(p => p.Name).Intersect(remainingParameterNames.Select(n => n.BestNameForParameter)).Any())
                {
                    return(false);
                }

                _delegatedConstructor = delegatedConstructor;
                GetParameters(remainingArguments, remainingAttributeArguments, remainingParameterTypes, remainingParameterNames, cancellationToken);
                return(true);
            }
Exemplo n.º 2
0
            private async Task <Document> GenerateDelegatingConstructorAsync(
                int argumentCount,
                INamedTypeSymbol namedType)
            {
                if (namedType == null)
                {
                    return(null);
                }

                // We can't resolve overloads across language.
                if (_document.Project.Language != namedType.Language)
                {
                    return(null);
                }

                var arguments                   = _state.Arguments.Take(argumentCount).ToList();
                var remainingArguments          = _state.Arguments.Skip(argumentCount).ToImmutableArray();
                var remainingAttributeArguments = _state.AttributeArguments != null
                    ? _state.AttributeArguments.Skip(argumentCount).ToImmutableArray()
                    : (ImmutableArray <TAttributeArgumentSyntax>?)null;

                var remainingParameterTypes = _state.ParameterTypes.Skip(argumentCount).ToImmutableArray();

                var instanceConstructors = namedType.InstanceConstructors.Where(IsSymbolAccessible).ToSet();

                if (instanceConstructors.IsEmpty())
                {
                    return(null);
                }

                var delegatedConstructor = _service.GetDelegatingConstructor(_state, _document, argumentCount, namedType, instanceConstructors, _cancellationToken);

                if (delegatedConstructor == null)
                {
                    return(null);
                }

                // There was a best match.  Call it directly.
                var provider              = _document.Project.Solution.Workspace.Services.GetLanguageServices(_state.TypeToGenerateIn.Language);
                var syntaxFactory         = provider.GetService <SyntaxGenerator>();
                var codeGenerationService = provider.GetService <ICodeGenerationService>();

                // Map the first N parameters to the other constructor in this type.  Then
                // try to map any further parameters to existing fields.  Finally, generate
                // new fields if no such parameters exist.

                // Find the names of the parameters that will follow the parameters we're
                // delegating.
                var remainingParameterNames = _service.GenerateParameterNames(
                    _document.SemanticModel, remainingArguments,
                    delegatedConstructor.Parameters.Select(p => p.Name).ToList(),
                    _cancellationToken);

                // Can't generate the constructor if the parameter names we're copying over forcibly
                // conflict with any names we generated.
                if (delegatedConstructor.Parameters.Select(p => p.Name)
                    .Intersect(remainingParameterNames.Select(n => n.BestNameForParameter)).Any())
                {
                    return(null);
                }
                // Try to map those parameters to fields.
                this.GetParameters(remainingArguments, remainingAttributeArguments,
                                   remainingParameterTypes, remainingParameterNames,
                                   out var parameterToExistingFieldMap, out var parameterToNewFieldMap, out var remainingParameters);

                var fields           = syntaxFactory.CreateFieldsForParameters(remainingParameters, parameterToNewFieldMap);
                var assignStatements = syntaxFactory.CreateAssignmentStatements(
                    _document.SemanticModel.Compilation, remainingParameters,
                    parameterToExistingFieldMap, parameterToNewFieldMap,
                    addNullChecks: false, preferThrowExpression: false);

                var allParameters = delegatedConstructor.Parameters.Concat(remainingParameters);

                var isThis = namedType.Equals(_state.TypeToGenerateIn);
                var delegatingArguments      = syntaxFactory.CreateArguments(delegatedConstructor.Parameters);
                var baseConstructorArguments = isThis ? default(ImmutableArray <SyntaxNode>) : delegatingArguments;
                var thisConstructorArguments = isThis ? delegatingArguments : default(ImmutableArray <SyntaxNode>);

                var constructor = CodeGenerationSymbolFactory.CreateConstructorSymbol(
                    attributes: default(ImmutableArray <AttributeData>),
                    accessibility: Accessibility.Public,
                    modifiers: default(DeclarationModifiers),
                    typeName: _state.TypeToGenerateIn.Name,
                    parameters: allParameters,
                    statements: assignStatements,
                    baseConstructorArguments: baseConstructorArguments,
                    thisConstructorArguments: thisConstructorArguments);

                var members = new List <ISymbol>(fields)
                {
                    constructor
                };
                var result = await codeGenerationService.AddMembersAsync(
                    _document.Project.Solution,
                    _state.TypeToGenerateIn,
                    members,
                    new CodeGenerationOptions(_state.Token.GetLocation()),
                    _cancellationToken)
                             .ConfigureAwait(false);

                return(result);
            }