From 54d97ddd742108b1e971576596539b6b736df4fb Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Sat, 13 May 2017 14:29:41 -0700 Subject: [PATCH 01/14] Remove code for generating constructors from class-decl, it will be provided by another fixer. --- .../GenerateConstructorCodeFixProvider.cs | 41 ++++--------------- .../GenerateConstructorCodeFixProvider.vb | 24 ++++------- 2 files changed, 16 insertions(+), 49 deletions(-) diff --git a/src/Features/CSharp/Portable/GenerateConstructor/GenerateConstructorCodeFixProvider.cs b/src/Features/CSharp/Portable/GenerateConstructor/GenerateConstructorCodeFixProvider.cs index e7b18c97f106c..cb9c038cbe578 100644 --- a/src/Features/CSharp/Portable/GenerateConstructor/GenerateConstructorCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/GenerateConstructor/GenerateConstructorCodeFixProvider.cs @@ -1,6 +1,5 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System.Collections.Generic; using System.Collections.Immutable; using System.Composition; using System.Threading; @@ -12,7 +11,6 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.GenerateMember.GenerateConstructor; using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.CSharp.GenerateConstructor { @@ -46,43 +44,22 @@ protected override Task> GetCodeActionsAsync( protected override bool IsCandidate(SyntaxNode node, SyntaxToken token, Diagnostic diagnostic) { - if (node is ObjectCreationExpressionSyntax || - node is ConstructorInitializerSyntax || - node is AttributeSyntax) - { - return true; - } - - return diagnostic.Id == GenerateConstructorDiagnosticIds.CS7036 && - node is ClassDeclarationSyntax && - IsInClassDeclarationHeader((ClassDeclarationSyntax)node, token); - } - - private bool IsInClassDeclarationHeader(ClassDeclarationSyntax node, SyntaxToken token) - { - var start = node.SpanStart; - var end = node.BaseList != null - ? node.BaseList.Span.End - : node.Identifier.Span.End; - - return TextSpan.FromBounds(start, end).Contains(token.Span); + return node is ObjectCreationExpressionSyntax || + node is ConstructorInitializerSyntax || + node is AttributeSyntax; } protected override SyntaxNode GetTargetNode(SyntaxNode node) { - var objectCreationNode = node as ObjectCreationExpressionSyntax; - if (objectCreationNode != null) - { - return objectCreationNode.Type.GetRightmostName(); - } - - var attributeNode = node as AttributeSyntax; - if (attributeNode != null) + switch (node) { - return attributeNode.Name; + case ObjectCreationExpressionSyntax objectCreationNode: + return objectCreationNode.Type.GetRightmostName(); + case AttributeSyntax attributeNode: + return attributeNode.Name; } return node; } } -} +} \ No newline at end of file diff --git a/src/Features/VisualBasic/Portable/GenerateConstructor/GenerateConstructorCodeFixProvider.vb b/src/Features/VisualBasic/Portable/GenerateConstructor/GenerateConstructorCodeFixProvider.vb index 487c4c143389a..98adf9129f224 100644 --- a/src/Features/VisualBasic/Portable/GenerateConstructor/GenerateConstructorCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/GenerateConstructor/GenerateConstructorCodeFixProvider.vb @@ -1,13 +1,13 @@ ' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -Imports System.Threading Imports System.Collections.Immutable +Imports System.Composition +Imports System.Threading Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.CodeFixes.GenerateMember -Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.GenerateMember.GenerateConstructor -Imports System.Composition +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateConstructor Friend Class GenerateConstructorDiagnosticIds @@ -60,19 +60,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateConstructor End Function Protected Overrides Function IsCandidate(node As SyntaxNode, token As SyntaxToken, diagnostic As Diagnostic) As Boolean - If TypeOf node Is InvocationExpressionSyntax OrElse - TypeOf node Is ObjectCreationExpressionSyntax OrElse - TypeOf node Is AttributeSyntax Then - Return True - End If - - Return diagnostic.Id = GenerateConstructorDiagnosticIds.BC30387 AndAlso - TypeOf node Is ClassBlockSyntax AndAlso - IsInClassDeclarationHeader(DirectCast(node, ClassBlockSyntax), token) - End Function - - Private Function IsInClassDeclarationHeader(node As ClassBlockSyntax, token As SyntaxToken) As Boolean - Return node.ClassStatement.Span.Contains(token.Span) + Return TypeOf node Is InvocationExpressionSyntax OrElse + TypeOf node Is ObjectCreationExpressionSyntax OrElse + TypeOf node Is AttributeSyntax End Function End Class -End Namespace +End Namespace \ No newline at end of file From 4c2862c19c16bdedddd4cadcf53a7f1d74b749e7 Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Sat, 13 May 2017 15:10:04 -0700 Subject: [PATCH 02/14] Move delegated constructor responsibility to the refactoring provider. --- ...SharpGenerateDefaultConstructorsService.cs | 48 +++++++------ ...uctorFromMembersCodeRefactoringProvider.cs | 18 +---- ...tConstructorsService.AbstractCodeAction.cs | 4 +- ...teDefaultConstructorsService.CodeAction.cs | 2 +- ...efaultConstructorsService.CodeActionAll.cs | 13 +--- ...enerateDefaultConstructorsService.State.cs | 68 +++++++++---------- ...tractGenerateDefaultConstructorsService.cs | 31 ++++----- ...BasicGenerateDefaultConstructorsService.vb | 30 +++++--- 8 files changed, 101 insertions(+), 113 deletions(-) diff --git a/src/Features/CSharp/Portable/GenerateMember/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsService.cs b/src/Features/CSharp/Portable/GenerateMember/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsService.cs index 03ca328782ad8..2cc803fe7bd7b 100644 --- a/src/Features/CSharp/Portable/GenerateMember/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsService.cs +++ b/src/Features/CSharp/Portable/GenerateMember/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsService.cs @@ -4,8 +4,10 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.GenerateFromMembers; using Microsoft.CodeAnalysis.GenerateMember.GenerateDefaultConstructors; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -16,33 +18,41 @@ internal class CSharpGenerateDefaultConstructorsService : AbstractGenerateDefaul { protected override bool TryInitializeState( SemanticDocument document, TextSpan textSpan, CancellationToken cancellationToken, - out SyntaxNode baseTypeNode, out INamedTypeSymbol classType) + out INamedTypeSymbol classOrStructType) { - if (!cancellationToken.IsCancellationRequested) + cancellationToken.ThrowIfCancellationRequested(); + + // Offer the feature if we're on the header for the class/struct, or if we're on the + // first base-type of a class. + + var syntaxFacts = document.Document.GetLanguageService(); + if (syntaxFacts.IsOnTypeHeader(document.Root, textSpan.Start)) + { + classOrStructType = AbstractGenerateFromMembersCodeRefactoringProvider.GetEnclosingNamedType( + document.SemanticModel, document.Root, textSpan.Start, cancellationToken); + return classOrStructType != null; + } + + var syntaxTree = document.SyntaxTree; + var node = document.Root.FindToken(textSpan.Start).GetAncestor(); + if (node != null) { - var syntaxTree = document.SyntaxTree; - var node = document.Root.FindToken(textSpan.Start).GetAncestor(); - if (node != null) + if (node.Parent is BaseTypeSyntax && node.Parent.IsParentKind(SyntaxKind.BaseList)) { - if (node.Parent is BaseTypeSyntax && node.Parent.IsParentKind(SyntaxKind.BaseList)) + var baseList = (BaseListSyntax)node.Parent.Parent; + if (baseList.Types.Count > 0 && + baseList.Types[0].Type == node && + baseList.IsParentKind(SyntaxKind.ClassDeclaration)) { - var baseList = (BaseListSyntax)node.Parent.Parent; - if (baseList.Types.Count > 0 && - baseList.Types[0].Type == node && - baseList.IsParentKind(SyntaxKind.ClassDeclaration)) - { - var semanticModel = document.SemanticModel; - classType = semanticModel.GetDeclaredSymbol(baseList.Parent, cancellationToken) as INamedTypeSymbol; - baseTypeNode = node; - return classType != null; - } + var semanticModel = document.SemanticModel; + classOrStructType = semanticModel.GetDeclaredSymbol(baseList.Parent, cancellationToken) as INamedTypeSymbol; + return classOrStructType != null; } } } - baseTypeNode = null; - classType = null; + classOrStructType = null; return false; } } -} +} \ No newline at end of file diff --git a/src/Features/Core/Portable/GenerateConstructorFromMembers/GenerateConstructorFromMembersCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateConstructorFromMembers/GenerateConstructorFromMembersCodeRefactoringProvider.cs index e9c64bc7f183b..17ef5f446f6fa 100644 --- a/src/Features/Core/Portable/GenerateConstructorFromMembers/GenerateConstructorFromMembersCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/GenerateConstructorFromMembers/GenerateConstructorFromMembersCodeRefactoringProvider.cs @@ -93,26 +93,10 @@ private async Task HandleNonSelectionAsync(CodeRefactoringContext context) // Find all the possible writable instance fields/properties. If there are any, then // show a dialog to the user to select the ones they want. Otherwise, if there are none - // just offer to generate the no-param constructor if they don't already have one. + // don't offer to generate anything. var viableMembers = containingType.GetMembers().WhereAsArray(IsWritableInstanceFieldOrProperty); if (viableMembers.Length == 0) { - var noParamConstructor = containingType.InstanceConstructors.FirstOrDefault(c => c.Parameters.Length == 0); - if (noParamConstructor == null || - noParamConstructor.IsImplicitlyDeclared) - { - // Offer to just make the no-param-constructor directly. - var state = State.TryGenerate(this, document, textSpan, containingType, - ImmutableArray.Empty, cancellationToken); - - if (state != null) - { - context.RegisterRefactoring( - new FieldDelegatingCodeAction(this, document, state, addNullChecks: false)); - } - } - - // already had an explicit, no-param constructor. No need to offer anything. return; } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.AbstractCodeAction.cs b/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.AbstractCodeAction.cs index 22258ba1ee6e1..686e4126edaab 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.AbstractCodeAction.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.AbstractCodeAction.cs @@ -42,7 +42,7 @@ protected override async Task GetChangedDocumentAsync(CancellationToke { var result = await CodeGenerator.AddMemberDeclarationsAsync( _document.Project.Solution, - _state.ClassType, + _state.ClassOrStructType, _constructors.Select(CreateConstructorDefinition), cancellationToken: cancellationToken).ConfigureAwait(false); @@ -61,7 +61,7 @@ private IMethodSymbol CreateConstructorDefinition( attributes: default(ImmutableArray), accessibility: constructor.DeclaredAccessibility, modifiers: new DeclarationModifiers(), - typeName: _state.ClassType.Name, + typeName: _state.ClassOrStructType.Name, parameters: constructor.Parameters, statements: default(ImmutableArray), baseConstructorArguments: baseConstructorArguments); diff --git a/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeAction.cs b/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeAction.cs index 9a3eccbb10fe7..8823a08e9f301 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeAction.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeAction.cs @@ -23,7 +23,7 @@ private static string GetDisplayText(State state, IMethodSymbol constructor) var parameterString = string.Join(", ", parameters); return string.Format(FeaturesResources.Generate_constructor_0_1 + ".", - state.ClassType.Name, parameterString); + state.ClassOrStructType.Name, parameterString); } } } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeActionAll.cs b/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeActionAll.cs index 1eff171a88bf7..92fb8370e5882 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeActionAll.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeActionAll.cs @@ -1,8 +1,6 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; -using System.Linq; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.GenerateMember.GenerateDefaultConstructors { @@ -15,16 +13,9 @@ public CodeActionAll( Document document, State state, IList constructors) - : base(service, document, state, GetConstructors(state, constructors), FeaturesResources.Generate_all) + : base(service, document, state, constructors, FeaturesResources.Generate_all) { } - - private static IList GetConstructors(State state, IList constructors) - { - return state.UnimplementedDefaultConstructor != null - ? new[] { state.UnimplementedDefaultConstructor }.Concat(constructors).ToList() - : constructors; - } } } -} +} \ No newline at end of file diff --git a/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs b/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs index c3646cb027020..060d71848857a 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using System.Threading; using Microsoft.CodeAnalysis; @@ -15,12 +17,9 @@ internal abstract partial class AbstractGenerateDefaultConstructorsService UnimplementedConstructors { get; private set; } - public IMethodSymbol UnimplementedDefaultConstructor { get; private set; } - - public SyntaxNode BaseTypeNode { get; private set; } + public ImmutableArray UnimplementedConstructors { get; private set; } private State() { @@ -47,56 +46,55 @@ private bool TryInitialize( TextSpan textSpan, CancellationToken cancellationToken) { - if (!service.TryInitializeState(document, textSpan, cancellationToken, out var baseTypeNode, out var classType)) - { - return false; - } - - if (!baseTypeNode.Span.IntersectsWith(textSpan.Start)) + if (!service.TryInitializeState(document, textSpan, cancellationToken, + out var classOrStructType)) { return false; } - this.BaseTypeNode = baseTypeNode; - this.ClassType = classType; - - var baseType = this.ClassType.BaseType; + this.ClassOrStructType = classOrStructType; - if (this.ClassType.TypeKind != TypeKind.Class || - this.ClassType.IsStatic || + var baseType = this.ClassOrStructType.BaseType; + if (this.ClassOrStructType.IsStatic || baseType == null || - baseType.SpecialType == SpecialType.System_Object || baseType.TypeKind == TypeKind.Error) { return false; } var semanticFacts = document.Project.LanguageServices.GetService(); - var classConstructors = this.ClassType.InstanceConstructors; - var baseTypeConstructors = - baseType.InstanceConstructors - .Where(c => c.IsAccessibleWithin(this.ClassType)); + var classConstructors = this.ClassOrStructType.InstanceConstructors; - var destinationProvider = document.Project.Solution.Workspace.Services.GetLanguageServices(this.ClassType.Language); + var destinationProvider = document.Project.Solution.Workspace.Services.GetLanguageServices(this.ClassOrStructType.Language); var syntaxFacts = destinationProvider.GetService(); + var isCaseSensitive = syntaxFacts.IsCaseSensitive; - var missingConstructors = - baseTypeConstructors.Where(c1 => !classConstructors.Any( - c2 => SignatureComparer.Instance.HaveSameSignature(c1.Parameters, c2.Parameters, compareParameterName: true, isCaseSensitive: syntaxFacts.IsCaseSensitive))).ToList(); + this.UnimplementedConstructors = + baseType.InstanceConstructors + .WhereAsArray(c => c.IsAccessibleWithin(this.ClassOrStructType) && + IsMissing(c, classConstructors, isCaseSensitive)); - this.UnimplementedConstructors = missingConstructors; + return this.UnimplementedConstructors.Length > 0; + } + + private bool IsMissing( + IMethodSymbol constructor, + ImmutableArray classConstructors, + bool isCaseSensitive) + { + var matchingConstructor = classConstructors.FirstOrDefault( + c => SignatureComparer.Instance.HaveSameSignature( + constructor.Parameters, c.Parameters, compareParameterName: true, isCaseSensitive: isCaseSensitive)); - this.UnimplementedDefaultConstructor = baseTypeConstructors.FirstOrDefault(c => c.Parameters.Length == 0); - if (this.UnimplementedDefaultConstructor != null) + if (matchingConstructor == null) { - if (classConstructors.Any(c => c.Parameters.Length == 0 && !c.IsImplicitlyDeclared)) - { - this.UnimplementedDefaultConstructor = null; - } + return true; } - return this.UnimplementedConstructors.Count > 0; + // We have a matching constructor in this type. But we'll still offer to create the + // constructor if the constructor that we have is implicit. + return matchingConstructor.IsImplicitlyDeclared; } } } -} +} \ No newline at end of file diff --git a/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.cs b/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.cs index 7966162f8d76f..80e2bb133f9d4 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.cs @@ -1,6 +1,5 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System.Collections.Generic; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; @@ -17,7 +16,7 @@ protected AbstractGenerateDefaultConstructorsService() { } - protected abstract bool TryInitializeState(SemanticDocument document, TextSpan textSpan, CancellationToken cancellationToken, out SyntaxNode baseTypeNode, out INamedTypeSymbol classType); + protected abstract bool TryInitializeState(SemanticDocument document, TextSpan textSpan, CancellationToken cancellationToken, out INamedTypeSymbol classOrStructType); public async Task> GenerateDefaultConstructorsAsync( Document document, @@ -28,30 +27,26 @@ public async Task> GenerateDefaultConstructorsAsync( { var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); + var result = ArrayBuilder.GetInstance(); if (textSpan.IsEmpty) { var state = State.Generate((TService)this, semanticDocument, textSpan, cancellationToken); if (state != null) { - return GetActions(document, state).AsImmutableOrNull(); + foreach (var constructor in state.UnimplementedConstructors) + { + result.Add(new GenerateDefaultConstructorCodeAction((TService)this, document, state, constructor)); + } + + if (state.UnimplementedConstructors.Length > 1) + { + result.Add(new CodeActionAll((TService)this, document, state, state.UnimplementedConstructors)); + } } } - return default(ImmutableArray); - } - } - - private IEnumerable GetActions(Document document, State state) - { - foreach (var constructor in state.UnimplementedConstructors) - { - yield return new GenerateDefaultConstructorCodeAction((TService)this, document, state, constructor); - } - - if (state.UnimplementedConstructors.Count > 1) - { - yield return new CodeActionAll((TService)this, document, state, state.UnimplementedConstructors); + return result.ToImmutableAndFree(); } } } -} +} \ No newline at end of file diff --git a/src/Features/VisualBasic/Portable/GenerateMember/GenerateDefaultConstructors/VisualBasicGenerateDefaultConstructorsService.vb b/src/Features/VisualBasic/Portable/GenerateMember/GenerateDefaultConstructors/VisualBasicGenerateDefaultConstructorsService.vb index 531cb88965a9e..e23bb0386e8e9 100644 --- a/src/Features/VisualBasic/Portable/GenerateMember/GenerateDefaultConstructors/VisualBasicGenerateDefaultConstructorsService.vb +++ b/src/Features/VisualBasic/Portable/GenerateMember/GenerateDefaultConstructors/VisualBasicGenerateDefaultConstructorsService.vb @@ -2,8 +2,10 @@ Imports System.Composition Imports System.Threading +Imports Microsoft.CodeAnalysis.GenerateFromMembers Imports Microsoft.CodeAnalysis.GenerateMember.GenerateDefaultConstructors Imports Microsoft.CodeAnalysis.Host.Mef +Imports Microsoft.CodeAnalysis.LanguageServices Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -14,28 +16,36 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateMember.GenerateDefaultConst Protected Overrides Function TryInitializeState( document As SemanticDocument, textSpan As TextSpan, cancellationToken As CancellationToken, - ByRef baseTypeNode As SyntaxNode, ByRef classType As INamedTypeSymbol) As Boolean - If cancellationToken.IsCancellationRequested Then - Return False + ByRef classOrStructType As INamedTypeSymbol) As Boolean + cancellationToken.ThrowIfCancellationRequested() + + ' Offer the feature if we're on the header for the class/struct, or if we're on the + ' first base-type of a class. + + Dim syntaxFacts = document.Document.GetLanguageService(Of ISyntaxFactsService)() + If syntaxFacts.IsOnTypeHeader(document.Root, textSpan.Start) Then + classOrStructType = AbstractGenerateFromMembersCodeRefactoringProvider.GetEnclosingNamedType( + document.SemanticModel, document.Root, textSpan.Start, cancellationToken) + Return classOrStructType IsNot Nothing End If - Dim token = DirectCast(document.Root, SyntaxNode).FindToken(textSpan.Start) + Dim token = document.Root.FindToken(textSpan.Start) Dim type = token.GetAncestor(Of TypeSyntax)() If type IsNot Nothing AndAlso type.IsParentKind(SyntaxKind.InheritsStatement) Then Dim baseList = DirectCast(type.Parent, InheritsStatementSyntax) + If baseList.Types.Count > 0 AndAlso baseList.Types(0) Is type AndAlso baseList.IsParentKind(SyntaxKind.ClassBlock) Then - classType = TryCast(document.SemanticModel.GetDeclaredSymbol(baseList.Parent, cancellationToken), INamedTypeSymbol) - baseTypeNode = type - Return classType IsNot Nothing + + classOrStructType = TryCast(document.SemanticModel.GetDeclaredSymbol(baseList.Parent, cancellationToken), INamedTypeSymbol) + Return classOrStructType IsNot Nothing End If End If - baseTypeNode = Nothing - classType = Nothing + classOrStructType = Nothing Return False End Function End Class -End Namespace +End Namespace \ No newline at end of file From c81dfd31b343b5224b894c972ce1773a97d5d9a6 Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Sat, 13 May 2017 15:19:48 -0700 Subject: [PATCH 03/14] Remove unneeded code. --- .../BasicEditorServicesTest.vbproj | 4 +- .../GenerateConstructorTests.vb | 3 +- .../GenerateDefaultConstructorsTests.vb | 3 +- .../CSharpGenerateConstructorService.cs | 42 +------------------ ...bstractGenerateConstructorService.State.cs | 26 ------------ .../AbstractGenerateConstructorService.cs | 2 - .../VisualBasicGenerateConstructorService.vb | 27 ------------ 7 files changed, 8 insertions(+), 99 deletions(-) rename src/EditorFeatures/VisualBasicTest/{Diagnostics => }/GenerateConstructor/GenerateConstructorTests.vb (99%) rename src/EditorFeatures/VisualBasicTest/{CodeActions => }/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.vb (98%) diff --git a/src/EditorFeatures/VisualBasicTest/BasicEditorServicesTest.vbproj b/src/EditorFeatures/VisualBasicTest/BasicEditorServicesTest.vbproj index 5960dd18eb7f3..00b590be83690 100644 --- a/src/EditorFeatures/VisualBasicTest/BasicEditorServicesTest.vbproj +++ b/src/EditorFeatures/VisualBasicTest/BasicEditorServicesTest.vbproj @@ -227,7 +227,7 @@ - + @@ -276,7 +276,7 @@ - + diff --git a/src/EditorFeatures/VisualBasicTest/Diagnostics/GenerateConstructor/GenerateConstructorTests.vb b/src/EditorFeatures/VisualBasicTest/GenerateConstructor/GenerateConstructorTests.vb similarity index 99% rename from src/EditorFeatures/VisualBasicTest/Diagnostics/GenerateConstructor/GenerateConstructorTests.vb rename to src/EditorFeatures/VisualBasicTest/GenerateConstructor/GenerateConstructorTests.vb index aacc36e69565d..3fe508606bfd9 100644 --- a/src/EditorFeatures/VisualBasicTest/Diagnostics/GenerateConstructor/GenerateConstructorTests.vb +++ b/src/EditorFeatures/VisualBasicTest/GenerateConstructor/GenerateConstructorTests.vb @@ -2,10 +2,11 @@ Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.Diagnostics +Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics Imports Microsoft.CodeAnalysis.VisualBasic.Diagnostics Imports Microsoft.CodeAnalysis.VisualBasic.GenerateConstructor -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics.GenerateConstructor +Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.GenerateConstructor Public Class GenerateConstructorTests Inherits AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest diff --git a/src/EditorFeatures/VisualBasicTest/CodeActions/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.vb b/src/EditorFeatures/VisualBasicTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.vb similarity index 98% rename from src/EditorFeatures/VisualBasicTest/CodeActions/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.vb rename to src/EditorFeatures/VisualBasicTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.vb index 831a6f8f698cc..821541d2e2749 100644 --- a/src/EditorFeatures/VisualBasicTest/CodeActions/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.vb +++ b/src/EditorFeatures/VisualBasicTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.vb @@ -2,8 +2,9 @@ Imports Microsoft.CodeAnalysis.CodeRefactorings Imports Microsoft.CodeAnalysis.CodeRefactorings.GenerateDefaultConstructors +Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeRefactorings -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeRefactorings.GenerateDefaultConstructors +Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.GenerateDefaultConstructors Public Class GenerateDefaultConstructorsTests Inherits AbstractVisualBasicCodeActionTest diff --git a/src/Features/CSharp/Portable/GenerateConstructor/CSharpGenerateConstructorService.cs b/src/Features/CSharp/Portable/GenerateConstructor/CSharpGenerateConstructorService.cs index 93679a43412f1..4943a66b121d9 100644 --- a/src/Features/CSharp/Portable/GenerateConstructor/CSharpGenerateConstructorService.cs +++ b/src/Features/CSharp/Portable/GenerateConstructor/CSharpGenerateConstructorService.cs @@ -21,19 +21,10 @@ internal class CSharpGenerateConstructorService : AbstractGenerateConstructorSer private static readonly SyntaxAnnotation s_annotation = new SyntaxAnnotation(); protected override bool IsSimpleNameGeneration(SemanticDocument document, SyntaxNode node, CancellationToken cancellationToken) - { - return node is SimpleNameSyntax; - } + => node is SimpleNameSyntax; protected override bool IsConstructorInitializerGeneration(SemanticDocument document, SyntaxNode node, CancellationToken cancellationToken) - { - return node is ConstructorInitializerSyntax; - } - - protected override bool IsClassDeclarationGeneration(SemanticDocument document, SyntaxNode node, CancellationToken cancellationToken) - { - return node is ClassDeclarationSyntax; - } + => node is ConstructorInitializerSyntax; protected override bool TryInitializeConstructorInitializerGeneration( SemanticDocument document, SyntaxNode node, CancellationToken cancellationToken, @@ -60,35 +51,6 @@ protected override bool TryInitializeConstructorInitializerGeneration( return false; } - protected override bool TryInitializeClassDeclarationGenerationState( - SemanticDocument document, - SyntaxNode node, - CancellationToken cancellationToken, - out SyntaxToken token, - out IMethodSymbol delegatedConstructor, - out INamedTypeSymbol typeToGenerateIn) - { - token = default(SyntaxToken); - typeToGenerateIn = null; - delegatedConstructor = null; - - var semanticModel = document.SemanticModel; - var classDeclaration = (ClassDeclarationSyntax)node; - var classSymbol = semanticModel.GetDeclaredSymbol(classDeclaration, cancellationToken); - - var baseType = classSymbol.BaseType; - var constructor = baseType.Constructors.FirstOrDefault(c => IsSymbolAccessible(c, document)); - if (constructor == null) - { - return false; - } - - typeToGenerateIn = classSymbol; - delegatedConstructor = constructor; - token = classDeclaration.Identifier; - return true; - } - protected override bool TryInitializeSimpleNameGenerationState( SemanticDocument document, SyntaxNode node, diff --git a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.State.cs b/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.State.cs index cc33c4c0cc849..adcd89487a43c 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.State.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.State.cs @@ -74,13 +74,6 @@ private async Task TryInitializeAsync( return false; } } - else if (service.IsClassDeclarationGeneration(document, node, cancellationToken)) - { - if (!await TryInitializeClassDeclarationGenerationAsync(service, document, node, cancellationToken).ConfigureAwait(false)) - { - return false; - } - } else { return false; @@ -196,25 +189,6 @@ private async Task TryInitializeConstructorInitializerGenerationAsync( return await TryDetermineTypeToGenerateInAsync(document, typeToGenerateIn, cancellationToken).ConfigureAwait(false); } - private async Task TryInitializeClassDeclarationGenerationAsync( - TService service, - SemanticDocument document, - SyntaxNode simpleName, - CancellationToken cancellationToken) - { - if (service.TryInitializeClassDeclarationGenerationState(document, simpleName, cancellationToken, - out var token, out var constructor, out var typeToGenerateIn)) - { - this.Token = token; - this.DelegatedConstructorOpt = constructor; - this.ParameterTypes = constructor.Parameters.Select(p => p.Type).ToImmutableArray(); - this.ParameterRefKinds = constructor.Parameters.Select(p => p.RefKind).ToList(); - } - cancellationToken.ThrowIfCancellationRequested(); - - return await TryDetermineTypeToGenerateInAsync(document, typeToGenerateIn, cancellationToken).ConfigureAwait(false); - } - private async Task TryInitializeSimpleNameGenerationAsync( TService service, SemanticDocument document, diff --git a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.cs b/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.cs index 7fc0642d8f9e1..b5faddef6ff11 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.cs @@ -23,11 +23,9 @@ protected AbstractGenerateConstructorService() } protected abstract bool IsSimpleNameGeneration(SemanticDocument document, SyntaxNode node, CancellationToken cancellationToken); - protected abstract bool IsClassDeclarationGeneration(SemanticDocument document, SyntaxNode node, CancellationToken cancellationToken); protected abstract bool IsConstructorInitializerGeneration(SemanticDocument document, SyntaxNode node, CancellationToken cancellationToken); protected abstract bool TryInitializeSimpleNameGenerationState(SemanticDocument document, SyntaxNode simpleName, CancellationToken cancellationToken, out SyntaxToken token, out ImmutableArray arguments, out INamedTypeSymbol typeToGenerateIn); - protected abstract bool TryInitializeClassDeclarationGenerationState(SemanticDocument document, SyntaxNode classDeclaration, CancellationToken cancellationToken, out SyntaxToken token, out IMethodSymbol constructor, out INamedTypeSymbol typeToGenerateIn); protected abstract bool TryInitializeConstructorInitializerGeneration(SemanticDocument document, SyntaxNode constructorInitializer, CancellationToken cancellationToken, out SyntaxToken token, out ImmutableArray arguments, out INamedTypeSymbol typeToGenerateIn); protected abstract bool TryInitializeSimpleAttributeNameGenerationState(SemanticDocument document, SyntaxNode simpleName, CancellationToken cancellationToken, out SyntaxToken token, out ImmutableArray arguments, out ImmutableArray attributeArguments, out INamedTypeSymbol typeToGenerateIn); protected abstract ImmutableArray GenerateParameterNames(SemanticModel semanticModel, IEnumerable arguments, IList reservedNames, CancellationToken cancellationToken); diff --git a/src/Features/VisualBasic/Portable/GenerateConstructor/VisualBasicGenerateConstructorService.vb b/src/Features/VisualBasic/Portable/GenerateConstructor/VisualBasicGenerateConstructorService.vb index d38bade0703ae..87a6ecf3cf1da 100644 --- a/src/Features/VisualBasic/Portable/GenerateConstructor/VisualBasicGenerateConstructorService.vb +++ b/src/Features/VisualBasic/Portable/GenerateConstructor/VisualBasicGenerateConstructorService.vb @@ -154,33 +154,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateConstructor Return compilation.ClassifyConversion(sourceType, targetType).IsWidening End Function - Protected Overrides Function IsClassDeclarationGeneration(document As SemanticDocument, - node As SyntaxNode, - cancellationToken As CancellationToken) As Boolean - Return TypeOf node Is ClassBlockSyntax - End Function - - Protected Overrides Function TryInitializeClassDeclarationGenerationState( - document As SemanticDocument, - classDeclaration As SyntaxNode, - cancellationToken As CancellationToken, - ByRef token As SyntaxToken, - ByRef delegatedConstructor As IMethodSymbol, - ByRef typeToGenerateIn As INamedTypeSymbol) As Boolean - Dim semanticModel = document.SemanticModel - Dim classBlock = DirectCast(classDeclaration, ClassBlockSyntax) - Dim classSymbol = semanticModel.GetDeclaredSymbol(classBlock.BlockStatement, cancellationToken) - Dim constructor = classSymbol?.BaseType?.Constructors.FirstOrDefault(Function(c) IsSymbolAccessible(c, document)) - If constructor Is Nothing Then - Return False - End If - - typeToGenerateIn = classSymbol - delegatedConstructor = constructor - token = classBlock.BlockStatement.Identifier - Return True - End Function - Private Shared ReadOnly s_annotation As SyntaxAnnotation = New SyntaxAnnotation Friend Overrides Function GetDelegatingConstructor(state As State, From 5865073828113c6dc96c73fc8eef421cc1f3373d Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Sat, 13 May 2017 15:21:11 -0700 Subject: [PATCH 04/14] Don't add punctuation in code. --- .../AbstractGenerateDefaultConstructorsService.CodeAction.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeAction.cs b/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeAction.cs index 8823a08e9f301..abc382700e647 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeAction.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeAction.cs @@ -22,9 +22,9 @@ private static string GetDisplayText(State state, IMethodSymbol constructor) var parameters = constructor.Parameters.Select(p => p.Name); var parameterString = string.Join(", ", parameters); - return string.Format(FeaturesResources.Generate_constructor_0_1 + ".", + return string.Format(FeaturesResources.Generate_constructor_0_1, state.ClassOrStructType.Name, parameterString); } } } -} +} \ No newline at end of file From a315a6494ea7c134a705cd4c0db8821e48b0ddbf Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Sat, 13 May 2017 15:34:18 -0700 Subject: [PATCH 05/14] Fixup VB tests. --- .../GenerateConstructorTests.vb | 92 ---------- .../GenerateDefaultConstructorsTests.vb | 159 ++++++++++++++++-- 2 files changed, 146 insertions(+), 105 deletions(-) diff --git a/src/EditorFeatures/VisualBasicTest/GenerateConstructor/GenerateConstructorTests.vb b/src/EditorFeatures/VisualBasicTest/GenerateConstructor/GenerateConstructorTests.vb index 3fe508606bfd9..65940a349c416 100644 --- a/src/EditorFeatures/VisualBasicTest/GenerateConstructor/GenerateConstructorTests.vb +++ b/src/EditorFeatures/VisualBasicTest/GenerateConstructor/GenerateConstructorTests.vb @@ -1529,98 +1529,6 @@ End Class") End Function End Class - - - Public Async Function TestGenerateInDerivedType1() As Task - Await TestInRegularAndScriptAsync( -" -Public Class Base - Public Sub New(a As String) - - End Sub -End Class - -Public Class [||]Derived - Inherits Base - -End Class", -" -Public Class Base - Public Sub New(a As String) - - End Sub -End Class - -Public Class Derived - Inherits Base - - Public Sub New(a As String) - MyBase.New(a) - End Sub -End Class") - End Function - - - - Public Async Function TestGenerateInDerivedType2() As Task - Await TestInRegularAndScriptAsync( -" -Public Class Base - Public Sub New(a As Integer, Optional b As String = Nothing) - - End Sub -End Class - -Public Class [||]Derived - Inherits Base - -End Class", -" -Public Class Base - Public Sub New(a As Integer, Optional b As String = Nothing) - - End Sub -End Class - -Public Class Derived - Inherits Base - - Public Sub New(a As Integer, Optional b As String = Nothing) - MyBase.New(a, b) - End Sub -End Class") - End Function - - - Public Async Function TestGenerateInDerivedType_InvalidClassStatement() As Task - Await TestInRegularAndScriptAsync( -" -Public Class Base - Public Sub New(a As Integer, Optional b As String = Nothing) - - End Sub -End Class - -Public Class [|;;|]Derived - Inherits Base - -End Class", -" -Public Class Base - Public Sub New(a As Integer, Optional b As String = Nothing) - - End Sub -End Class - -Public Class ;;Derived - Inherits Base - - Public Sub New(a As Integer, Optional b As String = Nothing) - MyBase.New(a, b) - End Sub -End Class") - End Function - Public Async Function TestGenerateConstructorNotOfferedForDuplicate() As Task Await TestMissingInRegularAndScriptAsync( diff --git a/src/EditorFeatures/VisualBasicTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.vb b/src/EditorFeatures/VisualBasicTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.vb index 821541d2e2749..d121ff837c8c2 100644 --- a/src/EditorFeatures/VisualBasicTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.vb +++ b/src/EditorFeatures/VisualBasicTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.vb @@ -28,8 +28,7 @@ Imports System.Collections.Generic Imports System.Linq Class Program Inherits Exception - Public Sub New(message As String) - MyBase.New(message) + Public Sub New() End Sub Sub Main(args As String()) End Sub @@ -52,8 +51,8 @@ Imports System.Collections.Generic Imports System.Linq Class Program Inherits Exception - Public Sub New(message As String, innerException As Exception) - MyBase.New(message, innerException) + Public Sub New(message As String) + MyBase.New(message) End Sub Sub Main(args As String()) End Sub @@ -75,20 +74,50 @@ End Class", "Imports System Imports System.Collections.Generic Imports System.Linq + +Class Program + Inherits Exception + + Public Sub New(message As String, innerException As Exception) + MyBase.New(message, innerException) + End Sub + + Sub Main(args As String()) + End Sub +End Class", +index:=2) + End Function + + + Public Async Function TestException3() As Task + Await TestInRegularAndScriptAsync( +"Imports System +Imports System.Collections.Generic +Imports System.Linq +Class Program + Inherits [||]Exception + Sub Main(args As String()) + End Sub +End Class", +"Imports System +Imports System.Collections.Generic +Imports System.Linq Imports System.Runtime.Serialization Class Program Inherits Exception + Protected Sub New(info As SerializationInfo, context As StreamingContext) MyBase.New(info, context) End Sub + Sub Main(args As String()) End Sub End Class", -index:=2) +index:=3) End Function - Public Async Function TestException3() As Task + Public Async Function TestException4() As Task Await TestInRegularAndScriptAsync( "Imports System Imports System.Collections.Generic @@ -102,33 +131,47 @@ End Class", Imports System.Collections.Generic Imports System.Linq Imports System.Runtime.Serialization + Class Program Inherits Exception + Public Sub New() End Sub + Public Sub New(message As String) MyBase.New(message) End Sub + Public Sub New(message As String, innerException As Exception) MyBase.New(message, innerException) End Sub + Protected Sub New(info As SerializationInfo, context As StreamingContext) MyBase.New(info, context) End Sub + Sub Main(args As String()) End Sub End Class", -index:=3) +index:=4) End Function Public Async Function TestNotOfferedOnResolvedBaseClassName() As Task - Await TestMissingInRegularAndScriptAsync( + Await TestInRegularAndScript1Async( "Class Base End Class Class Derived Inherits B[||]ase +End Class", +"Class Base +End Class +Class Derived + Inherits Base + + Public Sub New() + End Sub End Class") End Function @@ -253,8 +296,7 @@ Imports System.Collections.Generic Imports System.Linq Class Program Inherits Exception - Public Sub New() - End Sub + Public Sub New() End Sub Public Sub New(message As String) @@ -289,8 +331,7 @@ Imports System.Collections.Generic Imports System.Linq Class Program Inherits Exception - Public Sub New(message As String) - MyBase.New(message) + Public Sub New() End Sub Sub Main(args As String()) End Sub @@ -485,5 +526,97 @@ End Class index:=2, ignoreTrivia:=False) End Function + + + Public Async Function TestGenerateInDerivedType_InvalidClassStatement() As Task + Await TestInRegularAndScriptAsync( +" +Public Class Base + Public Sub New(a As Integer, Optional b As String = Nothing) + + End Sub +End Class + +Public [||]Class ;;Derived + Inherits Base + +End Class", +" +Public Class Base + Public Sub New(a As Integer, Optional b As String = Nothing) + + End Sub +End Class + +Public Class ;;Derived + Inherits Base + + Public Sub New(a As Integer, Optional b As String = Nothing) + MyBase.New(a, b) + End Sub +End Class") + End Function + + + + Public Async Function TestGenerateInDerivedType1() As Task + Await TestInRegularAndScriptAsync( +" +Public Class Base + Public Sub New(a As String) + + End Sub +End Class + +Public Class [||]Derived + Inherits Base + +End Class", +" +Public Class Base + Public Sub New(a As String) + + End Sub +End Class + +Public Class Derived + Inherits Base + + Public Sub New(a As String) + MyBase.New(a) + End Sub +End Class") + End Function + + + + Public Async Function TestGenerateInDerivedType2() As Task + Await TestInRegularAndScriptAsync( +" +Public Class Base + Public Sub New(a As Integer, Optional b As String = Nothing) + + End Sub +End Class + +Public Class [||]Derived + Inherits Base + +End Class", +" +Public Class Base + Public Sub New(a As Integer, Optional b As String = Nothing) + + End Sub +End Class + +Public Class Derived + Inherits Base + + Public Sub New(a As Integer, Optional b As String = Nothing) + MyBase.New(a, b) + End Sub +End Class") + End Function End Class -End Namespace +End Namespace \ No newline at end of file From 82373c8fb5f8f72c1e717277a8f7669abcec3496 Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Sat, 13 May 2017 15:35:39 -0700 Subject: [PATCH 06/14] Move type. --- src/Features/Core/Portable/Features.csproj | 2 +- .../GenerateDefaultConstructorsCodeRefactoringProvider.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/Features/Core/Portable/{CodeRefactorings => }/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs (95%) diff --git a/src/Features/Core/Portable/Features.csproj b/src/Features/Core/Portable/Features.csproj index cff5327a8c52d..f0392415bc4d6 100644 --- a/src/Features/Core/Portable/Features.csproj +++ b/src/Features/Core/Portable/Features.csproj @@ -323,7 +323,7 @@ - + diff --git a/src/Features/Core/Portable/CodeRefactorings/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs similarity index 95% rename from src/Features/Core/Portable/CodeRefactorings/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs rename to src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs index 25ad0e52fa5a7..7af17362cb3ff 100644 --- a/src/Features/Core/Portable/CodeRefactorings/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs @@ -5,7 +5,7 @@ using Microsoft.CodeAnalysis.GenerateMember.GenerateDefaultConstructors; using Microsoft.CodeAnalysis.Shared.Extensions; -namespace Microsoft.CodeAnalysis.CodeRefactorings.GenerateDefaultConstructors +namespace Microsoft.CodeAnalysis.GenerateDefaultConstructors { [ExportCodeRefactoringProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = PredefinedCodeRefactoringProviderNames.GenerateDefaultConstructors), Shared] From 62705b3f98febe6ea6a7cb0ad17b7ad011d8901f Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Sat, 13 May 2017 15:37:37 -0700 Subject: [PATCH 07/14] Fixup test code. --- .../GenerateDefaultConstructorsTests.vb | 2 +- .../GenerateDefaultConstructorsCodeRefactoringProvider.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/EditorFeatures/VisualBasicTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.vb b/src/EditorFeatures/VisualBasicTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.vb index d121ff837c8c2..c663f0743d3d4 100644 --- a/src/EditorFeatures/VisualBasicTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.vb +++ b/src/EditorFeatures/VisualBasicTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.vb @@ -1,8 +1,8 @@ ' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. Imports Microsoft.CodeAnalysis.CodeRefactorings -Imports Microsoft.CodeAnalysis.CodeRefactorings.GenerateDefaultConstructors Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeRefactorings +Imports Microsoft.CodeAnalysis.GenerateDefaultConstructors Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.GenerateDefaultConstructors Public Class GenerateDefaultConstructorsTests diff --git a/src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs index 7af17362cb3ff..50efc3e4fdbba 100644 --- a/src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs @@ -2,6 +2,7 @@ using System.Composition; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.GenerateMember.GenerateDefaultConstructors; using Microsoft.CodeAnalysis.Shared.Extensions; From fac36fe8af6524532478f8c5bc72ca77a6403614 Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Sat, 13 May 2017 15:39:16 -0700 Subject: [PATCH 08/14] Fixup C# test code. --- .../CSharpTest/CSharpEditorServicesTest.csproj | 2 +- .../GenerateDefaultConstructorsTests.cs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) rename src/EditorFeatures/CSharpTest/{CodeActions => }/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.cs (98%) diff --git a/src/EditorFeatures/CSharpTest/CSharpEditorServicesTest.csproj b/src/EditorFeatures/CSharpTest/CSharpEditorServicesTest.csproj index 24d00d4664012..fe91a8949ad67 100644 --- a/src/EditorFeatures/CSharpTest/CSharpEditorServicesTest.csproj +++ b/src/EditorFeatures/CSharpTest/CSharpEditorServicesTest.csproj @@ -246,7 +246,7 @@ - + diff --git a/src/EditorFeatures/CSharpTest/CodeActions/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.cs b/src/EditorFeatures/CSharpTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.cs similarity index 98% rename from src/EditorFeatures/CSharpTest/CodeActions/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.cs rename to src/EditorFeatures/CSharpTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.cs index ee5148980a810..498bd8e05fc14 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.cs +++ b/src/EditorFeatures/CSharpTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.cs @@ -2,11 +2,12 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.CodeRefactorings.GenerateDefaultConstructors; +using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings; +using Microsoft.CodeAnalysis.GenerateDefaultConstructors; using Roslyn.Test.Utilities; using Xunit; -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings.GenerateDefaultConstructors +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.GenerateDefaultConstructors { public class GenerateDefaultConstructorsTests : AbstractCSharpCodeActionTest { From c46b37e254495e07030d47f2725365ddff40017e Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Sat, 13 May 2017 15:52:46 -0700 Subject: [PATCH 09/14] Fixup C# tests. --- .../GenerateConstructorTests.cs | 60 ----------------- .../GenerateDefaultConstructorsTests.cs | 66 +++++++++++++++++-- 2 files changed, 61 insertions(+), 65 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/GenerateConstructor/GenerateConstructorTests.cs b/src/EditorFeatures/CSharpTest/GenerateConstructor/GenerateConstructorTests.cs index 3a7fb7ee22d11..93f140796a68f 100644 --- a/src/EditorFeatures/CSharpTest/GenerateConstructor/GenerateConstructorTests.cs +++ b/src/EditorFeatures/CSharpTest/GenerateConstructor/GenerateConstructorTests.cs @@ -2316,66 +2316,6 @@ public Base(bool val = false) }"); } - [WorkItem(6541, "https://github.com/dotnet/Roslyn/issues/6541")] - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)] - public async Task TestGenerateFromDerivedClass() - { - await TestInRegularAndScriptAsync( -@"class Base -{ - public Base(string value) - { - } -} - -class [||]Derived : Base -{ -}", -@"class Base -{ - public Base(string value) - { - } -} - -class Derived : Base -{ - public Derived(string value) : base(value) - { - } -}"); - } - - [WorkItem(6541, "https://github.com/dotnet/Roslyn/issues/6541")] - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)] - public async Task TestGenerateFromDerivedClass2() - { - await TestInRegularAndScriptAsync( -@"class Base -{ - public Base(int a, string value = null) - { - } -} - -class [||]Derived : Base -{ -}", -@"class Base -{ - public Base(int a, string value = null) - { - } -} - -class Derived : Base -{ - public Derived(int a, string value = null) : base(a, value) - { - } -}"); - } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)] public async Task TestGenerateWithIncorrectConstructorArguments_Crash() { diff --git a/src/EditorFeatures/CSharpTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.cs b/src/EditorFeatures/CSharpTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.cs index 498bd8e05fc14..a3b96fdbd1115 100644 --- a/src/EditorFeatures/CSharpTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.cs +++ b/src/EditorFeatures/CSharpTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.cs @@ -591,7 +591,7 @@ protected Program(SerializationInfo info, StreamingContext context) : base(info, { } }", -index: 3, +index: 4, ignoreTrivia: false); } @@ -729,10 +729,6 @@ public Program() { } - public Program() - { - } - public Program(string message) : base(message) { } @@ -807,6 +803,66 @@ class B public B((int a, string b) x) { } +}"); + } + + [WorkItem(6541, "https://github.com/dotnet/Roslyn/issues/6541")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)] + public async Task TestGenerateFromDerivedClass() + { + await TestInRegularAndScriptAsync( +@"class Base +{ + public Base(string value) + { + } +} + +class [||]Derived : Base +{ +}", +@"class Base +{ + public Base(string value) + { + } +} + +class Derived : Base +{ + public Derived(string value) : base(value) + { + } +}"); + } + + [WorkItem(6541, "https://github.com/dotnet/Roslyn/issues/6541")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)] + public async Task TestGenerateFromDerivedClass2() + { + await TestInRegularAndScriptAsync( +@"class Base +{ + public Base(int a, string value = null) + { + } +} + +class [||]Derived : Base +{ +}", +@"class Base +{ + public Base(int a, string value = null) + { + } +} + +class Derived : Base +{ + public Derived(int a, string value = null) : base(a, value) + { + } }"); } } From 9e95f3c670da3a913c137a4e03aa962885608e5a Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Sun, 14 May 2017 01:07:42 -0700 Subject: [PATCH 10/14] Add comment --- ...eConstructorFromMembersCodeRefactoringProvider.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Features/Core/Portable/GenerateConstructorFromMembers/GenerateConstructorFromMembersCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateConstructorFromMembers/GenerateConstructorFromMembersCodeRefactoringProvider.cs index 17ef5f446f6fa..b8c8684b933d4 100644 --- a/src/Features/Core/Portable/GenerateConstructorFromMembers/GenerateConstructorFromMembersCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/GenerateConstructorFromMembers/GenerateConstructorFromMembersCodeRefactoringProvider.cs @@ -16,6 +16,18 @@ namespace Microsoft.CodeAnalysis.GenerateConstructorFromMembers { + /// + /// This is responsible for allowing a user to pick a + /// set of members from a class or struct, and then generate a constructor for that takes in + /// matching parameters and assigns them to those members. The members can be picked using + /// a actual selection in the editor, or they can be picked using a picker control that will + /// then display all the viable members and allow the user to pick which ones they want to + /// use. + /// + /// Importantly, this type is not responsible for generating constructors when the user types + /// something like "new MyType(x, y, z)", nor is it responsible for generating constructors + /// in a derived type that delegate to a base type. + /// [ExportCodeRefactoringProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = PredefinedCodeRefactoringProviderNames.GenerateConstructorFromMembers), Shared] [ExtensionOrder(Before = PredefinedCodeRefactoringProviderNames.GenerateEqualsAndGetHashCodeFromMembers)] From 23fa44446c18012e84a91dcf2c8007fb38e05faa Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Sun, 14 May 2017 01:10:35 -0700 Subject: [PATCH 11/14] Add comment --- ...erateDefaultConstructorsCodeRefactoringProvider.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs index 50efc3e4fdbba..7835bdeefefc9 100644 --- a/src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs @@ -8,6 +8,17 @@ namespace Microsoft.CodeAnalysis.GenerateDefaultConstructors { + /// + /// This gives users a way to generate constructors for + /// a derived type that delegate to a base type. For all accessibly constructors in the base + /// type, the user will be offered to create a constructor in the derived type with the same + /// signature if they don't already have one. This way, a user can override a type and easily + /// create all the forwarding constructors. + /// + /// Importantly, this type is not responsible for generating constructors when the user types + /// something like "new MyType(x, y, z)", nor is it responsible for generating constructors + /// for a type based on the fields/properties of that type. + /// [ExportCodeRefactoringProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = PredefinedCodeRefactoringProviderNames.GenerateDefaultConstructors), Shared] internal class GenerateDefaultConstructorsCodeRefactoringProvider : CodeRefactoringProvider From cddbd90f7ff9459420e422c9ad26699c88ccba3c Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Sun, 14 May 2017 01:14:40 -0700 Subject: [PATCH 12/14] Add comments --- .../GenerateConstructorCodeFixProvider.cs | 12 ++++++++++++ ...eConstructorFromMembersCodeRefactoringProvider.cs | 2 +- ...rateDefaultConstructorsCodeRefactoringProvider.cs | 3 ++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/Features/CSharp/Portable/GenerateConstructor/GenerateConstructorCodeFixProvider.cs b/src/Features/CSharp/Portable/GenerateConstructor/GenerateConstructorCodeFixProvider.cs index cb9c038cbe578..c626229ace175 100644 --- a/src/Features/CSharp/Portable/GenerateConstructor/GenerateConstructorCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/GenerateConstructor/GenerateConstructorCodeFixProvider.cs @@ -29,6 +29,18 @@ internal static class GenerateConstructorDiagnosticIds ImmutableArray.Create(CS1729); } + /// + /// This gives users a way to generate constructors for an existing + /// type when a user tries to 'new' up an instance of that type with a set of parameter that does + /// not match any existing constructor. i.e. it is the equivalent of 'Generate-Method' but for + /// constructors. Parameters for the constructor will be picked in a manner similar to Generate- + /// Method. However, this type will also attempt to hook up those parameters to existing fields + /// and properties, or pass them to a this/base constructor if available. + /// + /// Importantly, this type is not responsible for generating constructors for a type based on + /// the user selecting some fields/properties of that type. Nor is it responsible for generating + /// derived class constructors for all unmatched base class constructors in a type hierarchy. + /// [ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.GenerateConstructor), Shared] [ExtensionOrder(After = PredefinedCodeFixProviderNames.FullyQualify)] internal class GenerateConstructorCodeFixProvider : AbstractGenerateMemberCodeFixProvider diff --git a/src/Features/Core/Portable/GenerateConstructorFromMembers/GenerateConstructorFromMembersCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateConstructorFromMembers/GenerateConstructorFromMembersCodeRefactoringProvider.cs index b8c8684b933d4..3348e6112d558 100644 --- a/src/Features/Core/Portable/GenerateConstructorFromMembers/GenerateConstructorFromMembersCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/GenerateConstructorFromMembers/GenerateConstructorFromMembersCodeRefactoringProvider.cs @@ -26,7 +26,7 @@ namespace Microsoft.CodeAnalysis.GenerateConstructorFromMembers /// /// Importantly, this type is not responsible for generating constructors when the user types /// something like "new MyType(x, y, z)", nor is it responsible for generating constructors - /// in a derived type that delegate to a base type. + /// in a derived type that delegate to a base type. Both of those are handled by other services. /// [ExportCodeRefactoringProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = PredefinedCodeRefactoringProviderNames.GenerateConstructorFromMembers), Shared] diff --git a/src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs index 7835bdeefefc9..97da2bd720204 100644 --- a/src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs @@ -17,7 +17,8 @@ namespace Microsoft.CodeAnalysis.GenerateDefaultConstructors /// /// Importantly, this type is not responsible for generating constructors when the user types /// something like "new MyType(x, y, z)", nor is it responsible for generating constructors - /// for a type based on the fields/properties of that type. + /// for a type based on the fields/properties of that type. Both of those are handled by other + /// services. /// [ExportCodeRefactoringProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = PredefinedCodeRefactoringProviderNames.GenerateDefaultConstructors), Shared] From 9781c815ca88ce24d52591be328931a6247a3d76 Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Sun, 14 May 2017 01:24:17 -0700 Subject: [PATCH 13/14] Simplify code. --- .../AbstractGenerateDefaultConstructorsService.State.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs b/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs index 060d71848857a..e6528c08314b4 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs @@ -46,8 +46,7 @@ private bool TryInitialize( TextSpan textSpan, CancellationToken cancellationToken) { - if (!service.TryInitializeState(document, textSpan, cancellationToken, - out var classOrStructType)) + if (!service.TryInitializeState(document, textSpan, cancellationToken, out var classOrStructType)) { return false; } From 9437cf870fc43f7d2713dc3484daf363b4eaa3d2 Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Sun, 14 May 2017 01:24:33 -0700 Subject: [PATCH 14/14] Remove unused usings. --- .../AbstractGenerateDefaultConstructorsService.State.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs b/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs index e6528c08314b4..ca76eae576bd5 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs @@ -1,11 +1,8 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading; -using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities;