提交 421121ce 编写于 作者: C CyrusNajmabadi

Merge pull request #6659 from CyrusNajmabadi/generateConstructor

Offer 'generate constructor' when a derived type doesn't include a delegating constructor to it's base type
......@@ -420,7 +420,7 @@ public void TestReadonlyFieldDelegation()
@"class C { private readonly int x ; public C ( int x ) { this . x = x ; } void Test ( ) { int x = 10 ; C c = new C ( x ) ; } } ");
}
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateMethod)]
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)]
public void TestNoGenerationIntoEntirelyHiddenType()
{
TestMissing(
......@@ -441,7 +441,7 @@ class D
");
}
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateMethod)]
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)]
public void TestNestedConstructorCall()
{
Test(
......@@ -569,7 +569,7 @@ public void TestAttributesWithLambda()
}
[WorkItem(889349)]
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateMethod)]
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)]
public void TestConstructorGenerationForDifferentNamedParameter()
{
Test(
......@@ -611,7 +611,7 @@ public Program(int wde)
}
[WorkItem(528257)]
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateMethod)]
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)]
public void TestGenerateInInaccessibleType()
{
Test(
......@@ -628,7 +628,7 @@ public partial class GenerateConstructorTestsWithFindMissingIdentifiersAnalyzer
}
[WorkItem(1241, @"https://github.com/dotnet/roslyn/issues/1241")]
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateMethod)]
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)]
public void TestGenerateConstructorInIncompleteLambda()
{
Test(
......@@ -638,7 +638,7 @@ public void TestGenerateConstructorInIncompleteLambda()
}
[WorkItem(5274, "https://github.com/dotnet/roslyn/issues/5274")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateMethod)]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)]
public void TestGenerateIntoDerivedClassWithAbstractBase()
{
Test(
......@@ -691,6 +691,70 @@ public Base(bool val = false)
_val = val;
}
}
}");
}
[WorkItem(6541, "https://github.com/dotnet/Roslyn/issues/6541")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)]
public void TestGenerateFromDerivedClass()
{
Test(
@"
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 void TestGenerateFromDerivedClass2()
{
Test(
@"
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)
{
}
}");
}
}
......
......@@ -501,5 +501,66 @@ NewLines("Imports System.Linq \n Class C \n Private v As Integer \n Sub New() \n
End Sub
End Class
<WorkItem(6541, "https://github.com/dotnet/Roslyn/issues/6541")>
<WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)>
Public Sub TestGenerateInDerivedType1()
Test(
"
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 Sub
<WorkItem(6541, "https://github.com/dotnet/Roslyn/issues/6541")>
<WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)>
Public Sub TestGenerateInDerivedType2()
Test(
"
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 Sub
End Class
End Namespace
......@@ -36,9 +36,17 @@ protected override Task<IEnumerable<CodeAction>> GetCodeActionsAsync(Document do
return service.GenerateConstructorAsync(document, node, cancellationToken);
}
protected override bool IsCandidate(SyntaxNode node)
protected override bool IsCandidate(SyntaxNode node, Diagnostic diagnostic)
{
return node is SimpleNameSyntax || node is ObjectCreationExpressionSyntax || node is ConstructorInitializerSyntax || node is AttributeSyntax;
if (node is SimpleNameSyntax ||
node is ObjectCreationExpressionSyntax ||
node is ConstructorInitializerSyntax ||
node is AttributeSyntax)
{
return true;
}
return diagnostic.Id == CS7036 && node is ClassDeclarationSyntax;
}
protected override SyntaxNode GetTargetNode(SyntaxNode node)
......
......@@ -31,7 +31,7 @@ protected override Task<IEnumerable<CodeAction>> GetCodeActionsAsync(Document do
return service.GenerateEnumMemberAsync(document, node, cancellationToken);
}
protected override bool IsCandidate(SyntaxNode node)
protected override bool IsCandidate(SyntaxNode node, Diagnostic diagnostic)
{
return node is IdentifierNameSyntax;
}
......
......@@ -27,7 +27,7 @@ public override ImmutableArray<string> FixableDiagnosticIds
get { return ImmutableArray.Create(CS0029, CS0030); }
}
protected override bool IsCandidate(SyntaxNode node)
protected override bool IsCandidate(SyntaxNode node, Diagnostic diagnostic)
{
return node.IsKind(SyntaxKind.IdentifierName) ||
node.IsKind(SyntaxKind.MethodDeclaration) ||
......
......@@ -37,7 +37,7 @@ public override ImmutableArray<string> FixableDiagnosticIds
get { return ImmutableArray.Create(CS0103, CS1061, CS0117, CS0122, CS0539, CS1501, CS1503, CS0305, CS0308, CS1660, CS1739, CS7036); }
}
protected override bool IsCandidate(SyntaxNode node)
protected override bool IsCandidate(SyntaxNode node, Diagnostic diagnostic)
{
return node.IsKind(SyntaxKind.IdentifierName) ||
node.IsKind(SyntaxKind.MethodDeclaration) ||
......
......@@ -33,7 +33,7 @@ public override ImmutableArray<string> FixableDiagnosticIds
get { return ImmutableArray.Create(CS0103, CS0117, CS0234, CS0246, CS0305, CS0308, CS0426, CS0616); }
}
protected override bool IsCandidate(SyntaxNode node)
protected override bool IsCandidate(SyntaxNode node, Diagnostic diagnostic)
{
var qualified = node as QualifiedNameSyntax;
if (qualified != null)
......
......@@ -30,7 +30,7 @@ public override ImmutableArray<string> FixableDiagnosticIds
get { return ImmutableArray.Create(CS1061, CS0103, CS0117, CS0539, CS0246); }
}
protected override bool IsCandidate(SyntaxNode node)
protected override bool IsCandidate(SyntaxNode node, Diagnostic diagnostic)
{
return node is SimpleNameSyntax || node is PropertyDeclarationSyntax || node is MemberBindingExpressionSyntax;
}
......
// 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.Composition;
using System.Linq;
......@@ -29,6 +30,11 @@ protected override bool IsConstructorInitializerGeneration(SemanticDocument docu
return node is ConstructorInitializerSyntax;
}
protected override bool IsClassDeclarationGeneration(SemanticDocument document, SyntaxNode node, CancellationToken cancellationToken)
{
return node is ClassDeclarationSyntax;
}
protected override bool TryInitializeConstructorInitializerGeneration(
SemanticDocument document, SyntaxNode node, CancellationToken cancellationToken,
out SyntaxToken token, out IList<ArgumentSyntax> arguments, out INamedTypeSymbol typeToGenerateIn)
......@@ -54,6 +60,35 @@ protected override bool IsConstructorInitializerGeneration(SemanticDocument docu
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,
......
......@@ -22,8 +22,9 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
return;
}
var diagnostic = context.Diagnostics.First();
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
var names = GetTargetNodes(root, context.Span);
var names = GetTargetNodes(root, context.Span, diagnostic);
foreach (var name in names)
{
var codeActions = await GetCodeActionsAsync(context.Document, name, context.CancellationToken).ConfigureAwait(false);
......@@ -44,12 +45,12 @@ protected virtual SyntaxNode GetTargetNode(SyntaxNode node)
return node;
}
protected virtual bool IsCandidate(SyntaxNode node)
protected virtual bool IsCandidate(SyntaxNode node, Diagnostic diagnostic)
{
return false;
}
protected virtual IEnumerable<SyntaxNode> GetTargetNodes(SyntaxNode root, TextSpan span)
protected virtual IEnumerable<SyntaxNode> GetTargetNodes(SyntaxNode root, TextSpan span, Diagnostic diagnostic)
{
var token = root.FindToken(span.Start);
if (!token.Span.IntersectsWith(span))
......@@ -57,7 +58,7 @@ protected virtual IEnumerable<SyntaxNode> GetTargetNodes(SyntaxNode root, TextSp
yield break;
}
var nodes = token.GetAncestors<SyntaxNode>().Where(IsCandidate);
var nodes = token.GetAncestors<SyntaxNode>().Where(n => IsCandidate(n, diagnostic));
foreach (var node in nodes)
{
var name = GetTargetNode(node);
......
......@@ -41,22 +41,28 @@ private partial class Editor
internal async Task<Document> GetEditAsync()
{
// First, see if there's an accessible base constructor that would accept these
// First, if we were just given the constructor and the type to generate it into
// then just go generat that constructor. There's nothing special we need to do.
var edit = await GenerateDelegatedConstructorAsync().ConfigureAwait(false);
if (edit != null)
{
return edit;
}
// then, see if there's an accessible base constructor that would accept these
// types, then just call into that instead of generating fields.
//
// then, 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 edit = await GenerateThisOrBaseDelegatingConstructorAsync().ConfigureAwait(false);
edit = await GenerateThisOrBaseDelegatingConstructorAsync().ConfigureAwait(false);
if (edit != null)
{
return edit;
}
// Otherwise, just generate a normal constructor that assigns any provided
// parameters into fields.
return await GenerateFieldDelegatingConstructorAsync().ConfigureAwait(false);
}
......@@ -88,6 +94,51 @@ private async Task<Document> GenerateThisOrBaseDelegatingConstructorAsync(int ar
return null;
}
private async Task<Document> GenerateDelegatedConstructorAsync()
{
var delegatedConstructor = _state.DelegatedConstructorOpt;
if (delegatedConstructor == null)
{
return null;
}
var namedType = _state.TypeToGenerateIn;
if (namedType == 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>();
var isThis = namedType.Equals(delegatedConstructor.ContainingType);
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: delegatedConstructor.Parameters,
baseConstructorArguments: baseConstructorArguments,
thisConstructorArguments: thisConstructorArguments);
var result = await codeGenerationService.AddMembersAsync(
_document.Project.Solution,
_state.TypeToGenerateIn,
new List<ISymbol> { constructor },
new CodeGenerationOptions(_state.Token.GetLocation()),
_cancellationToken)
.ConfigureAwait(false);
return result;
}
private async Task<Document> GenerateDelegatingConstructorAsync(
int argumentCount,
INamedTypeSymbol namedType)
......
......@@ -25,15 +25,17 @@ protected internal class State
// The type we're creating a constructor for. Will be a class or struct type.
public INamedTypeSymbol TypeToGenerateIn { get; private set; }
public IList<ITypeSymbol> ParameterTypes { get; private set; }
public IList<RefKind> ParameterRefKinds { get; private set; }
public IList<ITypeSymbol> ParameterTypes { get; private set; }
public IMethodSymbol DelegatedConstructorOpt { get; private set; }
public SyntaxToken Token { get; private set; }
public bool IsConstructorInitializerGeneration { get; private set; }
private State()
{
this.IsConstructorInitializerGeneration = false;
}
public static async Task<State> GenerateAsync(
......@@ -71,6 +73,13 @@ private State()
return false;
}
}
else if (service.IsClassDeclarationGeneration(document, node, cancellationToken))
{
if (!await TryInitializeClassDeclarationGenerationAsync(service, document, node, cancellationToken).ConfigureAwait(false))
{
return false;
}
}
else
{
return false;
......@@ -82,7 +91,7 @@ private State()
}
this.ParameterTypes = this.ParameterTypes ?? GetParameterTypes(service, document, cancellationToken);
this.ParameterRefKinds = this.Arguments.Select(service.GetRefKind).ToList();
this.ParameterRefKinds = this.ParameterRefKinds ?? this.Arguments.Select(service.GetRefKind).ToList();
return !ClashesWithExistingConstructor(service, document, cancellationToken);
}
......@@ -99,7 +108,8 @@ private bool ClashesWithExistingConstructor(TService service, SemanticDocument d
var destinationProvider = document.Project.Solution.Workspace.Services.GetLanguageServices(this.TypeToGenerateIn.Language);
var syntaxFacts = destinationProvider.GetService<ISyntaxFactsService>();
return this.TypeToGenerateIn.InstanceConstructors.Any(c => SignatureComparer.Instance.HaveSameSignature(parameters, c.Parameters, compareParameterName: true, isCaseSensitive: syntaxFacts.IsCaseSensitive));
return this.TypeToGenerateIn.InstanceConstructors.Any(
c => SignatureComparer.Instance.HaveSameSignature(parameters, c.Parameters, compareParameterName: true, isCaseSensitive: syntaxFacts.IsCaseSensitive));
}
internal List<ITypeSymbol> GetParameterTypes(
......@@ -155,6 +165,28 @@ private ITypeSymbol FixType(ITypeSymbol typeSymbol, SemanticModel semanticModel,
return await TryDetermineTypeToGenerateInAsync(document, typeToGenerateIn, cancellationToken).ConfigureAwait(false);
}
private async Task<bool> TryInitializeClassDeclarationGenerationAsync(
TService service,
SemanticDocument document,
SyntaxNode simpleName,
CancellationToken cancellationToken)
{
SyntaxToken token;
INamedTypeSymbol typeToGenerateIn;
IMethodSymbol constructor;
if (service.TryInitializeClassDeclarationGenerationState(document, simpleName, cancellationToken,
out token, out constructor, out typeToGenerateIn))
{
this.Token = token;
this.DelegatedConstructorOpt = constructor;
this.ParameterTypes = constructor.Parameters.Select(p => p.Type).ToList();
this.ParameterRefKinds = constructor.Parameters.Select(p => p.RefKind).ToList();
}
cancellationToken.ThrowIfCancellationRequested();
return await TryDetermineTypeToGenerateInAsync(document, typeToGenerateIn, cancellationToken).ConfigureAwait(false);
}
private async Task<bool> TryInitializeSimpleNameGenerationAsync(
TService service,
SemanticDocument document,
......
......@@ -5,6 +5,7 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.GenerateMember.GenerateConstructor
......@@ -20,10 +21,12 @@ 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 TryInitializeConstructorInitializerGeneration(SemanticDocument document, SyntaxNode constructorInitializer, CancellationToken cancellationToken, out SyntaxToken token, out IList<TArgumentSyntax> arguments, out INamedTypeSymbol typeToGenerateIn);
protected abstract bool TryInitializeSimpleNameGenerationState(SemanticDocument document, SyntaxNode simpleName, CancellationToken cancellationToken, out SyntaxToken token, out IList<TArgumentSyntax> 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 IList<TArgumentSyntax> arguments, out INamedTypeSymbol typeToGenerateIn);
protected abstract bool TryInitializeSimpleAttributeNameGenerationState(SemanticDocument document, SyntaxNode simpleName, CancellationToken cancellationToken, out SyntaxToken token, out IList<TArgumentSyntax> arguments, out IList<TAttributeArgumentSyntax> attributeArguments, out INamedTypeSymbol typeToGenerateIn);
protected abstract IList<string> GenerateParameterNames(SemanticModel semanticModel, IEnumerable<TArgumentSyntax> arguments, IList<string> reservedNames = null);
......@@ -55,5 +58,41 @@ private IEnumerable<CodeAction> GetActions(Document document, State state)
{
yield return new GenerateConstructorCodeAction((TService)this, document, state);
}
protected static bool IsSymbolAccessible(
ISymbol symbol, SemanticDocument document)
{
if (symbol == null)
{
return false;
}
if (symbol.Kind == SymbolKind.Property)
{
if (!IsSymbolAccessible(((IPropertySymbol)symbol).SetMethod, document))
{
return false;
}
}
// Public and protected constructors are accessible. Internal constructors are
// accessible if we have friend access. We can't call the normal accessibility
// checkers since they will think that a protected constructor isn't accessible
// (since we don't have the destination type that would have access to them yet).
switch (symbol.DeclaredAccessibility)
{
case Accessibility.ProtectedOrInternal:
case Accessibility.Protected:
case Accessibility.Public:
return true;
case Accessibility.ProtectedAndInternal:
case Accessibility.Internal:
return document.SemanticModel.Compilation.Assembly.IsSameAssemblyOrHasFriendAccessTo(
symbol.ContainingAssembly);
default:
return false;
}
}
}
}
......@@ -22,10 +22,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateConstructor
Friend Const BC30455 As String = "BC30455" ' error BC30455: Argument not specified for parameter 'x' of 'Public Sub New(x As Integer)'.
Friend Const BC30512 As String = "BC30512" ' error BC30512: Option Strict On disallows implicit conversions from 'Object' to 'Integer'.
Friend Const BC32006 As String = "BC32006" ' error BC32006: 'Char' values cannot be converted to 'Integer'.
Friend Const BC30387 As String = "BC30387" ' error BC32006: Class 'Derived' must declare a 'Sub New' because its base class 'Base' does not have an accessible 'Sub New' that can be called with no arguments.
Public Overrides ReadOnly Property FixableDiagnosticIds As ImmutableArray(Of String)
Get
Return ImmutableArray.Create(BC30057, BC30272, BC30274, BC30389, BC30455, BC32006, BC30512)
Return ImmutableArray.Create(BC30057, BC30272, BC30274, BC30389, BC30455, BC32006, BC30512, BC30387)
End Get
End Property
......@@ -53,8 +54,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateConstructor
Return node
End Function
Protected Overrides Function IsCandidate(node As SyntaxNode) As Boolean
Return TypeOf node Is SimpleNameSyntax OrElse TypeOf node Is InvocationExpressionSyntax OrElse TypeOf node Is ObjectCreationExpressionSyntax OrElse TypeOf node Is AttributeSyntax
Protected Overrides Function IsCandidate(node As SyntaxNode, diagnostic As Diagnostic) As Boolean
If TypeOf node Is SimpleNameSyntax OrElse TypeOf node Is InvocationExpressionSyntax OrElse TypeOf node Is ObjectCreationExpressionSyntax OrElse TypeOf node Is AttributeSyntax Then
Return True
End If
Return diagnostic.Id = BC30387 AndAlso TypeOf node Is ClassBlockSyntax
End Function
End Class
End Namespace
......@@ -28,7 +28,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEnumMember
Return service.GenerateEnumMemberAsync(document, node, cancellationToken)
End Function
Protected Overrides Function IsCandidate(node As SyntaxNode) As Boolean
Protected Overrides Function IsCandidate(node As SyntaxNode, diagnostic As Diagnostic) As Boolean
Return TypeOf node Is MemberAccessExpressionSyntax
End Function
......
......@@ -28,7 +28,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateMethod
Return service.GenerateConversionAsync(document, node, cancellationToken)
End Function
Protected Overrides Function IsCandidate(node As SyntaxNode) As Boolean
Protected Overrides Function IsCandidate(node As SyntaxNode, diagnostic As Diagnostic) As Boolean
Return TypeOf node Is QualifiedNameSyntax OrElse
TypeOf node Is SimpleNameSyntax OrElse
TypeOf node Is MemberAccessExpressionSyntax OrElse
......
......@@ -42,7 +42,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateMethod
Return service.GenerateMethodAsync(document, node, cancellationToken)
End Function
Protected Overrides Function IsCandidate(node As SyntaxNode) As Boolean
Protected Overrides Function IsCandidate(node As SyntaxNode, diagnostic As Diagnostic) As Boolean
Return TypeOf node Is QualifiedNameSyntax OrElse
TypeOf node Is SimpleNameSyntax OrElse
TypeOf node Is MemberAccessExpressionSyntax OrElse
......
......@@ -36,7 +36,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateType
Return service.GenerateTypeAsync(document, node, cancellationToken)
End Function
Protected Overrides Function IsCandidate(node As SyntaxNode) As Boolean
Protected Overrides Function IsCandidate(node As SyntaxNode, diagnostic As Diagnostic) As Boolean
Dim qualified = TryCast(node, QualifiedNameSyntax)
If qualified IsNot Nothing Then
Return True
......
......@@ -31,7 +31,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateVariable
Return service.GenerateVariableAsync(document, node, cancellationToken)
End Function
Protected Overrides Function IsCandidate(node As SyntaxNode) As Boolean
Protected Overrides Function IsCandidate(node As SyntaxNode, diagnostic As Diagnostic) As Boolean
If TypeOf node Is QualifiedNameSyntax OrElse TypeOf node Is MemberAccessExpressionSyntax Then
Return True
End If
......
......@@ -18,7 +18,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateMember.GenerateConstructor
End Function
Protected Overrides Function GenerateParameterNames(semanticModel As SemanticModel, arguments As IEnumerable(Of ArgumentSyntax), Optional reservedNames As IList(Of String) = Nothing) As IList(Of String)
Return semanticModel.GenerateParameterNames(arguments.ToList(), reservedNames)
Return semanticModel.GenerateParameterNames(arguments?.ToList(), reservedNames)
End Function
Protected Overrides Function GetArgumentType(semanticModel As SemanticModel, argument As ArgumentSyntax, cancellationToken As CancellationToken) As Microsoft.CodeAnalysis.ITypeSymbol
......@@ -146,6 +146,35 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateMember.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 baseType = classSymbol.BaseType
Dim constructor = 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,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册