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