From 2251e869e6eb2c2ffe48286fcb8585caeb7f66df Mon Sep 17 00:00:00 2001 From: akhera99 Date: Wed, 14 Sep 2022 12:00:53 -0700 Subject: [PATCH 1/2] struct + a lot of abstracting --- .../Snippets/CSharpClassSnippetProvider.cs | 81 +++----------- .../Snippets/CSharpStructSnippetProvider.cs | 65 +++++++++++ .../Snippets/CSharpTypeSnippetProvider.cs | 101 ++++++++++++++++++ .../Core/Portable/FeaturesResources.resx | 3 + ...ider.cs => AbstractTypeSnippetProvider.cs} | 43 +++----- .../Portable/xlf/FeaturesResources.cs.xlf | 5 + .../Portable/xlf/FeaturesResources.de.xlf | 5 + .../Portable/xlf/FeaturesResources.es.xlf | 5 + .../Portable/xlf/FeaturesResources.fr.xlf | 5 + .../Portable/xlf/FeaturesResources.it.xlf | 5 + .../Portable/xlf/FeaturesResources.ja.xlf | 5 + .../Portable/xlf/FeaturesResources.ko.xlf | 5 + .../Portable/xlf/FeaturesResources.pl.xlf | 5 + .../Portable/xlf/FeaturesResources.pt-BR.xlf | 5 + .../Portable/xlf/FeaturesResources.ru.xlf | 5 + .../Portable/xlf/FeaturesResources.tr.xlf | 5 + .../xlf/FeaturesResources.zh-Hans.xlf | 5 + .../xlf/FeaturesResources.zh-Hant.xlf | 5 + .../Services/SyntaxFacts/CSharpSyntaxKinds.cs | 1 + .../SyntaxFacts/ISyntaxFactsExtensions.cs | 3 + .../Core/Services/SyntaxFacts/ISyntaxKinds.cs | 1 + .../SyntaxFacts/VisualBasicSyntaxKinds.vb | 1 + 22 files changed, 271 insertions(+), 93 deletions(-) create mode 100644 src/Features/CSharp/Portable/Snippets/CSharpStructSnippetProvider.cs create mode 100644 src/Features/CSharp/Portable/Snippets/CSharpTypeSnippetProvider.cs rename src/Features/Core/Portable/Snippets/SnippetProviders/{AbstractClassSnippetProvider.cs => AbstractTypeSnippetProvider.cs} (54%) diff --git a/src/Features/CSharp/Portable/Snippets/CSharpClassSnippetProvider.cs b/src/Features/CSharp/Portable/Snippets/CSharpClassSnippetProvider.cs index f2e9872637093..43cc63680ff70 100644 --- a/src/Features/CSharp/Portable/Snippets/CSharpClassSnippetProvider.cs +++ b/src/Features/CSharp/Portable/Snippets/CSharpClassSnippetProvider.cs @@ -23,6 +23,7 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; +using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Snippets; using Microsoft.CodeAnalysis.Snippets.SnippetProviders; @@ -32,87 +33,33 @@ namespace Microsoft.CodeAnalysis.CSharp.Snippets { [ExportSnippetProvider(nameof(ISnippetProvider), LanguageNames.CSharp), Shared] - internal class CSharpClassSnippetProvider : AbstractClassSnippetProvider + internal class CSharpClassSnippetProvider : CSharpTypeSnippetProvider { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public CSharpClassSnippetProvider() { } + public override string SnippetIdentifier => "class"; - private static readonly ISet s_validModifiers = new HashSet(SyntaxFacts.EqualityComparer) - { - SyntaxKind.NewKeyword, - SyntaxKind.PublicKeyword, - SyntaxKind.ProtectedKeyword, - SyntaxKind.InternalKeyword, - SyntaxKind.PrivateKeyword, - SyntaxKind.AbstractKeyword, - SyntaxKind.SealedKeyword, - SyntaxKind.StaticKeyword, - SyntaxKind.UnsafeKeyword - }; + public override string SnippetDescription => FeaturesResources.class_; - protected override async Task IsValidSnippetLocationAsync(Document document, int position, CancellationToken cancellationToken) + protected override async Task GenerateTypeDeclarationAsync(Document document, int position, bool useAccessibility, CancellationToken cancellationToken) { - var semanticModel = await document.ReuseExistingSpeculativeModelAsync(position, cancellationToken).ConfigureAwait(false); - var syntaxContext = (CSharpSyntaxContext)document.GetRequiredLanguageService().CreateContext(document, semanticModel, position, cancellationToken); + var generator = SyntaxGenerator.GetGenerator(document); + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - return - syntaxContext.IsGlobalStatementContext || - syntaxContext.IsTypeDeclarationContext( - validModifiers: s_validModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, - canBePartial: true, - cancellationToken: cancellationToken); - } - - protected override int GetTargetCaretPosition(ISyntaxFactsService syntaxFacts, SyntaxNode caretTarget, SourceText sourceText) - { - var classDeclaration = (ClassDeclarationSyntax)caretTarget; - var triviaSpan = classDeclaration.CloseBraceToken.LeadingTrivia.Span; - var line = sourceText.Lines.GetLineFromPosition(triviaSpan.Start); - // Getting the location at the end of the line before the newline. - return line.Span.End; - } - - private static string GetIndentation(Document document, SyntaxNode node, SyntaxFormattingOptions syntaxFormattingOptions, CancellationToken cancellationToken) - { - var parsedDocument = ParsedDocument.CreateSynchronously(document, cancellationToken); - var classDeclarationSyntax = (ClassDeclarationSyntax)node; - var openBraceLine = parsedDocument.Text.Lines.GetLineFromPosition(classDeclarationSyntax.OpenBraceToken.SpanStart).LineNumber; - - var indentationOptions = new IndentationOptions(syntaxFormattingOptions); - var newLine = indentationOptions.FormattingOptions.NewLine; - - var indentationService = parsedDocument.LanguageServices.GetRequiredService(); - var indentation = indentationService.GetIndentation(parsedDocument, openBraceLine + 1, indentationOptions, cancellationToken); - - // Adding the offset calculated with one tab so that it is indented once past the line containing the opening brace - var newIndentation = new IndentationResult(indentation.BasePosition, indentation.Offset + syntaxFormattingOptions.TabSize); - return newIndentation.GetIndentationString(parsedDocument.Text, syntaxFormattingOptions.UseTabs, syntaxFormattingOptions.TabSize) + newLine; - } - - protected override async Task AddIndentationToDocumentAsync(Document document, int position, ISyntaxFacts syntaxFacts, CancellationToken cancellationToken) - { - var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var snippet = root.GetAnnotatedNodes(_findSnippetAnnotation).FirstOrDefault(); - - var syntaxFormattingOptions = await document.GetSyntaxFormattingOptionsAsync(fallbackOptions: null, cancellationToken).ConfigureAwait(false); - var indentationString = GetIndentation(document, snippet, syntaxFormattingOptions, cancellationToken); - - var originalClassDeclaration = (ClassDeclarationSyntax)snippet; - var newClassDeclaration = originalClassDeclaration.WithCloseBraceToken( - originalClassDeclaration.CloseBraceToken.WithPrependedLeadingTrivia(SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, indentationString))); + var name = NameGenerator.GenerateUniqueName("MyClass", name => semanticModel.LookupSymbols(position, name: name).IsEmpty); + var classDeclaration = useAccessibility is true + ? generator.ClassDeclaration(name, accessibility: Accessibility.Public) + : generator.ClassDeclaration(name); - var newRoot = root.ReplaceNode(originalClassDeclaration, newClassDeclaration.WithAdditionalAnnotations(_cursorAnnotation, _findSnippetAnnotation)); - return document.WithSyntaxRoot(newRoot); + return classDeclaration; } - protected override void GetClassDeclarationIdentifier(SyntaxNode node, out SyntaxToken identifier) + protected override Func GetSnippetContainerFunction(ISyntaxFacts syntaxFacts) { - var classDeclarationSyntax = (ClassDeclarationSyntax)node; - identifier = classDeclarationSyntax.Identifier; + return syntaxFacts.IsClassDeclaration; } } } diff --git a/src/Features/CSharp/Portable/Snippets/CSharpStructSnippetProvider.cs b/src/Features/CSharp/Portable/Snippets/CSharpStructSnippetProvider.cs new file mode 100644 index 0000000000000..a1a8db9f7b4ab --- /dev/null +++ b/src/Features/CSharp/Portable/Snippets/CSharpStructSnippetProvider.cs @@ -0,0 +1,65 @@ +// 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.Collections.Generic; +using System.Collections.Immutable; +using System.Composition; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.CodeStyle; +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.Formatting; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Indentation; +using Microsoft.CodeAnalysis.LanguageService; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; +using Microsoft.CodeAnalysis.Shared.Utilities; +using Microsoft.CodeAnalysis.Simplification; +using Microsoft.CodeAnalysis.Snippets; +using Microsoft.CodeAnalysis.Snippets.SnippetProviders; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.Snippets +{ + [ExportSnippetProvider(nameof(ISnippetProvider), LanguageNames.CSharp), Shared] + internal class CSharpStructSnippetProvider : CSharpTypeSnippetProvider + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CSharpStructSnippetProvider() + { + } + public override string SnippetIdentifier => "struct"; + + public override string SnippetDescription => FeaturesResources.struct_; + + protected override async Task GenerateTypeDeclarationAsync(Document document, int position, bool useAccessibility, CancellationToken cancellationToken) + { + var generator = SyntaxGenerator.GetGenerator(document); + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + + var name = NameGenerator.GenerateUniqueName("MyStruct", name => semanticModel.LookupSymbols(position, name: name).IsEmpty); + var classDeclaration = useAccessibility is true + ? generator.StructDeclaration(name, accessibility: Accessibility.Public) + : generator.StructDeclaration(name); + + return classDeclaration; + } + + protected override Func GetSnippetContainerFunction(ISyntaxFacts syntaxFacts) + { + return syntaxFacts.IsStructDeclaration; + } + } +} diff --git a/src/Features/CSharp/Portable/Snippets/CSharpTypeSnippetProvider.cs b/src/Features/CSharp/Portable/Snippets/CSharpTypeSnippetProvider.cs new file mode 100644 index 0000000000000..5c02472729b83 --- /dev/null +++ b/src/Features/CSharp/Portable/Snippets/CSharpTypeSnippetProvider.cs @@ -0,0 +1,101 @@ +// 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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Utilities; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Indentation; +using Microsoft.CodeAnalysis.LanguageService; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; +using Microsoft.CodeAnalysis.Snippets.SnippetProviders; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.CSharp.Snippets +{ + internal abstract class CSharpTypeSnippetProvider : AbstractTypeSnippetProvider + { + private static readonly ISet s_validModifiers = new HashSet(SyntaxFacts.EqualityComparer) + { + SyntaxKind.NewKeyword, + SyntaxKind.PublicKeyword, + SyntaxKind.ProtectedKeyword, + SyntaxKind.InternalKeyword, + SyntaxKind.PrivateKeyword, + SyntaxKind.AbstractKeyword, + SyntaxKind.SealedKeyword, + SyntaxKind.StaticKeyword, + SyntaxKind.UnsafeKeyword + }; + + protected override async Task IsValidSnippetLocationAsync(Document document, int position, CancellationToken cancellationToken) + { + var semanticModel = await document.ReuseExistingSpeculativeModelAsync(position, cancellationToken).ConfigureAwait(false); + var syntaxContext = (CSharpSyntaxContext)document.GetRequiredLanguageService().CreateContext(document, semanticModel, position, cancellationToken); + + return + syntaxContext.IsGlobalStatementContext || + syntaxContext.IsTypeDeclarationContext( + validModifiers: s_validModifiers, + validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, + canBePartial: true, + cancellationToken: cancellationToken); + } + + protected override int GetTargetCaretPosition(ISyntaxFactsService syntaxFacts, SyntaxNode caretTarget, SourceText sourceText) + { + var typeDeclaration = (TypeDeclarationSyntax)caretTarget; + var triviaSpan = typeDeclaration.CloseBraceToken.LeadingTrivia.Span; + var line = sourceText.Lines.GetLineFromPosition(triviaSpan.Start); + // Getting the location at the end of the line before the newline. + return line.Span.End; + } + + private static string GetIndentation(Document document, SyntaxNode node, SyntaxFormattingOptions syntaxFormattingOptions, CancellationToken cancellationToken) + { + var parsedDocument = ParsedDocument.CreateSynchronously(document, cancellationToken); + var typeDelcaration = (TypeDeclarationSyntax)node; + var openBraceLine = parsedDocument.Text.Lines.GetLineFromPosition(typeDelcaration.OpenBraceToken.SpanStart).LineNumber; + + var indentationOptions = new IndentationOptions(syntaxFormattingOptions); + var newLine = indentationOptions.FormattingOptions.NewLine; + + var indentationService = parsedDocument.LanguageServices.GetRequiredService(); + var indentation = indentationService.GetIndentation(parsedDocument, openBraceLine + 1, indentationOptions, cancellationToken); + + // Adding the offset calculated with one tab so that it is indented once past the line containing the opening brace + var newIndentation = new IndentationResult(indentation.BasePosition, indentation.Offset + syntaxFormattingOptions.TabSize); + return newIndentation.GetIndentationString(parsedDocument.Text, syntaxFormattingOptions.UseTabs, syntaxFormattingOptions.TabSize) + newLine; + } + + protected override async Task AddIndentationToDocumentAsync(Document document, int position, ISyntaxFacts syntaxFacts, CancellationToken cancellationToken) + { + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var snippet = root.GetAnnotatedNodes(_findSnippetAnnotation).FirstOrDefault(); + + var syntaxFormattingOptions = await document.GetSyntaxFormattingOptionsAsync(fallbackOptions: null, cancellationToken).ConfigureAwait(false); + var indentationString = GetIndentation(document, snippet, syntaxFormattingOptions, cancellationToken); + + var originalTypeDeclaration = (TypeDeclarationSyntax)snippet; + var newTypeDeclaration = originalTypeDeclaration.WithCloseBraceToken( + originalTypeDeclaration.CloseBraceToken.WithPrependedLeadingTrivia(SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, indentationString))); + + var newRoot = root.ReplaceNode(originalTypeDeclaration, newTypeDeclaration.WithAdditionalAnnotations(_cursorAnnotation, _findSnippetAnnotation)); + return document.WithSyntaxRoot(newRoot); + } + + protected override void GetTypeDeclarationIdentifier(SyntaxNode node, out SyntaxToken identifier) + { + var typeDeclaration = (TypeDeclarationSyntax)node; + identifier = typeDeclaration.Identifier; + } + } +} diff --git a/src/Features/Core/Portable/FeaturesResources.resx b/src/Features/Core/Portable/FeaturesResources.resx index 6ed9501f9b772..ea19f70a1d8c3 100644 --- a/src/Features/Core/Portable/FeaturesResources.resx +++ b/src/Features/Core/Portable/FeaturesResources.resx @@ -3164,4 +3164,7 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Extract base record... {Locked="record"} "record" is a language construct for C# and should not be localized. + + struct + \ No newline at end of file diff --git a/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractClassSnippetProvider.cs b/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractTypeSnippetProvider.cs similarity index 54% rename from src/Features/Core/Portable/Snippets/SnippetProviders/AbstractClassSnippetProvider.cs rename to src/Features/Core/Portable/Snippets/SnippetProviders/AbstractTypeSnippetProvider.cs index 8f639cedded7c..cb63a597612b9 100644 --- a/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractClassSnippetProvider.cs +++ b/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractTypeSnippetProvider.cs @@ -3,59 +3,50 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using System.Collections.Immutable; +using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; -using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Snippets +namespace Microsoft.CodeAnalysis.Snippets.SnippetProviders { - internal abstract class AbstractClassSnippetProvider : AbstractSnippetProvider + internal abstract class AbstractTypeSnippetProvider : AbstractSnippetProvider { - protected abstract void GetClassDeclarationIdentifier(SyntaxNode node, out SyntaxToken identifier); - - public override string SnippetIdentifier => "class"; - - public override string SnippetDescription => FeaturesResources.class_; + protected abstract void GetTypeDeclarationIdentifier(SyntaxNode node, out SyntaxToken identifier); + protected abstract Task GenerateTypeDeclarationAsync(Document document, int position, bool useAccessibility, CancellationToken cancellationToken); protected override async Task> GenerateSnippetTextChangesAsync(Document document, int position, CancellationToken cancellationToken) { - var generator = SyntaxGenerator.GetGenerator(document); - var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var useAccessibility = await AreAccessibilityModifiersRequiredAsync(document, cancellationToken).ConfigureAwait(false); - var options = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); - var accessibilityModifiersRequired = options.GetEditorConfigOptionValue(CodeStyleOptions2.AccessibilityModifiersRequired, AccessibilityModifiersRequired.Never); - var useAccessibility = accessibilityModifiersRequired is AccessibilityModifiersRequired.ForNonInterfaceMembers or AccessibilityModifiersRequired.Always; + var typeDeclaration = await GenerateTypeDeclarationAsync(document, position, useAccessibility, cancellationToken).ConfigureAwait(false); - var name = NameGenerator.GenerateUniqueName("MyClass", name => semanticModel.LookupSymbols(position, name: name).IsEmpty); - var classDeclaration = useAccessibility is true - ? generator.ClassDeclaration(name, accessibility: Accessibility.Public) - : generator.ClassDeclaration(name); - - var snippetTextChange = new TextChange(TextSpan.FromBounds(position, position), classDeclaration.NormalizeWhitespace().ToFullString()); + var snippetTextChange = new TextChange(TextSpan.FromBounds(position, position), typeDeclaration.NormalizeWhitespace().ToFullString()); return ImmutableArray.Create(snippetTextChange); } - protected override Func GetSnippetContainerFunction(ISyntaxFacts syntaxFacts) - { - return syntaxFacts.IsClassDeclaration; - } - protected override ImmutableArray GetPlaceHolderLocationsList(SyntaxNode node, ISyntaxFacts syntaxFacts, CancellationToken cancellationToken) { using var _ = ArrayBuilder.GetInstance(out var arrayBuilder); - GetClassDeclarationIdentifier(node, out var identifier); + GetTypeDeclarationIdentifier(node, out var identifier); arrayBuilder.Add(new SnippetPlaceholder(identifier: identifier.ValueText, placeholderPositions: ImmutableArray.Create(identifier.SpanStart))); return arrayBuilder.ToImmutableArray(); } + + private static async Task AreAccessibilityModifiersRequiredAsync(Document document, CancellationToken cancellationToken) + { + var options = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); + var accessibilityModifiersRequired = options.GetEditorConfigOptionValue(CodeStyleOptions2.AccessibilityModifiersRequired, AccessibilityModifiersRequired.Never); + return accessibilityModifiersRequired is AccessibilityModifiersRequired.ForNonInterfaceMembers or AccessibilityModifiersRequired.Always; + } } } diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf index 9dac5bbafa2ff..076e2e76c9b0e 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf @@ -4275,6 +4275,11 @@ Když se tento specifikátor standardního formátu použije, operace formátov statický konstruktor + + struct + struct + + 'symbol' cannot be a namespace. 'Symbol nemůže být obor názvů. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf index 38787158c0d1e..75ecc28e03bb6 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf @@ -4275,6 +4275,11 @@ Bei Verwendung dieses Standardformatbezeichners wird zur Formatierung oder Analy statischer Konstruktor + + struct + struct + + 'symbol' cannot be a namespace. '"symbol" kann kein Namespace sein. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf index 62811d1af2f23..c7895f9958170 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf @@ -4275,6 +4275,11 @@ Cuando se usa este especificador de formato estándar, la operación de formato constructor estático + + struct + struct + + 'symbol' cannot be a namespace. 'símbolo' no puede ser un espacio de nombres. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf index f1ee4c3df511e..e6dae23f0d6d0 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf @@ -4275,6 +4275,11 @@ Quand ce spécificateur de format standard est utilisé, l'opération qui consis constructeur statique + + struct + struct + + 'symbol' cannot be a namespace. 'symbol' ne peut pas être un espace de noms. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf index 3e137f023fc3f..0704f2e6ea4ea 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf @@ -4275,6 +4275,11 @@ Quando si usa questo identificatore di formato standard, la formattazione o l'op costruttore statico + + struct + struct + + 'symbol' cannot be a namespace. 'L'elemento 'symbol' non può essere uno spazio dei nomi. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf index 3f2ecbf162c36..2286d8db540c8 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf @@ -4275,6 +4275,11 @@ When this standard format specifier is used, the formatting or parsing operation 静的コンストラクター + + struct + struct + + 'symbol' cannot be a namespace. 'symbol' は名前空間にすることはできません。 diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf index 3d55b1227bdd7..ff1f3c6966c3d 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf @@ -4275,6 +4275,11 @@ When this standard format specifier is used, the formatting or parsing operation 정적 생성자 + + struct + struct + + 'symbol' cannot be a namespace. '기호'는 네임스페이스일 수 없습니다. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf index 89b6d91fc1a4f..bb15b979e7b15 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf @@ -4275,6 +4275,11 @@ Gdy jest używany ten standardowy specyfikator formatu, operacja formatowania lu konstruktor statyczny + + struct + struct + + 'symbol' cannot be a namespace. 'Element „symbol” nie może być przestrzenią nazw. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf index 9b375c3004015..cbc2b7b8af480 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf @@ -4275,6 +4275,11 @@ Quando esse especificador de formato padrão é usado, a operação de análise construtor estático + + struct + struct + + 'symbol' cannot be a namespace. "símbolo" não pode ser um namespace. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf index 489961d08bd9f..fc9cd05325a2d 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf @@ -4275,6 +4275,11 @@ When this standard format specifier is used, the formatting or parsing operation статический конструктор + + struct + struct + + 'symbol' cannot be a namespace. '"символ" не может быть пространством имен. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf index ef356caa50ee8..2b433a041c244 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf @@ -4275,6 +4275,11 @@ Bu standart biçim belirticisi kullanıldığında, biçimlendirme veya ayrışt statik oluşturucu + + struct + struct + + 'symbol' cannot be a namespace. 'symbol' bir ad alanı olamaz. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf index 52db7b18291c7..5c1c16cbc2c8c 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf @@ -4275,6 +4275,11 @@ When this standard format specifier is used, the formatting or parsing operation 静态构造函数 + + struct + struct + + 'symbol' cannot be a namespace. '“symbol” 不能为命名空间。 diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf index 069636309c85e..ce5ad44132f76 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf @@ -4275,6 +4275,11 @@ When this standard format specifier is used, the formatting or parsing operation 靜態建構函式 + + struct + struct + + 'symbol' cannot be a namespace. 'symbol' 不可為命名空間。 diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxKinds.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxKinds.cs index 792210f90d2f8..cb8392ed54f88 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxKinds.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxKinds.cs @@ -126,6 +126,7 @@ public TSyntaxKind Convert(int kind) where TSyntaxKind : struct public int ClassDeclaration => (int)SyntaxKind.ClassDeclaration; public int? RecordDeclaration => (int)SyntaxKind.RecordDeclaration; public int? RecordStructDeclaration => (int)SyntaxKind.RecordStructDeclaration; + public int? StructDeclaration => (int)SyntaxKind.StructDeclaration; public int Parameter => (int)SyntaxKind.Parameter; public int TypeConstraint => (int)SyntaxKind.TypeConstraint; public int VariableDeclarator => (int)SyntaxKind.VariableDeclarator; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxFactsExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxFactsExtensions.cs index a69f6e5590fe4..46ed2837ff877 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxFactsExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxFactsExtensions.cs @@ -938,6 +938,9 @@ public static bool IsFieldDeclaration(this ISyntaxFacts syntaxFacts, [NotNullWhe public static bool IsPropertyDeclaration(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.PropertyDeclaration; + public static bool IsStructDeclaration(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) + => node?.RawKind == syntaxFacts.SyntaxKinds.StructDeclaration; + public static bool IsTypeArgumentList(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.TypeArgumentList; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxKinds.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxKinds.cs index 1479aeed11bd5..8e6c6211c16e8 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxKinds.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxKinds.cs @@ -177,6 +177,7 @@ internal interface ISyntaxKinds int ClassDeclaration { get; } int? RecordDeclaration { get; } int? RecordStructDeclaration { get; } + int? StructDeclaration { get; } int Parameter { get; } int TypeConstraint { get; } int VariableDeclarator { get; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxKinds.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxKinds.vb index 6246480563524..f418b5fd9e5b9 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxKinds.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxKinds.vb @@ -130,6 +130,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService Public ReadOnly Property ClassDeclaration As Integer = SyntaxKind.ClassBlock Implements ISyntaxKinds.ClassDeclaration Public ReadOnly Property RecordDeclaration As Integer? Implements ISyntaxKinds.RecordDeclaration Public ReadOnly Property RecordStructDeclaration As Integer? Implements ISyntaxKinds.RecordStructDeclaration + Public ReadOnly Property StructDeclaration As Integer? Implements ISyntaxKinds.StructDeclaration Public ReadOnly Property Parameter As Integer = SyntaxKind.Parameter Implements ISyntaxKinds.Parameter Public ReadOnly Property TypeConstraint As Integer = SyntaxKind.TypeConstraint Implements ISyntaxKinds.TypeConstraint Public ReadOnly Property VariableDeclarator As Integer = SyntaxKind.VariableDeclarator Implements ISyntaxKinds.VariableDeclarator From add0f8d1d79887229f869eead4ad765c103ad8b9 Mon Sep 17 00:00:00 2001 From: akhera99 Date: Wed, 14 Sep 2022 13:57:22 -0700 Subject: [PATCH 2/2] tests --- ...arpStructSnippetCompletionProviderTests.cs | 250 ++++++++++++++++++ .../Snippets/CSharpClassSnippetProvider.cs | 16 -- .../Snippets/CSharpStructSnippetProvider.cs | 16 -- 3 files changed, 250 insertions(+), 32 deletions(-) create mode 100644 src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpStructSnippetCompletionProviderTests.cs diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpStructSnippetCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpStructSnippetCompletionProviderTests.cs new file mode 100644 index 0000000000000..4eaf3fa400d01 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpStructSnippetCompletionProviderTests.cs @@ -0,0 +1,250 @@ +// 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.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 +{ + [Trait(Traits.Feature, Traits.Features.Completion)] + public class CSharpStructSnippetCompletionProviderTests : AbstractCSharpSnippetCompletionProviderTests + { + protected override string ItemToCommit => "struct"; + + [WpfFact] + public async Task InsertStructSnippetInNamespaceTest() + { + var markupBeforeCommit = +@"namespace Namespace +{ + $$ +}"; + + var expectedCodeAfterCommit = +@"namespace Namespace +{ + struct MyStruct + { + $$ + } +}"; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + } + + [WpfFact] + public async Task InsertStructSnippetInFileScopedNamespaceTest() + { + var markupBeforeCommit = +@"namespace Namespace; + +$$"; + + var expectedCodeAfterCommit = +@"namespace Namespace; + +struct MyStruct +{ + $$ +}" +; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + } + + [WpfFact] + public async Task InsertStructSnippetTest() + { + var markupBeforeCommit = +@"$$"; + + var expectedCodeAfterCommit = +@"struct MyStruct +{ + $$ +}" +; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + } + + [WpfFact] + public async Task InsertStructTopLevelSnippetTest() + { + var markupBeforeCommit = +@"System.Console.WriteLine(); +$$"; + + var expectedCodeAfterCommit = +@"System.Console.WriteLine(); + +struct MyStruct +{ + $$ +}" +; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + } + + [WpfFact] + public async Task InsertStructSnippetInClassTest() + { + var markupBeforeCommit = +@"struct MyClass +{ + $$ +}" +; + + var expectedCodeAfterCommit = +@"struct MyClass +{ + struct MyStruct + { + $$ + } +}" +; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + } + + [WpfFact] + public async Task InsertStructSnippetInRecordTest() + { + var markupBeforeCommit = +@"record MyRecord +{ + $$ +}"; + + var expectedCodeAfterCommit = +@"record MyRecord +{ + struct MyStruct + { + $$ + } +}" +; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + } + + [WpfFact] + public async Task InsertStructSnippetInStructTest() + { + var markupBeforeCommit = +@"struct MyStruct +{ + $$ +}"; + + var expectedCodeAfterCommit = +@"struct MyStruct +{ + struct MyStruct1 + { + $$ + } +}" +; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + } + + [WpfFact] + public async Task InsertStructSnippetInInterfaceTest() + { + var markupBeforeCommit = +@"interface MyInterface +{ + $$ +}"; + + var expectedCodeAfterCommit = +@"interface MyInterface +{ + struct MyStruct + { + $$ + } +}" +; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + } + + [WpfFact] + public async Task InsertStructSnippetWithModifiersTest() + { + var markupBeforeCommit = + $@" + + + +$$ + + +root = true + +[*] +# IDE0008: Use explicit type +dotnet_style_require_accessibility_modifiers = always + + +"; + var expectedCodeAfterCommit = + $@" +public struct MyStruct +{{ + $$ +}} +"; + + await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + } + + [WpfFact] + public async Task NoStructSnippetInEnumTest() + { + var markupBeforeCommit = +@"enum MyEnum +{ + $$ +}"; + + await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + } + + [WpfFact] + public async Task NoStructSnippetInMethodTest() + { + var markupBeforeCommit = +@"struct Program +{ + public void Method() + { + $$ + } +}" +; + await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + } + + [WpfFact] + public async Task NoStructSnippetInConstructorTest() + { + var markupBeforeCommit = +@"struct Program +{ + public Program() + { + $$ + } +}" +; + await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + } + } +} diff --git a/src/Features/CSharp/Portable/Snippets/CSharpClassSnippetProvider.cs b/src/Features/CSharp/Portable/Snippets/CSharpClassSnippetProvider.cs index 43cc63680ff70..7732176f33239 100644 --- a/src/Features/CSharp/Portable/Snippets/CSharpClassSnippetProvider.cs +++ b/src/Features/CSharp/Portable/Snippets/CSharpClassSnippetProvider.cs @@ -3,32 +3,16 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; -using System.Collections.Immutable; using System.Composition; -using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.CSharp.CodeStyle; -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.Formatting; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.LanguageService; -using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; using Microsoft.CodeAnalysis.Shared.Utilities; -using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Snippets; using Microsoft.CodeAnalysis.Snippets.SnippetProviders; -using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Snippets { diff --git a/src/Features/CSharp/Portable/Snippets/CSharpStructSnippetProvider.cs b/src/Features/CSharp/Portable/Snippets/CSharpStructSnippetProvider.cs index a1a8db9f7b4ab..fce2fe5f246a4 100644 --- a/src/Features/CSharp/Portable/Snippets/CSharpStructSnippetProvider.cs +++ b/src/Features/CSharp/Portable/Snippets/CSharpStructSnippetProvider.cs @@ -3,32 +3,16 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; -using System.Collections.Immutable; using System.Composition; -using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.CSharp.CodeStyle; -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.Formatting; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.LanguageService; -using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; using Microsoft.CodeAnalysis.Shared.Utilities; -using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Snippets; using Microsoft.CodeAnalysis.Snippets.SnippetProviders; -using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Snippets {