private async Task <Document> GenerateFieldDelegatingConstructorAsync()
            {
                var arguments      = _state.Arguments.ToList();
                var parameterTypes = _state.ParameterTypes;

                var typeParametersNames = _state.TypeToGenerateIn.GetAllTypeParameters().Select(t => t.Name).ToList();
                var parameterNames      = _state.AttributeArguments != null
                                        ? _service.GenerateParameterNames(_document.SemanticModel, _state.AttributeArguments, typeParametersNames)
                                        : _service.GenerateParameterNames(_document.SemanticModel, arguments, typeParametersNames);

                Dictionary <string, ISymbol> parameterToExistingFieldMap;
                Dictionary <string, string>  parameterToNewFieldMap;
                List <IParameterSymbol>      parameters;

                GetParameters(arguments, _state.AttributeArguments, parameterTypes, parameterNames, out parameterToExistingFieldMap, out parameterToNewFieldMap, out parameters);

                var provider              = _document.Project.Solution.Workspace.Services.GetLanguageServices(_state.TypeToGenerateIn.Language);
                var syntaxFactory         = provider.GetService <SyntaxGenerator>();
                var codeGenerationService = new CSharpCodeGenerationService(_document.Project.Solution.Workspace);

                var syntaxTree = _document.SyntaxTree;
                var members    = syntaxFactory.CreateFieldDelegatingConstructor(
                    _state.TypeToGenerateIn.Name, _state.TypeToGenerateIn, parameters,
                    parameterToExistingFieldMap, parameterToNewFieldMap, _cancellationToken);

                var result = await codeGenerationService.AddMembersAsync(
                    _document.Project.Solution,
                    _state.TypeToGenerateIn,
                    members,
                    new CodeGenerationOptions(_state.Token.GetLocation(), generateDefaultAccessibility : false),
                    _cancellationToken)
                             .ConfigureAwait(false);

                return(result);
            }
Пример #2
0
            protected override async Task <Document> GetChangedDocumentAsync(CancellationToken cancellationToken)
            {
                // First, see if there are any constructors that would take the first 'n' arguments
                // we've provided.  If so, delegate to those, and then create a field for any
                // remaining arguments.  Try to match from largest to smallest.
                //
                // Otherwise, just generate a normal constructor that assigns any provided
                // parameters into fields.
                var parameterToExistingFieldMap = new Dictionary <string, ISymbol>();

                for (int i = 0; i < _state.Parameters.Count; i++)
                {
                    parameterToExistingFieldMap[_state.Parameters[i].Name] = _state.SelectedMembers[i];
                }

                var factory = _document.GetLanguageService <SyntaxGenerator>();

                var syntaxTree = await _document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

                var members = factory.CreateFieldDelegatingConstructor(
                    _state.ContainingType.Name,
                    _state.ContainingType,
                    _state.Parameters,
                    parameterToExistingFieldMap,
                    parameterToNewFieldMap: null,
                    cancellationToken: cancellationToken);
                var codeGenerationService = new CSharpCodeGenerationService(_document.Project.Solution.Workspace.Services.GetLanguageServices(LanguageNames.CSharp));

                var result = await codeGenerationService.AddMembersAsync(
                    _document.Project.Solution,
                    _state.ContainingType,
                    members,
                    new CodeGenerationOptions(contextLocation : syntaxTree.GetLocation(_state.TextSpan), generateDefaultAccessibility : false),
                    cancellationToken)
                             .ConfigureAwait(false);

                return(result);
            }
            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).ToList();
                var remainingAttributeArguments = _state.AttributeArguments != null?_state.AttributeArguments.Skip(argumentCount).ToList() : null;

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

                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 = new CSharpCodeGenerationService(_document.Project.Solution.Workspace);

                // 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());

                // 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).Any())
                {
                    return(null);
                }

                // Try to map those parameters to fields.
                Dictionary <string, ISymbol> parameterToExistingFieldMap;
                Dictionary <string, string>  parameterToNewFieldMap;
                List <IParameterSymbol>      remainingParameters;

                this.GetParameters(remainingArguments, remainingAttributeArguments, remainingParameterTypes, remainingParameterNames, out parameterToExistingFieldMap, out parameterToNewFieldMap, out remainingParameters);

                var fields           = syntaxFactory.CreateFieldsForParameters(remainingParameters, parameterToNewFieldMap);
                var assignStatements = syntaxFactory.CreateAssignmentStatements(remainingParameters, parameterToExistingFieldMap, parameterToNewFieldMap);

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

                var isThis = namedType.Equals(_state.TypeToGenerateIn);
                var delegatingArguments      = syntaxFactory.CreateArguments(delegatedConstructor.Parameters);
                var baseConstructorArguments = isThis ? null : delegatingArguments;
                var thisConstructorArguments = isThis ? delegatingArguments : null;

                var constructor = CodeGenerationSymbolFactory.CreateConstructorSymbol(
                    attributes: null,
                    accessibility: Accessibility.Public,
                    modifiers: default(DeclarationModifiers),
                    typeName: _state.TypeToGenerateIn.Name,
                    parameters: allParameters,
                    statements: assignStatements.ToList(),
                    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(), generateDefaultAccessibility : false),
                    _cancellationToken)
                             .ConfigureAwait(false);

                return(result);
            }