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