提交 0ffcceec 编写于 作者: C CyrusNajmabadi

Merge branch 'nonSpecializedDefinitionItems' into findRefsOOPWork

......@@ -4066,7 +4066,7 @@ public class Test
// TODO...
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/18800")]
[Fact]
public void CS0306ERR_BadTypeArgument01()
{
var source =
......
......@@ -1552,5 +1552,38 @@ public override void M2<T>(T? i = null)
}
}");
}
[WorkItem(13932, "https://github.com/dotnet/roslyn/issues/13932")]
[WorkItem(5898, "https://github.com/dotnet/roslyn/issues/5898")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)]
public async Task TestAutoProperties()
{
await TestInRegularAndScript1Async(
@"abstract class AbstractClass
{
public abstract int ReadOnlyProp { get; }
public abstract int ReadWriteProp { get; set; }
public abstract int WriteOnlyProp { set; }
}
class [|C|] : AbstractClass
{
}",
@"abstract class AbstractClass
{
public abstract int ReadOnlyProp { get; }
public abstract int ReadWriteProp { get; set; }
public abstract int WriteOnlyProp { set; }
}
class C : AbstractClass
{
public override int ReadOnlyProp { get; }
public override int ReadWriteProp { get; set; }
public override int WriteOnlyProp { set => throw new System.NotImplementedException(); }
}", parameters: new TestParameters(options: Option(
ImplementTypeOptions.PropertyGenerationBehavior,
ImplementTypePropertyGenerationBehavior.PreferAutoProperties)));
}
}
}
\ No newline at end of file
......@@ -3,7 +3,6 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.ImplementInterface;
......@@ -6705,5 +6704,40 @@ class C : I
}
}");
}
[WorkItem(13932, "https://github.com/dotnet/roslyn/issues/13932")]
[WorkItem(5898, "https://github.com/dotnet/roslyn/issues/5898")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)]
public async Task TestAutoProperties()
{
await TestInRegularAndScript1Async(
@"interface IInterface
{
int ReadOnlyProp { get; }
int ReadWriteProp { get; set; }
int WriteOnlyProp { set; }
}
class Class : [|IInterface|]
{
}",
@"interface IInterface
{
int ReadOnlyProp { get; }
int ReadWriteProp { get; set; }
int WriteOnlyProp { set; }
}
class Class : IInterface
{
public int ReadOnlyProp { get; }
public int ReadWriteProp { get; set; }
public int WriteOnlyProp { set => throw new System.NotImplementedException(); }
}", parameters: new TestParameters(options: Option(
ImplementTypeOptions.PropertyGenerationBehavior,
ImplementTypePropertyGenerationBehavior.PreferAutoProperties)));
}
}
}
\ No newline at end of file
......@@ -182,6 +182,8 @@ private void VerifyBreakIntoCharacterParts(string original, params string[] part
[InlineData("[|Fog|]Bar", "fog", PatternMatchKind.Prefix, CaseInsensitive)]
[InlineData("[|fog|]BarFoo", "Fog", PatternMatchKind.Prefix, CaseInsensitive)]
[InlineData("[|system.ref|]lection", "system.ref", PatternMatchKind.Prefix, CaseSensitive)]
[InlineData("Fog[|B|]ar", "b", PatternMatchKind.Substring, CaseInsensitive)]
[InlineData("_[|my|]Button", "my", PatternMatchKind.Substring, CaseSensitive)]
......@@ -234,10 +236,10 @@ private void VerifyBreakIntoCharacterParts(string original, params string[] part
[InlineData("my[|_b|]utton", "_B", PatternMatchKind.CamelCase, CaseInsensitive, PatternMatcher.CamelCaseContiguousBonus)]
[InlineData("[|_|]my_[|b|]utton", "_B", PatternMatchKind.CamelCase, CaseInsensitive, PatternMatcher.CamelCaseMatchesFromStartBonus)]
public void TryMatchSingleWordPattern(
public void TestNonFuzzyMatch(
string candidate, string pattern, int matchKindInt, bool isCaseSensitive, int? camelCaseWeight = null)
{
var match = TryMatchSingleWordPattern(candidate, pattern);
var match = TestNonFuzzyMatch(candidate, pattern);
Assert.NotNull(match);
var matchKind = (PatternMatchKind)matchKindInt;
......@@ -269,9 +271,10 @@ private void VerifyBreakIntoCharacterParts(string original, params string[] part
[InlineData("FogBarBaz", "FZ")]
[InlineData("_mybutton", "myB")]
[InlineData("FogBarChangedEventArgs", "changedeventarrrgh")]
public void TryMatchSingleWordPattern_NoMatch(string candidate, string pattern)
[InlineData("runtime.native.system", "system.reflection")]
public void TestNonFuzzyMatch_NoMatch(string candidate, string pattern)
{
var match = TryMatchSingleWordPattern(candidate, pattern);
var match = TestNonFuzzyMatch(candidate, pattern);
Assert.Null(match);
}
......@@ -470,7 +473,7 @@ public void TryMatchSingleWordPattern_CultureAwareSingleWordPreferCaseSensitiveE
try
{
var match = TryMatchSingleWordPattern("[|ioo|]", "\u0130oo"); // u0130 = Capital I with dot
var match = TestNonFuzzyMatch("[|ioo|]", "\u0130oo"); // u0130 = Capital I with dot
Assert.Equal(PatternMatchKind.Exact, match.Value.Kind);
Assert.False(match.Value.IsCaseSensitive);
......@@ -499,11 +502,15 @@ private static IList<string> BreakIntoCharacterParts(string identifier)
private static IList<string> BreakIntoWordParts(string identifier)
=> PartListToSubstrings(identifier, StringBreaker.BreakIntoWordParts(identifier));
private static PatternMatch? TryMatchSingleWordPattern(string candidate, string pattern)
private static PatternMatch? TestNonFuzzyMatch(string candidate, string pattern)
{
MarkupTestFile.GetSpans(candidate, out candidate, out ImmutableArray<TextSpan> spans);
var match = new PatternMatcher(pattern).MatchSingleWordPattern_ForTestingOnly(candidate);
var match = new PatternMatcher(pattern).GetFirstMatch(candidate, includeMatchSpans: true);
if (match?.Kind == PatternMatchKind.Fuzzy)
{
match = null;
}
if (match == null)
{
......@@ -536,4 +543,4 @@ private static IEnumerable<PatternMatch> TryMatchMultiWordPattern(string candida
}
}
}
}
}
\ No newline at end of file
......@@ -3,6 +3,7 @@
Imports System.Globalization
Imports Microsoft.CodeAnalysis.Completion
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
Imports Microsoft.CodeAnalysis.Text
Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense
' These tests adapted from David Kean's table at
......@@ -10,7 +11,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense
Public Class CompletionRulesTests
<Fact>
Public Sub TestMatchLowerCaseEnglishI()
Dim wordsToMatch = {"index", "Index", "işte", şte"}
Dim wordsToMatch = {"[|i|]ndex", "[|I|]ndex", "[|i|]şte", "[|İ|]şte"}
Dim wordsToNotMatch = {"ırak"}
TestMatches("i", wordsToMatch)
......@@ -19,7 +20,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense
<Fact>
Public Sub TestMatchDottedUpperTurkishI()
Dim wordsToMatch = {"index", "işte", şte"}
Dim wordsToMatch = {"[|i|]ndex", "[|i|]şte", "[|İ|]şte"}
Dim wordsToNotMatch = {"ırak", "Irak", "Index"}
TestMatches("İ", wordsToMatch)
......@@ -28,7 +29,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense
<Fact>
Public Sub TestMatchNonDottedLowerTurkishI()
Dim wordsToMatch = {"ırak", "Irak"}
Dim wordsToMatch = {"[|ı|]rak", "[|I|]rak"}
Dim wordsToNotMatch = {"index", "işte", "İşte"}
TestMatches("ı", wordsToMatch)
......@@ -37,31 +38,48 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense
<Fact>
Public Sub TestMatchEnglishUpperI()
Dim wordsToMatch = {"Index", "index", "ırak", "Irak"}
' In turkish-culture "I" will not match "index". However, we want to verify that
' the underlying completion helper will fallback to doing an en-us check if the
' tr-tr check fails, and that it properly also returns the matched spans in this case.
Dim wordsToMatch = {"[|I|]ndex", "[|i|]ndex", "[|ı|]rak", "[|I|]rak"}
Dim wordsToNotMatch = {"İşte"}
TestMatches("I", wordsToMatch)
TestNotMatches("I", wordsToNotMatch)
End Sub
Private Sub TestMatches(v As String, wordsToMatch() As String)
Private Sub TestMatches(pattern As String, wordsToMatch() As String)
Dim culture = New CultureInfo("tr-TR", useUserOverride:=False)
Dim workspace = New TestWorkspace
Dim helper = CompletionHelper.GetHelper(workspace, LanguageNames.CSharp)
For Each word In wordsToMatch
For Each wordMarkup In wordsToMatch
Dim word As String = Nothing
Dim wordMatchSpan As TextSpan = Nothing
MarkupTestFile.GetSpan(wordMarkup, word, wordMatchSpan)
Dim item = CompletionItem.Create(word)
Assert.True(helper.MatchesPattern(item.FilterText, v, culture), $"Expected item {word} does not match {v}")
Assert.True(helper.MatchesPattern(item.FilterText, pattern, culture), $"Expected item {word} does not match {pattern}")
Dim highlightedSpans = helper.GetHighlightedSpans(item.FilterText, pattern, culture)
Assert.NotEmpty(highlightedSpans)
Assert.Equal(1, highlightedSpans.Length)
Assert.Equal(wordMatchSpan, highlightedSpans(0))
Next
End Sub
Private Sub TestNotMatches(v As String, wordsToNotMatch() As String)
Private Sub TestNotMatches(pattern As String, wordsToNotMatch() As String)
Dim culture = New CultureInfo("tr-TR", useUserOverride:=False)
Dim workspace = New TestWorkspace
Dim helper = CompletionHelper.GetHelper(workspace, LanguageNames.CSharp)
For Each word In wordsToNotMatch
Dim item = CompletionItem.Create(word)
Assert.False(helper.MatchesPattern(item.FilterText, v, culture), $"Unexpected item {word} matches {v}")
Assert.False(helper.MatchesPattern(item.FilterText, pattern, culture), $"Unexpected item {word} matches {pattern}")
Dim highlightedSpans = helper.GetHighlightedSpans(item.FilterText, pattern, culture)
Assert.Empty(highlightedSpans)
Next
End Sub
End Class
......
......@@ -3,6 +3,7 @@
Imports Microsoft.CodeAnalysis.CodeFixes
Imports Microsoft.CodeAnalysis.Diagnostics
Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics
Imports Microsoft.CodeAnalysis.ImplementType
Imports Microsoft.CodeAnalysis.VisualBasic.ImplementAbstractClass
Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.ImplementAbstractClass
......@@ -574,5 +575,42 @@ Class x
End Function
End Class")
End Function
<WorkItem(13932, "https://github.com/dotnet/roslyn/issues/13932")>
<WorkItem(5898, "https://github.com/dotnet/roslyn/issues/5898")>
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)>
Public Async Function TestAutoProperties() As Task
Await TestInRegularAndScript1Async(
"MustInherit Class AbstractClass
MustOverride ReadOnly Property ReadOnlyProp As Integer
MustOverride Property ReadWriteProp As Integer
MustOverride WriteOnly Property WriteOnlyProp As Integer
End Class
Class [|C|]
Inherits AbstractClass
End Class",
"MustInherit Class AbstractClass
MustOverride ReadOnly Property ReadOnlyProp As Integer
MustOverride Property ReadWriteProp As Integer
MustOverride WriteOnly Property WriteOnlyProp As Integer
End Class
Class C
Inherits AbstractClass
Public Overrides ReadOnly Property ReadOnlyProp As Integer
Public Overrides Property ReadWriteProp As Integer
Public Overrides WriteOnly Property WriteOnlyProp As Integer
Set(value As Integer)
Throw New System.NotImplementedException()
End Set
End Property
End Class", parameters:=New TestParameters(options:=[Option](
ImplementTypeOptions.PropertyGenerationBehavior,
ImplementTypePropertyGenerationBehavior.PreferAutoProperties)))
End Function
End Class
End Namespace
\ No newline at end of file
......@@ -3,6 +3,7 @@
Imports Microsoft.CodeAnalysis.CodeFixes
Imports Microsoft.CodeAnalysis.Diagnostics
Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics
Imports Microsoft.CodeAnalysis.ImplementType
Imports Microsoft.CodeAnalysis.VisualBasic.ImplementInterface
Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.ImplementInterface
......@@ -4518,5 +4519,41 @@ Namespace System
End Structure
End Namespace")
End Function
<WorkItem(13932, "https://github.com/dotnet/roslyn/issues/13932")>
<WorkItem(5898, "https://github.com/dotnet/roslyn/issues/5898")>
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)>
Public Async Function TestAutoProperties() As Task
Await TestInRegularAndScript1Async(
"interface IInterface
readonly property ReadOnlyProp as integer
property ReadWriteProp as integer
writeonly property WriteOnlyProp as integer
end interface
class Class
implements [|IInterface|]
end class",
"interface IInterface
readonly property ReadOnlyProp as integer
property ReadWriteProp as integer
writeonly property WriteOnlyProp as integer
end interface
class Class
implements IInterface
Public ReadOnly Property ReadOnlyProp As Integer Implements IInterface.ReadOnlyProp
Public Property ReadWriteProp As Integer Implements IInterface.ReadWriteProp
Public WriteOnly Property WriteOnlyProp As Integer Implements IInterface.WriteOnlyProp
Set(value As Integer)
Throw New System.NotImplementedException()
End Set
End Property
end class", parameters:=New TestParameters(options:=[Option](
ImplementTypeOptions.PropertyGenerationBehavior,
ImplementTypePropertyGenerationBehavior.PreferAutoProperties)))
End Function
End Class
End Namespace
\ No newline at end of file
......@@ -112,7 +112,7 @@ public bool MatchesPattern(string text, string pattern, CultureInfo culture)
if (!culture.Equals(EnUSCultureInfo))
{
patternMatcher = this.GetPatternMatcher(pattern, EnUSCultureInfo);
match = patternMatcher.GetFirstMatch(completionItemText);
match = patternMatcher.GetFirstMatch(completionItemText, includeMatchSpans);
if (match != null)
{
return match;
......
......@@ -138,7 +138,6 @@
<DesignTime>True</DesignTime>
<DependentUpon>FeaturesResources.resx</DependentUpon>
</Compile>
<Compile Include="FindUsages\DefinitionItem.MetadataDefinitionItem.cs" />
<Compile Include="GenerateConstructorFromMembers\GenerateConstructorFromMembersOptions.cs" />
<Compile Include="GenerateConstructorFromMembers\GenerateConstructorWithDialogCodeAction.cs" />
<Compile Include="GenerateEqualsAndGetHashCodeFromMembers\FormatLargeBinaryExpressionRule.cs" />
......@@ -397,7 +396,6 @@
<Compile Include="DocumentSpan.cs" />
<Compile Include="FindUsages\DefinitionItem.cs" />
<Compile Include="FindUsages\DefinitionItem.DocumentLocationDefinitionItem.cs" />
<Compile Include="FindUsages\DefinitionItem.NonNavigatingDefinitionItem.cs" />
<Compile Include="FindUsages\DefinitionsAndReferences.cs" />
<Compile Include="FindUsages\SourceReferenceItem.cs" />
<Compile Include="Diagnostics\EngineV2\DiagnosticAnalyzerExecutor.cs" />
......
// 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.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Navigation;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.FindUsages
{
......@@ -11,25 +17,112 @@ internal partial class DefinitionItem
/// <see cref="DocumentSpan"/>.
/// </summary>
// internal for testing purposes.
internal sealed class DocumentLocationDefinitionItem : DefinitionItem
internal sealed class DefaultDefinitionItem : DefinitionItem
{
private readonly Workspace _workspaceOpt;
internal override bool IsExternal => false;
public DocumentLocationDefinitionItem(
public DefaultDefinitionItem(
Workspace workspaceOpt,
ImmutableArray<string> tags,
ImmutableArray<TaggedText> displayParts,
ImmutableArray<TaggedText> nameDisplayParts,
ImmutableArray<TaggedText> originationParts,
ImmutableArray<DocumentSpan> sourceSpans,
ImmutableDictionary<string, string> properties,
bool displayIfNoReferences)
: base(tags, displayParts, nameDisplayParts,
ImmutableArray.Create(new TaggedText(TextTags.Text, sourceSpans[0].Document.Project.Name)),
: base(tags, displayParts, nameDisplayParts, originationParts,
sourceSpans, properties, displayIfNoReferences)
{
_workspaceOpt = workspaceOpt;
}
public override bool CanNavigateTo() => SourceSpans[0].CanNavigateTo();
public override bool TryNavigateTo() => SourceSpans[0].TryNavigateTo();
public override bool CanNavigateTo()
{
if (this.Properties.ContainsKey(NonNavigable))
{
return false;
}
if (this.Properties.TryGetValue(MetadataSymbolKey, out var symbolKey))
{
return CanNavigateToMetadataSymbol(symbolKey);
}
return SourceSpans[0].CanNavigateTo();
}
public override bool TryNavigateTo()
{
if (this.Properties.ContainsKey(NonNavigable))
{
return false;
}
if (this.Properties.TryGetValue(MetadataSymbolKey, out var symbolKey))
{
return TryNavigateToMetadataSymbol(symbolKey);
}
return SourceSpans[0].TryNavigateTo();
}
private bool CanNavigateToMetadataSymbol(string symbolKey)
=> TryNavigateToMetadataSymbol(symbolKey, (symbol, project, service) => true);
private bool TryNavigateToMetadataSymbol(string symbolKey)
=> TryNavigateToMetadataSymbol(symbolKey, (symbol, project, service) =>
service.TryNavigateToSymbol(
symbol, project, project.Solution.Options.WithChangedOption(NavigationOptions.PreferProvisionalTab, true)));
private bool TryNavigateToMetadataSymbol(string symbolKey, Func<ISymbol, Project, ISymbolNavigationService, bool> action)
{
var projectAndSymbol = ResolveSymbolInCurrentSolution(symbolKey);
if (projectAndSymbol == null)
{
return false;
}
var project = projectAndSymbol?.project;
var symbol = projectAndSymbol?.symbol;
if (symbol == null || project == null)
{
return false;
}
if (symbol.Kind == SymbolKind.Namespace)
{
return false;
}
var navigationService = _workspaceOpt.Services.GetService<ISymbolNavigationService>();
return action(symbol, project, navigationService);
}
private (Project project, ISymbol symbol)? ResolveSymbolInCurrentSolution(string symbolKey)
{
if (!this.Properties.TryGetValue(MetadataAssemblyIdentityDisplayName, out var identityDisplayName) ||
!AssemblyIdentity.TryParseDisplayName(identityDisplayName, out var identity))
{
return null;
}
var project = _workspaceOpt.CurrentSolution
.ProjectsWithReferenceToAssembly(identity)
.FirstOrDefault();
if (project == null)
{
return null;
}
var compilation = project.GetCompilationAsync(CancellationToken.None)
.WaitAndGetResult(CancellationToken.None);
var symbol = SymbolKey.Resolve(symbolKey, compilation).Symbol;
return (project, symbol);
}
}
}
}
\ No newline at end of file
// 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.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Navigation;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.FindUsages
{
internal partial class DefinitionItem
{
/// <summary>
/// Implementation of a <see cref="DefinitionItem"/> that sits on top of an
/// <see cref="ISymbol"/>. In order to not keep anything alive too long, we only
/// hold onto IDs and Keys. When the user tries to navigate to an item we will
/// attempt to find the symbol again in the current solution snapshot and
/// navigate to it there.
/// </summary>
private sealed class MetadataDefinitionItem : DefinitionItem
{
private readonly Workspace _workspace;
private readonly SymbolKey _symbolKey;
private readonly AssemblyIdentity _symbolAssemblyIdentity;
internal override bool IsExternal => false;
public MetadataDefinitionItem(
ImmutableArray<string> tags,
ImmutableArray<TaggedText> displayParts,
ImmutableArray<TaggedText> nameDisplayParts,
ImmutableDictionary<string, string> properties,
bool displayIfNoReferences,
Solution solution, ISymbol definition)
: base(tags, displayParts, nameDisplayParts,
GetOriginationParts(definition),
ImmutableArray<DocumentSpan>.Empty,
properties,
displayIfNoReferences)
{
_workspace = solution.Workspace;
_symbolKey = definition.GetSymbolKey();
_symbolAssemblyIdentity = definition.ContainingAssembly?.Identity;
}
public override bool CanNavigateTo()
=> TryNavigateTo((symbol, project, service) => true);
public override bool TryNavigateTo()
{
return TryNavigateTo((symbol, project, service) =>
service.TryNavigateToSymbol(
symbol, project, project.Solution.Options.WithChangedOption(NavigationOptions.PreferProvisionalTab, true)));
}
private bool TryNavigateTo(Func<ISymbol, Project, ISymbolNavigationService, bool> action)
{
var projectAndSymbol = ResolveSymbolInCurrentSolution();
if (projectAndSymbol == null)
{
return false;
}
var project = projectAndSymbol?.project;
var symbol = projectAndSymbol?.symbol;
if (symbol == null || project == null)
{
return false;
}
if (symbol.Kind == SymbolKind.Namespace)
{
return false;
}
var navigationService = _workspace.Services.GetService<ISymbolNavigationService>();
return action(symbol, project, navigationService);
}
private (Project project, ISymbol symbol)? ResolveSymbolInCurrentSolution()
{
var project = _workspace.CurrentSolution
.ProjectsWithReferenceToAssembly(_symbolAssemblyIdentity)
.FirstOrDefault();
if (project == null)
{
return null;
}
var compilation = project.GetCompilationAsync(CancellationToken.None)
.WaitAndGetResult(CancellationToken.None);
return (project, _symbolKey.Resolve(compilation).Symbol);
}
}
}
}
\ No newline at end of file
// 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.Immutable;
namespace Microsoft.CodeAnalysis.FindUsages
{
internal partial class DefinitionItem
{
/// <summary>
/// Implementation of a <see cref="DefinitionItem"/> used for definitions
/// that cannot be navigated to. For example, C# and VB namespaces cannot be
/// navigated to.
/// </summary>
private sealed class NonNavigatingDefinitionItem : DefinitionItem
{
internal override bool IsExternal => false;
public NonNavigatingDefinitionItem(
ImmutableArray<string> tags,
ImmutableArray<TaggedText> displayParts,
ImmutableArray<TaggedText> originationParts,
ImmutableDictionary<string, string> properties,
bool displayIfNoReferences)
: base(tags, displayParts, ImmutableArray<TaggedText>.Empty,
originationParts, ImmutableArray<DocumentSpan>.Empty,
properties, displayIfNoReferences)
{
}
public override bool CanNavigateTo() => false;
public override bool TryNavigateTo() => false;
}
}
}
\ No newline at end of file
......@@ -25,6 +25,10 @@ internal abstract partial class DefinitionItem
internal const string RQNameKey1 = nameof(RQNameKey1);
internal const string RQNameKey2 = nameof(RQNameKey2);
private const string MetadataSymbolKey = nameof(MetadataSymbolKey);
private const string MetadataAssemblyIdentityDisplayName = nameof(MetadataAssemblyIdentityDisplayName);
private const string NonNavigable = nameof(NonNavigable);
/// <summary>
/// Descriptive tags from <see cref="CompletionTags"/>. These tags may influence how the
/// item is displayed.
......@@ -89,7 +93,7 @@ internal abstract partial class DefinitionItem
NameDisplayParts = nameDisplayParts.IsDefaultOrEmpty ? displayParts : nameDisplayParts;
OriginationParts = originationParts.NullToEmpty();
SourceSpans = sourceSpans.NullToEmpty();
Properties = properties;
Properties = properties ?? ImmutableDictionary<string, string>.Empty;
DisplayIfNoReferences = displayIfNoReferences;
}
......@@ -134,8 +138,14 @@ internal abstract partial class DefinitionItem
throw new ArgumentException($"{nameof(sourceSpans)} cannot be empty.");
}
return new DocumentLocationDefinitionItem(
tags, displayParts, nameDisplayParts, sourceSpans, properties, displayIfNoReferences);
var firstDocument = sourceSpans[0].Document;
var originationParts = ImmutableArray.Create(
new TaggedText(TextTags.Text, firstDocument.Project.Name));
return new DefaultDefinitionItem(
firstDocument.Project.Solution.Workspace,
tags, displayParts, nameDisplayParts, originationParts,
sourceSpans, properties, displayIfNoReferences);
}
internal static DefinitionItem CreateMetadataDefinition(
......@@ -146,9 +156,21 @@ internal abstract partial class DefinitionItem
ImmutableDictionary<string, string> properties = null,
bool displayIfNoReferences = true)
{
return new MetadataDefinitionItem(
tags, displayParts, nameDisplayParts, properties,
displayIfNoReferences, solution, symbol);
properties = properties ?? ImmutableDictionary<string, string>.Empty;
var symbolKey = symbol.GetSymbolKey().ToString();
var assemblyIdentityDisplayName = symbol.ContainingAssembly?.Identity.GetDisplayName();
properties = properties.Add(MetadataSymbolKey, symbolKey)
.Add(MetadataAssemblyIdentityDisplayName, assemblyIdentityDisplayName);
var originationParts = GetOriginationParts(symbol);
return new DefaultDefinitionItem(
solution.Workspace, tags,
displayParts, nameDisplayParts, originationParts,
sourceSpans: ImmutableArray<DocumentSpan>.Empty,
properties: properties,
displayIfNoReferences: displayIfNoReferences);
}
// Kept around for binary compat with F#/TypeScript.
......@@ -170,8 +192,18 @@ internal abstract partial class DefinitionItem
ImmutableDictionary<string, string> properties = null,
bool displayIfNoReferences = true)
{
return new NonNavigatingDefinitionItem(
tags, displayParts, originationParts, properties, displayIfNoReferences);
properties = properties ?? ImmutableDictionary<string, string>.Empty;
properties = properties.Add(NonNavigable, NonNavigable);
return new DefaultDefinitionItem(
workspaceOpt: null,
tags: tags,
displayParts: displayParts,
nameDisplayParts: ImmutableArray<TaggedText>.Empty,
originationParts: originationParts,
sourceSpans: ImmutableArray<DocumentSpan>.Empty,
properties: properties,
displayIfNoReferences: displayIfNoReferences);
}
internal static ImmutableArray<TaggedText> GetOriginationParts(ISymbol symbol)
......
// 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;
......@@ -37,11 +35,12 @@ public async Task<Document> GetEditAsync(CancellationToken cancellationToken)
{
var unimplementedMembers = _state.UnimplementedMembers;
var options = await _document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
var propertyGenerationBehavior = options.GetOption(ImplementTypeOptions.PropertyGenerationBehavior);
var memberDefinitions = GenerateMembers(
unimplementedMembers,
cancellationToken);
unimplementedMembers, propertyGenerationBehavior, cancellationToken);
var options = await _document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
var insertionBehavior = options.GetOption(ImplementTypeOptions.InsertionBehavior);
var groupMembers = insertionBehavior == ImplementTypeInsertionBehavior.WithOtherMembersOfTheSameKind;
......@@ -51,23 +50,25 @@ public async Task<Document> GetEditAsync(CancellationToken cancellationToken)
memberDefinitions,
new CodeGenerationOptions(
_state.Location.GetLocation(),
autoInsertionLocation: groupMembers,
autoInsertionLocation: groupMembers,
sortMembers: groupMembers),
cancellationToken).ConfigureAwait(false);
}
private ImmutableArray<ISymbol> GenerateMembers(
ImmutableArray<(INamedTypeSymbol type, ImmutableArray<ISymbol> members)> unimplementedMembers,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
CancellationToken cancellationToken)
{
return unimplementedMembers.SelectMany(t => t.members)
.Select(m => GenerateMember(m, cancellationToken))
.Select(m => GenerateMember(m, propertyGenerationBehavior, cancellationToken))
.WhereNotNull()
.ToImmutableArray();
}
private ISymbol GenerateMember(
ISymbol member,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
......@@ -76,32 +77,29 @@ public async Task<Document> GetEditAsync(CancellationToken cancellationToken)
var syntaxFacts = _document.Project.LanguageServices.GetService<ISyntaxFactsService>();
var addUnsafe = member.IsUnsafe() && !syntaxFacts.IsUnsafeContext(_state.Location);
return GenerateMember(member, addUnsafe, cancellationToken);
return GenerateMember(member, addUnsafe, propertyGenerationBehavior, cancellationToken);
}
private ISymbol GenerateMember(
ISymbol member,
bool addUnsafe,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
CancellationToken cancellationToken)
{
var modifiers = new DeclarationModifiers(isOverride: true, isUnsafe: addUnsafe);
var accessibility = member.ComputeResultantAccessibility(_state.ClassType);
if (member.Kind == SymbolKind.Method)
{
return GenerateMethod((IMethodSymbol)member, modifiers, accessibility, cancellationToken);
}
else if (member.Kind == SymbolKind.Property)
{
return GenerateProperty((IPropertySymbol)member, modifiers, accessibility, cancellationToken);
}
else if (member.Kind == SymbolKind.Event)
switch (member)
{
var @event = (IEventSymbol)member;
return CodeGenerationSymbolFactory.CreateEventSymbol(
@event,
accessibility: accessibility,
modifiers: modifiers);
case IMethodSymbol method:
return GenerateMethod(method, modifiers, accessibility, cancellationToken);
case IPropertySymbol property:
return GenerateProperty(property, modifiers, accessibility, propertyGenerationBehavior, cancellationToken);
case IEventSymbol @event:
return CodeGenerationSymbolFactory.CreateEventSymbol(
@event, accessibility: accessibility, modifiers: modifiers);
}
return null;
......@@ -128,18 +126,27 @@ public async Task<Document> GetEditAsync(CancellationToken cancellationToken)
IPropertySymbol property,
DeclarationModifiers modifiers,
Accessibility accessibility,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
CancellationToken cancellationToken)
{
if (property.GetMethod == null)
{
// Can't generate an auto-prop for a setter-only property.
propertyGenerationBehavior = ImplementTypePropertyGenerationBehavior.PreferThrowingProperties;
}
var syntaxFactory = _document.Project.LanguageServices.GetService<SyntaxGenerator>();
var throwingBody = syntaxFactory.CreateThrowNotImplementedStatementBlock(
_model.Compilation);
var accessorBody = propertyGenerationBehavior == ImplementTypePropertyGenerationBehavior.PreferAutoProperties
? default(ImmutableArray<SyntaxNode>)
: syntaxFactory.CreateThrowNotImplementedStatementBlock(_model.Compilation);
var getMethod = ShouldGenerateAccessor(property.GetMethod)
? CodeGenerationSymbolFactory.CreateAccessorSymbol(
property.GetMethod,
attributes: default(ImmutableArray<AttributeData>),
accessibility: property.GetMethod.ComputeResultantAccessibility(_state.ClassType),
statements: throwingBody)
statements: accessorBody)
: null;
var setMethod = ShouldGenerateAccessor(property.SetMethod)
......@@ -147,7 +154,7 @@ public async Task<Document> GetEditAsync(CancellationToken cancellationToken)
property.SetMethod,
attributes: default(ImmutableArray<AttributeData>),
accessibility: property.SetMethod.ComputeResultantAccessibility(_state.ClassType),
statements: throwingBody)
statements: accessorBody)
: null;
return CodeGenerationSymbolFactory.CreatePropertySymbol(
......@@ -158,7 +165,8 @@ public async Task<Document> GetEditAsync(CancellationToken cancellationToken)
setMethod: setMethod);
}
private bool ShouldGenerateAccessor(IMethodSymbol method) => method != null && _state.ClassType.FindImplementationForAbstractMember(method) == null;
private bool ShouldGenerateAccessor(IMethodSymbol method)
=> method != null && _state.ClassType.FindImplementationForAbstractMember(method) == null;
}
}
}
}
\ No newline at end of file
......@@ -176,15 +176,15 @@ public Task<Document> GetUpdatedDocumentAsync(CancellationToken cancellationToke
var compilation = await result.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
var isComImport = unimplementedMembers.Any(t => t.Item1.IsComImport);
var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
var propertyGenerationBehavior = options.GetOption(ImplementTypeOptions.PropertyGenerationBehavior);
var memberDefinitions = GenerateMembers(
compilation,
unimplementedMembers,
cancellationToken);
compilation, unimplementedMembers, propertyGenerationBehavior, cancellationToken);
// Only group the members in the destination if the user wants that *and*
// it's not a ComImport interface. Member ordering in ComImport interfaces
// matters, so we don't want to much with them.
var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
var insertionBehavior = options.GetOption(ImplementTypeOptions.InsertionBehavior);
var groupMembers = !isComImport &&
insertionBehavior == ImplementTypeInsertionBehavior.WithOtherMembersOfTheSameKind;
......@@ -203,6 +203,7 @@ public Task<Document> GetUpdatedDocumentAsync(CancellationToken cancellationToke
private ImmutableArray<ISymbol> GenerateMembers(
Compilation compilation,
ImmutableArray<(INamedTypeSymbol type, ImmutableArray<ISymbol> members)> unimplementedMembers,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
CancellationToken cancellationToken)
{
// As we go along generating members we may end up with conflicts. For example, say
......@@ -229,7 +230,9 @@ public Task<Document> GetUpdatedDocumentAsync(CancellationToken cancellationToke
foreach (var unimplementedInterfaceMember in unimplementedInterfaceMembers)
{
var member = GenerateMember(compilation, unimplementedInterfaceMember, implementedVisibleMembers, cancellationToken);
var member = GenerateMember(
compilation, unimplementedInterfaceMember, implementedVisibleMembers,
propertyGenerationBehavior, cancellationToken);
if (member != null)
{
implementedMembers.Add(member);
......@@ -272,6 +275,7 @@ private string DetermineMemberName(ISymbol member, List<ISymbol> implementedVisi
Compilation compilation,
ISymbol member,
List<ISymbol> implementedVisibleMembers,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
CancellationToken cancellationToken)
{
// First check if we already generate a member that matches the member we want to
......@@ -308,7 +312,9 @@ private string DetermineMemberName(ISymbol member, List<ISymbol> implementedVisi
var syntaxFacts = Document.GetLanguageService<ISyntaxFactsService>();
var addUnsafe = member.IsUnsafe() && !syntaxFacts.IsUnsafeContext(State.Location);
return GenerateMember(compilation, member, memberName, generateInvisibleMember, generateAbstractly, addNew, addUnsafe, cancellationToken);
return GenerateMember(
compilation, member, memberName, generateInvisibleMember, generateAbstractly,
addNew, addUnsafe, propertyGenerationBehavior, cancellationToken);
}
private bool GenerateInvisibleMember(ISymbol member, string memberName)
......@@ -376,6 +382,7 @@ private static bool IsUnexpressibleTypeParameter(ITypeParameterSymbol typeParame
bool generateAbstractly,
bool addNew,
bool addUnsafe,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
CancellationToken cancellationToken)
{
var factory = this.Document.GetLanguageService<SyntaxGenerator>();
......@@ -386,35 +393,28 @@ private static bool IsUnexpressibleTypeParameter(ITypeParameterSymbol typeParame
? Accessibility.Public
: Accessibility.Private;
if (member.Kind == SymbolKind.Method)
{
var method = (IMethodSymbol)member;
return GenerateMethod(compilation, method, accessibility, modifiers, generateAbstractly, useExplicitInterfaceSymbol, memberName, cancellationToken);
}
else if (member.Kind == SymbolKind.Property)
{
var property = (IPropertySymbol)member;
return GenerateProperty(compilation, property, accessibility, modifiers, generateAbstractly, useExplicitInterfaceSymbol, memberName, cancellationToken);
}
else if (member.Kind == SymbolKind.Event)
switch (member)
{
var @event = (IEventSymbol)member;
var accessor = CodeGenerationSymbolFactory.CreateAccessorSymbol(
attributes: default(ImmutableArray<AttributeData>),
accessibility: Accessibility.NotApplicable,
statements: factory.CreateThrowNotImplementedStatementBlock(compilation));
return CodeGenerationSymbolFactory.CreateEventSymbol(
@event,
accessibility: accessibility,
modifiers: modifiers,
explicitInterfaceSymbol: useExplicitInterfaceSymbol ? @event : null,
name: memberName,
addMethod: GetAddOrRemoveMethod(generateInvisibly, accessor, memberName, factory.AddEventHandler),
removeMethod: GetAddOrRemoveMethod(generateInvisibly, accessor, memberName, factory.RemoveEventHandler));
case IMethodSymbol method:
return GenerateMethod(compilation, method, accessibility, modifiers, generateAbstractly, useExplicitInterfaceSymbol, memberName, cancellationToken);
case IPropertySymbol property:
return GenerateProperty(compilation, property, accessibility, modifiers, generateAbstractly, useExplicitInterfaceSymbol, memberName, propertyGenerationBehavior, cancellationToken);
case IEventSymbol @event:
var accessor = CodeGenerationSymbolFactory.CreateAccessorSymbol(
attributes: default(ImmutableArray<AttributeData>),
accessibility: Accessibility.NotApplicable,
statements: factory.CreateThrowNotImplementedStatementBlock(compilation));
return CodeGenerationSymbolFactory.CreateEventSymbol(
@event,
accessibility: accessibility,
modifiers: modifiers,
explicitInterfaceSymbol: useExplicitInterfaceSymbol ? @event : null,
name: memberName,
addMethod: GetAddOrRemoveMethod(generateInvisibly, accessor, memberName, factory.AddEventHandler),
removeMethod: GetAddOrRemoveMethod(generateInvisibly, accessor, memberName, factory.RemoveEventHandler));
}
return null;
......
......@@ -7,6 +7,7 @@
using System.Threading;
using Microsoft.CodeAnalysis.CodeGeneration;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.ImplementType;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities;
......@@ -25,16 +26,19 @@ internal partial class ImplementInterfaceCodeAction
bool generateAbstractly,
bool useExplicitInterfaceSymbol,
string memberName,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
CancellationToken cancellationToken)
{
var factory = this.Document.GetLanguageService<SyntaxGenerator>();
var attributesToRemove = AttributesToRemove(compilation);
var getAccessor = GenerateGetAccessor(compilation, property, accessibility, generateAbstractly,
useExplicitInterfaceSymbol, attributesToRemove, cancellationToken);
var getAccessor = GenerateGetAccessor(
compilation, property, accessibility, generateAbstractly, useExplicitInterfaceSymbol,
propertyGenerationBehavior, attributesToRemove, cancellationToken);
var setAccessor = GenerateSetAccessor(compilation, property, accessibility,
generateAbstractly, useExplicitInterfaceSymbol, attributesToRemove, cancellationToken);
var setAccessor = GenerateSetAccessor(
compilation, property, accessibility, generateAbstractly, useExplicitInterfaceSymbol,
propertyGenerationBehavior, attributesToRemove, cancellationToken);
var syntaxFacts = Document.GetLanguageService<ISyntaxFactsService>();
var parameterNames = NameGenerator.EnsureUniqueness(
......@@ -73,6 +77,7 @@ private INamedTypeSymbol[] AttributesToRemove(Compilation compilation)
Accessibility accessibility,
bool generateAbstractly,
bool useExplicitInterfaceSymbol,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
INamedTypeSymbol[] attributesToRemove,
CancellationToken cancellationToken)
{
......@@ -81,6 +86,12 @@ private INamedTypeSymbol[] AttributesToRemove(Compilation compilation)
return null;
}
if (property.GetMethod == null)
{
// Can't have an auto-prop with just a setter.
propertyGenerationBehavior = ImplementTypePropertyGenerationBehavior.PreferThrowingProperties;
}
var setMethod = property.SetMethod.RemoveInaccessibleAttributesAndAttributesOfTypes(
this.State.ClassOrStructType,
attributesToRemove);
......@@ -90,7 +101,8 @@ private INamedTypeSymbol[] AttributesToRemove(Compilation compilation)
attributes: default(ImmutableArray<AttributeData>),
accessibility: accessibility,
explicitInterfaceSymbol: useExplicitInterfaceSymbol ? property.SetMethod : null,
statements: GetSetAccessorStatements(compilation, property, generateAbstractly, cancellationToken));
statements: GetSetAccessorStatements(
compilation, property, generateAbstractly, propertyGenerationBehavior, cancellationToken));
}
private IMethodSymbol GenerateGetAccessor(
......@@ -99,6 +111,7 @@ private INamedTypeSymbol[] AttributesToRemove(Compilation compilation)
Accessibility accessibility,
bool generateAbstractly,
bool useExplicitInterfaceSymbol,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
INamedTypeSymbol[] attributesToRemove,
CancellationToken cancellationToken)
{
......@@ -116,13 +129,15 @@ private INamedTypeSymbol[] AttributesToRemove(Compilation compilation)
attributes: default(ImmutableArray<AttributeData>),
accessibility: accessibility,
explicitInterfaceSymbol: useExplicitInterfaceSymbol ? property.GetMethod : null,
statements: GetGetAccessorStatements(compilation, property, generateAbstractly, cancellationToken));
statements: GetGetAccessorStatements(
compilation, property, generateAbstractly, propertyGenerationBehavior, cancellationToken));
}
private ImmutableArray<SyntaxNode> GetSetAccessorStatements(
Compilation compilation,
IPropertySymbol property,
bool generateAbstractly,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
CancellationToken cancellationToken)
{
if (generateAbstractly)
......@@ -157,13 +172,16 @@ private INamedTypeSymbol[] AttributesToRemove(Compilation compilation)
return ImmutableArray.Create(factory.ExpressionStatement(expression));
}
return factory.CreateThrowNotImplementedStatementBlock(compilation);
return propertyGenerationBehavior == ImplementTypePropertyGenerationBehavior.PreferAutoProperties
? default(ImmutableArray<SyntaxNode>)
: factory.CreateThrowNotImplementedStatementBlock(compilation);
}
private ImmutableArray<SyntaxNode> GetGetAccessorStatements(
Compilation compilation,
IPropertySymbol property,
bool generateAbstractly,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
CancellationToken cancellationToken)
{
if (generateAbstractly)
......@@ -196,8 +214,10 @@ private INamedTypeSymbol[] AttributesToRemove(Compilation compilation)
return ImmutableArray.Create(factory.ReturnStatement(expression));
}
return factory.CreateThrowNotImplementedStatementBlock(compilation);
return propertyGenerationBehavior == ImplementTypePropertyGenerationBehavior.PreferAutoProperties
? default(ImmutableArray<SyntaxNode>)
: factory.CreateThrowNotImplementedStatementBlock(compilation);
}
}
}
}
}
\ No newline at end of file
// 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.Linq;
using System.Threading;
......
......@@ -10,6 +10,12 @@ internal enum ImplementTypeInsertionBehavior
AtTheEnd = 1,
}
internal enum ImplementTypePropertyGenerationBehavior
{
PreferThrowingProperties = 0,
PreferAutoProperties = 1,
}
internal static class ImplementTypeOptions
{
public static readonly PerLanguageOption<ImplementTypeInsertionBehavior> InsertionBehavior =
......@@ -19,5 +25,14 @@ internal static class ImplementTypeOptions
defaultValue: ImplementTypeInsertionBehavior.WithOtherMembersOfTheSameKind,
storageLocations: new RoamingProfileStorageLocation(
$"TextEditor.%LANGUAGE%.{nameof(ImplementTypeOptions)}.{nameof(InsertionBehavior)}"));
public static readonly PerLanguageOption<ImplementTypePropertyGenerationBehavior> PropertyGenerationBehavior =
new PerLanguageOption<ImplementTypePropertyGenerationBehavior>(
nameof(ImplementTypeOptions),
nameof(PropertyGenerationBehavior),
defaultValue: ImplementTypePropertyGenerationBehavior.PreferThrowingProperties,
storageLocations: new RoamingProfileStorageLocation(
$"TextEditor.%LANGUAGE%.{nameof(ImplementTypeOptions)}.{nameof(PropertyGenerationBehavior)}"));
}
}
\ No newline at end of file
......@@ -100,6 +100,16 @@
x:Name="at_the_end"
Content="{x:Static local:AdvancedOptionPageStrings.Option_at_the_end}"/>
</StackPanel>
<Label Content="{x:Static local:AdvancedOptionPageStrings.Option_When_generating_properties}"/>
<StackPanel Margin="15, 0, 0, 0">
<RadioButton GroupName="Property_generation_behavior"
x:Name="prefer_throwing_properties"
Content="{x:Static local:AdvancedOptionPageStrings.Option_prefer_throwing_properties}"/>
<RadioButton GroupName="Property_generation_behavior"
x:Name="prefer_auto_properties"
Content="{x:Static local:AdvancedOptionPageStrings.Option_prefer_auto_properties}"/>
</StackPanel>
</StackPanel>
</GroupBox>
</StackPanel>
......
......@@ -48,6 +48,9 @@ public AdvancedOptionPageControl(IServiceProvider serviceProvider) : base(servic
BindToOption(with_other_members_of_the_same_kind, ImplementTypeOptions.InsertionBehavior, ImplementTypeInsertionBehavior.WithOtherMembersOfTheSameKind, LanguageNames.CSharp);
BindToOption(at_the_end, ImplementTypeOptions.InsertionBehavior, ImplementTypeInsertionBehavior.AtTheEnd, LanguageNames.CSharp);
BindToOption(prefer_throwing_properties, ImplementTypeOptions.PropertyGenerationBehavior, ImplementTypePropertyGenerationBehavior.PreferThrowingProperties, LanguageNames.CSharp);
BindToOption(prefer_auto_properties, ImplementTypeOptions.PropertyGenerationBehavior, ImplementTypePropertyGenerationBehavior.PreferAutoProperties, LanguageNames.CSharp);
}
}
}
\ No newline at end of file
......@@ -62,6 +62,15 @@ public static string Option_with_other_members_of_the_same_kind
public static string Option_at_the_end
=> ServicesVSResources.at_the_end;
public static string Option_When_generating_properties
=> ServicesVSResources.When_generating_properties;
public static string Option_prefer_auto_properties
=> ServicesVSResources.prefer_auto_properties;
public static string Option_prefer_throwing_properties
=> ServicesVSResources.prefer_throwing_properties;
public static string Option_GenerateXmlDocCommentsForTripleSlash
{
get { return CSharpVSResources.Generate_XML_documentation_comments_for; }
......
......@@ -1457,6 +1457,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to prefer auto properties.
/// </summary>
internal static string prefer_auto_properties {
get {
return ResourceManager.GetString("prefer_auto_properties", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Prefer braces.
/// </summary>
......@@ -1547,6 +1556,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to prefer throwing properties.
/// </summary>
internal static string prefer_throwing_properties {
get {
return ResourceManager.GetString("prefer_throwing_properties", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Preference.
/// </summary>
......@@ -2164,7 +2182,7 @@ internal class ServicesVSResources {
internal static string Unfortunately_a_process_used_by_Visual_Studio_has_encountered_an_unrecoverable_error_We_recommend_saving_your_work_and_then_closing_and_restarting_Visual_Studio {
get {
return ResourceManager.GetString("Unfortunately_a_process_used_by_Visual_Studio_has_encountered_an_unrecoverable_er" +
"ror_We_recommend_saving_your_work_and_then_closing_and_restarting_Visual Studio", resourceCulture);
"ror_We_recommend_saving_your_work_and_then_closing_and_restarting_Visual_Studio", resourceCulture);
}
}
......@@ -2332,6 +2350,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to When generating properties:.
/// </summary>
internal static string When_generating_properties {
get {
return ResourceManager.GetString("When_generating_properties", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to When inserting properties, events and methods, place them:.
/// </summary>
......
......@@ -873,7 +873,7 @@ Additional information: {1}</value>
<data name="Pick_members" xml:space="preserve">
<value>Pick members</value>
</data>
<data name="Unfortunately_a_process_used_by_Visual_Studio_has_encountered_an_unrecoverable_error_We_recommend_saving_your_work_and_then_closing_and_restarting_Visual Studio" xml:space="preserve">
<data name="Unfortunately_a_process_used_by_Visual_Studio_has_encountered_an_unrecoverable_error_We_recommend_saving_your_work_and_then_closing_and_restarting_Visual_Studio" xml:space="preserve">
<value>Unfortunately, a process used by Visual Studio has encountered an unrecoverable error. We recommend saving your work, and then closing and restarting Visual Studio.</value>
</data>
<data name="Add_a_symbol_specification" xml:space="preserve">
......@@ -900,6 +900,15 @@ Additional information: {1}</value>
<data name="VisualStudioWorkspace_TryApplyChanges_cannot_be_called_from_a_background_thread" xml:space="preserve">
<value>VisualStudioWorkspace.TryApplyChanges cannot be called from a background thread.</value>
</data>
<data name="prefer_auto_properties" xml:space="preserve">
<value>prefer auto properties</value>
</data>
<data name="prefer_throwing_properties" xml:space="preserve">
<value>prefer throwing properties</value>
</data>
<data name="When_generating_properties" xml:space="preserve">
<value>When generating properties:</value>
</data>
<data name="Options" xml:space="preserve">
<value>Options</value>
</data>
......
......@@ -110,6 +110,16 @@
x:Name="at_the_end"
Content="{x:Static local:AdvancedOptionPageStrings.Option_at_the_end}"/>
</StackPanel>
<Label Content="{x:Static local:AdvancedOptionPageStrings.Option_When_generating_properties}"/>
<StackPanel Margin="15, 0, 0, 0">
<RadioButton GroupName="Property_generation_behavior"
x:Name="prefer_throwing_properties"
Content="{x:Static local:AdvancedOptionPageStrings.Option_prefer_throwing_properties}"/>
<RadioButton GroupName="Property_generation_behavior"
x:Name="prefer_auto_properties"
Content="{x:Static local:AdvancedOptionPageStrings.Option_prefer_auto_properties}"/>
</StackPanel>
</StackPanel>
</GroupBox>
......
......@@ -45,6 +45,9 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
BindToOption(with_other_members_of_the_same_kind, ImplementTypeOptions.InsertionBehavior, ImplementTypeInsertionBehavior.WithOtherMembersOfTheSameKind, LanguageNames.VisualBasic)
BindToOption(at_the_end, ImplementTypeOptions.InsertionBehavior, ImplementTypeInsertionBehavior.AtTheEnd, LanguageNames.VisualBasic)
BindToOption(prefer_throwing_properties, ImplementTypeOptions.PropertyGenerationBehavior, ImplementTypePropertyGenerationBehavior.PreferThrowingProperties, LanguageNames.VisualBasic)
BindToOption(prefer_auto_properties, ImplementTypeOptions.PropertyGenerationBehavior, ImplementTypePropertyGenerationBehavior.PreferAutoProperties, LanguageNames.VisualBasic)
End Sub
End Class
End Namespace
\ No newline at end of file
......@@ -84,6 +84,15 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
Public ReadOnly Property Option_with_other_members_of_the_same_kind As String =
ServicesVSResources.with_other_members_of_the_same_kind
Public ReadOnly Property Option_When_generating_properties As String =
ServicesVSResources.When_generating_properties
Public ReadOnly Property Option_prefer_auto_properties As String =
ServicesVSResources.prefer_auto_properties
Public ReadOnly Property Option_prefer_throwing_properties As String =
ServicesVSResources.prefer_throwing_properties
Public ReadOnly Property Option_at_the_end As String =
ServicesVSResources.at_the_end
......
......@@ -246,18 +246,27 @@ public PatternMatches GetMatches(string candidate, string dottedContainer)
/// so, unless you need to know the full set of matches, use this version.
/// </remarks>
/// <param name="candidate">The word being tested.</param>
/// <param name="inludeMatchSpans">Whether or not the matched spans should be included with results</param>
/// <param name="includeMatchSpans">Whether or not the matched spans should be included with results</param>
/// <returns>If this was a match, the first element of the set of match types that occurred while matching the
/// patterns. If it was not a match, it returns null.</returns>
public PatternMatch? GetFirstMatch(string candidate, bool inludeMatchSpans = false)
public PatternMatch? GetFirstMatch(
string candidate, bool includeMatchSpans)
{
if (SkipMatch(candidate))
{
return null;
}
return MatchPatternSegment(candidate, inludeMatchSpans, _fullPatternSegment, wantAllMatches: false, allMatches: out _, fuzzyMatch: false) ??
MatchPatternSegment(candidate, inludeMatchSpans, _fullPatternSegment, wantAllMatches: false, allMatches: out _, fuzzyMatch: true);
return GetFirstMatchWorker(candidate, includeMatchSpans, fuzzyMatch: false) ??
GetFirstMatchWorker(candidate, includeMatchSpans, fuzzyMatch: true);
}
private PatternMatch? GetFirstMatchWorker(
string candidate, bool includeMatchSpans, bool fuzzyMatch)
{
return MatchPatternSegment(
candidate, includeMatchSpans, _fullPatternSegment,
wantAllMatches: false, allMatches: out _, fuzzyMatch: fuzzyMatch);
}
private StringBreaks GetWordSpans(string word)
......@@ -268,13 +277,6 @@ private StringBreaks GetWordSpans(string word)
}
}
internal PatternMatch? MatchSingleWordPattern_ForTestingOnly(string candidate)
{
return MatchPatternChunk(candidate, includeMatchSpans: true,
patternChunk: _fullPatternSegment.TotalTextChunk, punctuationStripped: false,
fuzzyMatch: false);
}
private static bool ContainsUpperCaseLetter(string pattern)
{
// Expansion of "foreach(char ch in pattern)" to avoid a CharEnumerator allocation
......@@ -443,12 +445,10 @@ private static bool ContainsSpaceOrAsterisk(string text)
var singleMatch = MatchPatternSegment(candidate, includeMatchSpans, patternSegment,
wantAllMatches: true, fuzzyMatch: fuzzyMatch, allMatches: out var matches);
if (singleMatch.HasValue)
{
return ImmutableArray.Create(singleMatch.Value);
}
return matches;
return singleMatch.HasValue
? ImmutableArray.Create(singleMatch.Value)
: matches;
}
/// <summary>
......@@ -554,17 +554,18 @@ private static bool ContainsSpaceOrAsterisk(string text)
return null;
}
if (!wantAllMatches || subWordTextChunks.Length == 1)
{
// Stop at the first word
return result;
}
matches.Add(result.Value);
}
allMatches = matches.ToImmutable();
return null;
if (wantAllMatches && matches.Count >= 2)
{
allMatches = matches.ToImmutable();
return null;
}
else
{
return matches.FirstOrNullable();
}
}
finally
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册