diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/AbstractCSharpAutoPropertyCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/AbstractCSharpAutoPropertyCompletionProviderTests.cs
new file mode 100644
index 0000000000000..d1be6609f3414
--- /dev/null
+++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/AbstractCSharpAutoPropertyCompletionProviderTests.cs
@@ -0,0 +1,148 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Test.Utilities;
+using Microsoft.CodeAnalysis.Testing;
+using Roslyn.Test.Utilities;
+using Xunit;
+
+namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets
+{
+ public abstract class AbstractCSharpAutoPropertyCompletionProviderTests : AbstractCSharpSnippetCompletionProviderTests
+ {
+ protected abstract string GetDefaultPropertyText(string propertyName);
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)]
+ public async Task MissingInNamespace()
+ {
+ await VerifyPropertyAbsenceAsync("""
+ namespace Namespace
+ {
+ $$
+ }
+ """);
+ }
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)]
+ public async Task MissingInFilescopedNamespace()
+ {
+ await VerifyPropertyAbsenceAsync("""
+ namespace Namespace;
+
+ $$
+ """);
+ }
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)]
+ public async Task MissingInTopLevelContext()
+ {
+ await VerifyPropertyAbsenceAsync("""
+ System.Console.WriteLine();
+ $$
+ """);
+ }
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)]
+ public async Task InsertSnippetInClass()
+ {
+ await VerifyDefaultPropertyAsync("""
+ class MyClass
+ {
+ $$
+ }
+ """);
+ }
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)]
+ public async Task InsertSnippetInRecord()
+ {
+ await VerifyDefaultPropertyAsync("""
+ record MyRecord
+ {
+ $$
+ }
+ """);
+ }
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)]
+ public async Task InsertSnippetInStruct()
+ {
+ await VerifyDefaultPropertyAsync("""
+ struct MyStruct
+ {
+ $$
+ }
+ """);
+ }
+
+ // This case might produce non-default results for different snippets (e.g. no `set` accessor in 'propg' snippet),
+ // so it is tested separately for all of them
+ [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)]
+ public abstract Task InsertSnippetInInterface();
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)]
+ public async Task InsertSnippetNaming()
+ {
+ await VerifyDefaultPropertyAsync("""
+ class MyClass
+ {
+ public int MyProperty { get; set; }
+ $$
+ }
+ """, "MyProperty1");
+ }
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)]
+ public async Task MissingInEnum()
+ {
+ await VerifyPropertyAbsenceAsync("""
+ enum MyEnum
+ {
+ $$
+ }
+ """);
+ }
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)]
+ public async Task MissingInMethod()
+ {
+ await VerifyPropertyAbsenceAsync("""
+ class Program
+ {
+ public void Method()
+ {
+ $$
+ }
+ }
+ """);
+ }
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)]
+ public async Task MissingInConstructor()
+ {
+ await VerifyPropertyAbsenceAsync("""
+ class Program
+ {
+ public Program()
+ {
+ $$
+ }
+ }
+ """);
+ }
+
+ private Task VerifyPropertyAbsenceAsync(string markup) => VerifyItemIsAbsentAsync(markup, ItemToCommit);
+
+ protected async Task VerifyPropertyAsync(string markup, string propertyText)
+ {
+ TestFileMarkupParser.GetPosition(markup, out var code, out var position);
+ var expectedCode = code.Insert(position, propertyText + "$$");
+ await VerifyCustomCommitProviderAsync(markup, ItemToCommit, expectedCode);
+ }
+
+ protected Task VerifyDefaultPropertyAsync(string markup, string propertyName = "MyProperty")
+ => VerifyPropertyAsync(markup, GetDefaultPropertyText(propertyName));
+ }
+}
diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpPropSnippetCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpPropSnippetCompletionProviderTests.cs
index 63110bcf0a40a..f2898d3713c9e 100644
--- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpPropSnippetCompletionProviderTests.cs
+++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpPropSnippetCompletionProviderTests.cs
@@ -2,179 +2,25 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
using System.Threading.Tasks;
-using Microsoft.CodeAnalysis.Test.Utilities;
-using Roslyn.Test.Utilities;
-using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets
{
- public class CSharpPropSnippetCompletionProviderTests : AbstractCSharpSnippetCompletionProviderTests
+ public class CSharpPropSnippetCompletionProviderTests : AbstractCSharpAutoPropertyCompletionProviderTests
{
protected override string ItemToCommit => "prop";
- [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)]
- public async Task PropSnippetMissingInNamespace()
- {
- var markupBeforeCommit =
-@"namespace Namespace
-{
- $$
-}";
-
- await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit);
- }
+ protected override string GetDefaultPropertyText(string propertyName)
+ => $"public int {propertyName} {{ get; set; }}";
- [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)]
- public async Task PropSnippetMissingInFilescopedNamespace()
+ public override async Task InsertSnippetInInterface()
{
- var markupBeforeCommit =
-@"namespace Namespace;
-
-$$";
-
- await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit);
- }
-
- [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)]
- public async Task PropSnippetMissingInTopLevelContext()
- {
- var markupBeforeCommit =
-@"System.Console.WriteLine();
-$$";
-
- await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit);
- }
-
- [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)]
- public async Task InsertPropSnippetInClassTest()
- {
- var markupBeforeCommit =
-@"class MyClass
-{
- $$
-}";
-
- var expectedCodeAfterCommit =
-@"class MyClass
-{
- public int MyProperty { get; set; }$$
-}";
- await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit);
- }
-
- [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)]
- public async Task InsertPropSnippetInRecordTest()
- {
- var markupBeforeCommit =
-@"record MyRecord
-{
- $$
-}";
-
- var expectedCodeAfterCommit =
-@"record MyRecord
-{
- public int MyProperty { get; set; }$$
-}";
- await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit);
- }
-
- [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)]
- public async Task InsertPropSnippetInStructTest()
- {
- var markupBeforeCommit =
-@"struct MyStruct
-{
- $$
-}";
-
- var expectedCodeAfterCommit =
-@"struct MyStruct
-{
- public int MyProperty { get; set; }$$
-}";
- await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit);
- }
-
- [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)]
- public async Task InsertPropSnippetInInterfaceTest()
- {
- var markupBeforeCommit =
-@"interface MyInterface
-{
- $$
-}";
-
- var expectedCodeAfterCommit =
-@"interface MyInterface
-{
- public int MyProperty { get; set; }$$
-}";
- await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit);
- }
-
- [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)]
- public async Task InsertPropSnippetNamingTest()
- {
- var markupBeforeCommit =
-@"class MyClass
-{
- public int MyProperty { get; set; }
- $$
-}";
-
- var expectedCodeAfterCommit =
-@"class MyClass
-{
- public int MyProperty { get; set; }
- public int MyProperty1 { get; set; }$$
-}";
- await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit);
- }
-
- [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)]
- public async Task NoPropSnippetInEnumTest()
- {
- var markupBeforeCommit =
-@"enum MyEnum
-{
- $$
-}";
-
- await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit);
- }
-
- [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)]
- public async Task NoPropSnippetInMethodTest()
- {
- var markupBeforeCommit =
-@"class Program
-{
- public void Method()
- {
- $$
- }
-}";
- await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit);
- }
-
- [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)]
- public async Task NoPropSnippetInConstructorTest()
- {
- var markupBeforeCommit =
-@"class Program
-{
- public Program()
- {
- $$
- }
-}";
- await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit);
+ await VerifyDefaultPropertyAsync("""
+ interface MyInterface
+ {
+ $$
+ }
+ """);
}
}
}
diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpPropgSnippetCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpPropgSnippetCompletionProviderTests.cs
new file mode 100644
index 0000000000000..945b47bbe0323
--- /dev/null
+++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpPropgSnippetCompletionProviderTests.cs
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading.Tasks;
+
+namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets
+{
+ public class CSharpPropgSnippetCompletionProviderTests : AbstractCSharpAutoPropertyCompletionProviderTests
+ {
+ protected override string ItemToCommit => "propg";
+
+ protected override string GetDefaultPropertyText(string propertyName)
+ => $"public int {propertyName} {{ get; private set; }}";
+
+ public override async Task InsertSnippetInInterface()
+ {
+ // Ensure we don't generate redundant `set` accessor when executed in interface
+ await VerifyPropertyAsync("""
+ interface MyInterface
+ {
+ $$
+ }
+ """, "public int MyProperty { get; }");
+ }
+ }
+}
diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpPropiSnippetCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpPropiSnippetCompletionProviderTests.cs
new file mode 100644
index 0000000000000..685ce642be9cf
--- /dev/null
+++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpPropiSnippetCompletionProviderTests.cs
@@ -0,0 +1,26 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading.Tasks;
+
+namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets
+{
+ public class CSharpPropiSnippetCompletionProviderTests : AbstractCSharpAutoPropertyCompletionProviderTests
+ {
+ protected override string ItemToCommit => "propi";
+
+ protected override string GetDefaultPropertyText(string propertyName)
+ => $"public int {propertyName} {{ get; init; }}";
+
+ public override async Task InsertSnippetInInterface()
+ {
+ await VerifyDefaultPropertyAsync("""
+ interface MyInterface
+ {
+ $$
+ }
+ """);
+ }
+ }
+}
diff --git a/src/Features/CSharp/Portable/CSharpFeaturesResources.resx b/src/Features/CSharp/Portable/CSharpFeaturesResources.resx
index 97f4896fe310a..377ba2099a93f 100644
--- a/src/Features/CSharp/Portable/CSharpFeaturesResources.resx
+++ b/src/Features/CSharp/Portable/CSharpFeaturesResources.resx
@@ -638,4 +638,7 @@
Selection cannot be in constructor initializer
+
+ init-only property
+
\ No newline at end of file
diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/SnippetCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/SnippetCompletionProvider.cs
index 78acc22d76182..2ef9aa564b822 100644
--- a/src/Features/CSharp/Portable/Completion/CompletionProviders/SnippetCompletionProvider.cs
+++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/SnippetCompletionProvider.cs
@@ -33,7 +33,7 @@ internal sealed class SnippetCompletionProvider : LSPCompletionProvider
{
private static readonly HashSet s_snippetsWithReplacements = new()
{
- "class", "cw", "ctor", "else", "foreach", "if", "interface", "prop", "struct", "while"
+ "class", "cw", "ctor", "else", "foreach", "if", "interface", "prop", "propg", "struct", "while"
};
internal override bool IsSnippetProvider => true;
diff --git a/src/Features/CSharp/Portable/Snippets/AbstractCSharpAutoPropertySnippetProvider.cs b/src/Features/CSharp/Portable/Snippets/AbstractCSharpAutoPropertySnippetProvider.cs
new file mode 100644
index 0000000000000..f16024c9a023a
--- /dev/null
+++ b/src/Features/CSharp/Portable/Snippets/AbstractCSharpAutoPropertySnippetProvider.cs
@@ -0,0 +1,83 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Immutable;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.CSharp.Extensions;
+using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.CSharp.Utilities;
+using Microsoft.CodeAnalysis.Editing;
+using Microsoft.CodeAnalysis.LanguageService;
+using Microsoft.CodeAnalysis.PooledObjects;
+using Microsoft.CodeAnalysis.Shared.Extensions;
+using Microsoft.CodeAnalysis.Shared.Utilities;
+using Microsoft.CodeAnalysis.Snippets;
+using Microsoft.CodeAnalysis.Snippets.SnippetProviders;
+using Microsoft.CodeAnalysis.Text;
+using Roslyn.Utilities;
+
+namespace Microsoft.CodeAnalysis.CSharp.Snippets
+{
+ internal abstract class AbstractCSharpAutoPropertySnippetProvider : AbstractPropertySnippetProvider
+ {
+ protected virtual AccessorDeclarationSyntax? GenerateGetAccessorDeclaration(CSharpSyntaxContext syntaxContext, SyntaxGenerator generator)
+ => (AccessorDeclarationSyntax)generator.GetAccessorDeclaration();
+
+ protected virtual AccessorDeclarationSyntax? GenerateSetAccessorDeclaration(CSharpSyntaxContext syntaxContext, SyntaxGenerator generator)
+ => (AccessorDeclarationSyntax)generator.SetAccessorDeclaration();
+
+ protected override async Task IsValidSnippetLocationAsync(Document document, int position, CancellationToken cancellationToken)
+ {
+ var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
+ Contract.ThrowIfNull(syntaxTree);
+
+ return syntaxTree.IsMemberDeclarationContext(position, contextOpt: null,
+ SyntaxKindSet.AllMemberModifiers, SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, canBePartial: true, cancellationToken);
+ }
+
+ protected override async Task GenerateSnippetSyntaxAsync(Document document, int position, CancellationToken cancellationToken)
+ {
+ var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false);
+ var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);
+ var generator = SyntaxGenerator.GetGenerator(document);
+ var identifierName = NameGenerator.GenerateUniqueName("MyProperty",
+ n => semanticModel.LookupSymbols(position, name: n).IsEmpty);
+ var syntaxContext = CSharpSyntaxContext.CreateContext(document, semanticModel, position, cancellationToken);
+ var accessors = new AccessorDeclarationSyntax?[]
+ {
+ GenerateGetAccessorDeclaration(syntaxContext, generator),
+ GenerateSetAccessorDeclaration(syntaxContext, generator),
+ };
+
+ return SyntaxFactory.PropertyDeclaration(
+ attributeLists: default,
+ modifiers: SyntaxTokenList.Create(SyntaxFactory.Token(SyntaxKind.PublicKeyword)),
+ type: compilation.GetSpecialType(SpecialType.System_Int32).GenerateTypeSyntax(allowVar: false),
+ explicitInterfaceSpecifier: null,
+ identifier: identifierName.ToIdentifierToken(),
+ accessorList: SyntaxFactory.AccessorList(new SyntaxList(accessors.Where(a => a is not null)!)));
+ }
+
+ protected override int GetTargetCaretPosition(ISyntaxFactsService syntaxFacts, SyntaxNode caretTarget, SourceText sourceText)
+ {
+ var propertyDeclaration = (PropertyDeclarationSyntax)caretTarget;
+ return propertyDeclaration.AccessorList!.CloseBraceToken.Span.End;
+ }
+
+ protected override ImmutableArray GetPlaceHolderLocationsList(SyntaxNode node, ISyntaxFacts syntaxFacts, CancellationToken cancellationToken)
+ {
+ using var _ = ArrayBuilder.GetInstance(out var arrayBuilder);
+ var propertyDeclaration = (PropertyDeclarationSyntax)node;
+ var identifier = propertyDeclaration.Identifier;
+ var type = propertyDeclaration.Type;
+
+ arrayBuilder.Add(new SnippetPlaceholder(identifier: type.ToString(), placeholderPositions: ImmutableArray.Create(type.SpanStart)));
+ arrayBuilder.Add(new SnippetPlaceholder(identifier: identifier.ValueText, placeholderPositions: ImmutableArray.Create(identifier.SpanStart)));
+ return arrayBuilder.ToImmutableArray();
+ }
+ }
+}
diff --git a/src/Features/CSharp/Portable/Snippets/CSharpPropSnippetProvider.cs b/src/Features/CSharp/Portable/Snippets/CSharpPropSnippetProvider.cs
index f592e2ce742f5..1b71cfd7d85b7 100644
--- a/src/Features/CSharp/Portable/Snippets/CSharpPropSnippetProvider.cs
+++ b/src/Features/CSharp/Portable/Snippets/CSharpPropSnippetProvider.cs
@@ -3,78 +3,24 @@
// See the LICENSE file in the project root for more information.
using System;
-using System.Collections.Generic;
using System.Composition;
-using System.Text;
-using Microsoft.CodeAnalysis.Shared.Extensions;
-using System.Threading.Tasks;
-using System.Threading;
+using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Snippets;
using Microsoft.CodeAnalysis.Snippets.SnippetProviders;
-using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery;
-using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery;
-using Microsoft.CodeAnalysis.CSharp.Utilities;
-using Microsoft.CodeAnalysis.Host.Mef;
-using Roslyn.Utilities;
-using System.Collections.Immutable;
-using Microsoft.CodeAnalysis.Text;
-using Microsoft.CodeAnalysis.Editing;
-using Microsoft.CodeAnalysis.Shared.Utilities;
-using Microsoft.CodeAnalysis.CSharp.Extensions;
-using Microsoft.CodeAnalysis.LanguageService;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Microsoft.CodeAnalysis.PooledObjects;
namespace Microsoft.CodeAnalysis.CSharp.Snippets
{
[ExportSnippetProvider(nameof(ISnippetProvider), LanguageNames.CSharp), Shared]
- internal sealed class CSharpPropSnippetProvider : AbstractPropSnippetProvider
+ internal sealed class CSharpPropSnippetProvider : AbstractCSharpAutoPropertySnippetProvider
{
-
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public CSharpPropSnippetProvider()
{
}
- protected override async Task IsValidSnippetLocationAsync(Document document, int position, CancellationToken cancellationToken)
- {
- var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
- Contract.ThrowIfNull(syntaxTree);
-
- return syntaxTree.IsMemberDeclarationContext(position, contextOpt: null,
- SyntaxKindSet.AllMemberModifiers, SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, canBePartial: true, cancellationToken);
- }
+ public override string Identifier => "prop";
- protected override async Task GenerateSnippetSyntaxAsync(Document document, int position, CancellationToken cancellationToken)
- {
- var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false);
- var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);
- var generator = SyntaxGenerator.GetGenerator(document);
- var identifierName = NameGenerator.GenerateUniqueName("MyProperty",
- n => semanticModel.LookupSymbols(position, name: n).IsEmpty);
- return generator.PropertyDeclaration(
- name: identifierName,
- type: compilation.GetSpecialType(SpecialType.System_Int32).GenerateTypeSyntax(allowVar: false),
- accessibility: Accessibility.Public);
- }
-
- protected override int GetTargetCaretPosition(ISyntaxFactsService syntaxFacts, SyntaxNode caretTarget, SourceText sourceText)
- {
- var propertyDeclaration = (PropertyDeclarationSyntax)caretTarget;
- return propertyDeclaration.AccessorList!.CloseBraceToken.Span.End;
- }
-
- protected override ImmutableArray GetPlaceHolderLocationsList(SyntaxNode node, ISyntaxFacts syntaxFacts, CancellationToken cancellationToken)
- {
- using var _ = ArrayBuilder.GetInstance(out var arrayBuilder);
- var propertyDeclaration = (PropertyDeclarationSyntax)node;
- var identifier = propertyDeclaration.Identifier;
- var type = propertyDeclaration.Type;
-
- arrayBuilder.Add(new SnippetPlaceholder(identifier: type.ToString(), placeholderPositions: ImmutableArray.Create(type.SpanStart)));
- arrayBuilder.Add(new SnippetPlaceholder(identifier: identifier.ValueText, placeholderPositions: ImmutableArray.Create(identifier.SpanStart)));
- return arrayBuilder.ToImmutableArray();
- }
+ public override string Description => FeaturesResources.property_;
}
}
diff --git a/src/Features/CSharp/Portable/Snippets/CSharpPropgSnippetProvider.cs b/src/Features/CSharp/Portable/Snippets/CSharpPropgSnippetProvider.cs
new file mode 100644
index 0000000000000..ff1ab2c2e9161
--- /dev/null
+++ b/src/Features/CSharp/Portable/Snippets/CSharpPropgSnippetProvider.cs
@@ -0,0 +1,42 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Composition;
+using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Editing;
+using Microsoft.CodeAnalysis.Host.Mef;
+using Microsoft.CodeAnalysis.Snippets;
+using Microsoft.CodeAnalysis.Snippets.SnippetProviders;
+
+namespace Microsoft.CodeAnalysis.CSharp.Snippets
+{
+ [ExportSnippetProvider(nameof(ISnippetProvider), LanguageNames.CSharp), Shared]
+ internal class CSharpPropgSnippetProvider : AbstractCSharpAutoPropertySnippetProvider
+ {
+ [ImportingConstructor]
+ [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
+ public CSharpPropgSnippetProvider()
+ {
+ }
+
+ public override string Identifier => "propg";
+
+ public override string Description => FeaturesResources.get_only_property;
+
+ protected override AccessorDeclarationSyntax? GenerateSetAccessorDeclaration(CSharpSyntaxContext syntaxContext, SyntaxGenerator generator)
+ {
+ // Interface cannot have properties with `private set` accessor.
+ // So if we are inside an interface, we just return null here.
+ // This causes the caller to just skip this `set` accessor
+ if (syntaxContext.ContainingTypeDeclaration is InterfaceDeclarationSyntax)
+ {
+ return null;
+ }
+
+ return (AccessorDeclarationSyntax)generator.SetAccessorDeclaration(Accessibility.Private);
+ }
+ }
+}
diff --git a/src/Features/CSharp/Portable/Snippets/CSharpPropiSnippetProvider.cs b/src/Features/CSharp/Portable/Snippets/CSharpPropiSnippetProvider.cs
new file mode 100644
index 0000000000000..20ffc714b1efc
--- /dev/null
+++ b/src/Features/CSharp/Portable/Snippets/CSharpPropiSnippetProvider.cs
@@ -0,0 +1,32 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Composition;
+using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Editing;
+using Microsoft.CodeAnalysis.Host.Mef;
+using Microsoft.CodeAnalysis.Snippets;
+using Microsoft.CodeAnalysis.Snippets.SnippetProviders;
+
+namespace Microsoft.CodeAnalysis.CSharp.Snippets
+{
+ [ExportSnippetProvider(nameof(ISnippetProvider), LanguageNames.CSharp), Shared]
+ internal class CSharpPropiSnippetProvider : AbstractCSharpAutoPropertySnippetProvider
+ {
+ [ImportingConstructor]
+ [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
+ public CSharpPropiSnippetProvider()
+ {
+ }
+
+ public override string Identifier => "propi";
+
+ public override string Description => CSharpFeaturesResources.init_only_property;
+
+ protected override AccessorDeclarationSyntax? GenerateSetAccessorDeclaration(CSharpSyntaxContext syntaxContext, SyntaxGenerator generator)
+ => SyntaxFactory.AccessorDeclaration(SyntaxKind.InitAccessorDeclaration).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken));
+ }
+}
diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf
index a6ad57fce8269..aed887d0e2fc7 100644
--- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf
+++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf
@@ -282,6 +282,11 @@
externí alias
+
+
+ init-only property
+
+
<lambda výraz>
diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf
index 0a111b4903b01..2a13d115c1274 100644
--- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf
+++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf
@@ -282,6 +282,11 @@
externer Alias
+
+
+ init-only property
+
+
<Lambdaausdruck>
diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf
index 4557a09eda8ce..35b8e0cd832ef 100644
--- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf
+++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf
@@ -282,6 +282,11 @@
alias externo
+
+
+ init-only property
+
+
<expresión lambda>
diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf
index 9aed46ba38503..3a7e4ae8f9968 100644
--- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf
+++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf
@@ -282,6 +282,11 @@
alias externe
+
+
+ init-only property
+
+
<expression lambda>
diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf
index 71344adf88cb8..17e8b195a4bff 100644
--- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf
+++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf
@@ -282,6 +282,11 @@
alias extern
+
+
+ init-only property
+
+
<espressione lambda>
diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf
index 2e8462fedbed8..f7a52ae29b582 100644
--- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf
+++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf
@@ -282,6 +282,11 @@
extern エイリアス
+
+
+ init-only property
+
+
<ラムダ式>
diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf
index 914e6b3e8054d..b289b88f548a0 100644
--- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf
+++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf
@@ -282,6 +282,11 @@
extern 별칭
+
+
+ init-only property
+
+
<람다 식>
diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf
index b24a9128f4d42..0f76a512d0421 100644
--- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf
+++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf
@@ -282,6 +282,11 @@
alias zewnętrzny
+
+
+ init-only property
+
+
<wyrażenie lambda>
diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf
index ed76b1ba03d4a..51355e0a09c1b 100644
--- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf
+++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf
@@ -282,6 +282,11 @@
alias externo
+
+
+ init-only property
+
+
<expressão lambda>
diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf
index 4018387aea7ea..62e212d8d45c8 100644
--- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf
+++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf
@@ -282,6 +282,11 @@
внешний псевдоним
+
+
+ init-only property
+
+
<лямбда-выражение>
diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf
index 2280b4a44d90d..562a625ce1e6a 100644
--- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf
+++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf
@@ -282,6 +282,11 @@
dış diğer ad
+
+
+ init-only property
+
+
<lambda ifadesi>
diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf
index c4666685a7c52..d656fe4d39b2d 100644
--- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf
+++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf
@@ -282,6 +282,11 @@
外部别名
+
+
+ init-only property
+
+
<lambda 表达式>
diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf
index 38312939a98be..e756d692150ad 100644
--- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf
+++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf
@@ -282,6 +282,11 @@
外部別名
+
+
+ init-only property
+
+
<Lambda 運算式>
diff --git a/src/Features/Core/Portable/FeaturesResources.resx b/src/Features/Core/Portable/FeaturesResources.resx
index 2d8ac9097ea10..121237ade2117 100644
--- a/src/Features/Core/Portable/FeaturesResources.resx
+++ b/src/Features/Core/Portable/FeaturesResources.resx
@@ -3203,6 +3203,9 @@ Zero-width positive lookbehind assertions are typically used at the beginning of
You must rename an identifier.
+
+ get-only property
+
This {0} has {1} reference(s).
diff --git a/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractPropSnippetProvider.cs b/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractPropertySnippetProvider.cs
similarity index 87%
rename from src/Features/Core/Portable/Snippets/SnippetProviders/AbstractPropSnippetProvider.cs
rename to src/Features/Core/Portable/Snippets/SnippetProviders/AbstractPropertySnippetProvider.cs
index e3605b38399e2..0e25000800f12 100644
--- a/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractPropSnippetProvider.cs
+++ b/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractPropertySnippetProvider.cs
@@ -11,12 +11,8 @@
namespace Microsoft.CodeAnalysis.Snippets.SnippetProviders
{
- internal abstract class AbstractPropSnippetProvider : AbstractSnippetProvider
+ internal abstract class AbstractPropertySnippetProvider : AbstractSnippetProvider
{
- public override string Identifier => "prop";
-
- public override string Description => FeaturesResources.property_;
-
///
/// Generates the property syntax.
/// Requires language specificity for the TypeSyntax as well as the
diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf
index bc31ff63f20d4..0669cd7d4a621 100644
--- a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf
+++ b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf
@@ -3562,6 +3562,11 @@ Specifikátor standardního formátu f představuje kombinaci vzorů dlouhého d
obecná přetížení
+
+
+ get-only property
+
+
příkaz if
diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf
index 1a48783f68691..e3f405720990b 100644
--- a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf
+++ b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf
@@ -3562,6 +3562,11 @@ Der Standardformatbezeichner "f" repräsentiert eine Kombination aus den Mustern
generische Überladungen
+
+
+ get-only property
+
+
Wenn-Anweisung
diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf
index ac25e0fb45ee3..6df1a95330dad 100644
--- a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf
+++ b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf
@@ -3562,6 +3562,11 @@ El especificador de formato estándar "f" representa una combinación de los pat
sobrecargas genéricas
+
+
+ get-only property
+
+
instrucción if
diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf
index bc2e0af73cd44..8e715b1011fd1 100644
--- a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf
+++ b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf
@@ -3562,6 +3562,11 @@ Le spécificateur de format standard "f" représente une combinaison des modèle
surcharges génériques
+
+
+ get-only property
+
+
si l’instruction
diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf
index 4b4c494c261fa..65b2790800857 100644
--- a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf
+++ b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf
@@ -3562,6 +3562,11 @@ L'identificatore di formato standard "f" rappresenta una combinazione degli sche
overload generici
+
+
+ get-only property
+
+
istruzione if
diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf
index f74e9ae03870b..cacc9c41b5608 100644
--- a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf
+++ b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf
@@ -3562,6 +3562,11 @@ The "f" standard format specifier represents a combination of the long date ("D"
ジェネリック オーバーロード
+
+
+ get-only property
+
+
If ステートメント
diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf
index c3b2e6d8b7e0d..031e1ab60e9ef 100644
--- a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf
+++ b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf
@@ -3562,6 +3562,11 @@ The "f" standard format specifier represents a combination of the long date ("D"
제네릭 오버로드
+
+
+ get-only property
+
+
If 문
diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf
index 1450cf591c28b..cdf9f785dfdc3 100644
--- a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf
+++ b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf
@@ -3562,6 +3562,11 @@ Standardowy specyfikator formatu „f” reprezentuje połączenie wzorców dłu
przeciążenia ogólne
+
+
+ get-only property
+
+
instrukcja if
diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf
index b61fa17ccbf12..9648ea78b3044 100644
--- a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf
+++ b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf
@@ -3562,6 +3562,11 @@ O especificador de formato padrão "f" representa uma combinação de padrões d
sobrecargas genéricas
+
+
+ get-only property
+
+
instrução if
diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf
index 2a2ecf6812330..2de08fbb9e2db 100644
--- a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf
+++ b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf
@@ -3562,6 +3562,11 @@ The "f" standard format specifier represents a combination of the long date ("D"
универсальные перегрузки
+
+
+ get-only property
+
+
оператор if
diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf
index 290eb85b69fd8..294f336ecfbe2 100644
--- a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf
+++ b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf
@@ -3562,6 +3562,11 @@ The "f" standard format specifier represents a combination of the long date ("D"
genel aşırı yüklemeler
+
+
+ get-only property
+
+
If deyimi
diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf
index 038a482bee185..4d35c80c7bad6 100644
--- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf
+++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf
@@ -3562,6 +3562,11 @@ The "f" standard format specifier represents a combination of the long date ("D"
多个泛型重载
+
+
+ get-only property
+
+
If 语句
diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf
index 53995d6760947..f6f59b303dda8 100644
--- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf
+++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf
@@ -3562,6 +3562,11 @@ The "f" standard format specifier represents a combination of the long date ("D"
泛型多載
+
+
+ get-only property
+
+
If 陳述式