diff --git a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_DateAndTime.vb b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_DateAndTime.vb index bef42e96ac7a6c719d171c072bff3e6e7a506a2d..f857bddccc0ec76815bd3176798d06ff85332368 100644 --- a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_DateAndTime.vb +++ b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_DateAndTime.vb @@ -162,5 +162,235 @@ class c End If End Using End Function + + + Public Async Function ExplicitInvoke_StringInterpolation1(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + , showCompletionInArgumentLists:=showCompletionInArgumentLists) + + state.SendInvokeCompletionList() + Await state.AssertSelectedCompletionItem("G", inlineDescription:=FeaturesResources.general_long_date_time) + state.SendTab() + Await state.AssertNoCompletionSession() + Assert.Contains("_ = $""Text {d:G}""", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) + End Using + End Function + + + Public Async Function ExplicitInvoke_StringInterpolation2(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + , showCompletionInArgumentLists:=showCompletionInArgumentLists) + + state.SendInvokeCompletionList() + Await state.AssertSelectedCompletionItem("G", inlineDescription:=FeaturesResources.general_long_date_time) + state.SendTab() + Await state.AssertNoCompletionSession() + Assert.Contains("_ = @$""Text {d:G}""", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) + End Using + End Function + + + Public Async Function ExplicitInvoke_OverwriteExisting_StringInterpolation1(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + , showCompletionInArgumentLists:=showCompletionInArgumentLists) + + state.SendInvokeCompletionList() + Await state.AssertSelectedCompletionItem("ff") + state.SendDownKey() + Await state.AssertSelectedCompletionItem("FF") + state.SendTab() + Await state.AssertNoCompletionSession() + Assert.Contains("_ = $""Text {d:FF}""", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) + End Using + End Function + + + Public Async Function ExplicitInvoke_OverwriteExisting_StringInterpolation2(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + , showCompletionInArgumentLists:=showCompletionInArgumentLists) + + state.SendInvokeCompletionList() + Await state.AssertSelectedCompletionItem("ff") + state.SendDownKey() + Await state.AssertSelectedCompletionItem("FF") + state.SendTab() + Await state.AssertNoCompletionSession() + Assert.Contains("_ = @$""Text {d:FF}""", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) + End Using + End Function + + + Public Async Function TypeChar_BeginningOfWord_StringInterpolation1(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + , showCompletionInArgumentLists:=showCompletionInArgumentLists) + + state.SendTypeChars("f") + Await state.AssertCompletionSession() + Await state.AssertSelectedCompletionItem("f") + End Using + End Function + + + Public Async Function TypeChar_BeginningOfWord_StringInterpolation2(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + , showCompletionInArgumentLists:=showCompletionInArgumentLists) + + state.SendTypeChars("f") + Await state.AssertCompletionSession() + Await state.AssertSelectedCompletionItem("f") + End Using + End Function + + + Public Async Function TestExample1_StringInterpolation1(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( +, showCompletionInArgumentLists:=showCompletionInArgumentLists) + + state.SendInvokeCompletionList() + state.SendTypeChars("ss") + Await state.AssertSelectedCompletionItem("ss", inlineDescription:=FeaturesResources.second_2_digits) + + Dim description = Await state.GetSelectedItemDescriptionAsync() + Dim text = description.Text + + If CultureInfo.CurrentCulture.Name <> "en-US" Then + Assert.Contains($"hh:mm:ss (en-US) → 01:45:30", text) + Assert.Contains($"hh:mm:ss ({CultureInfo.CurrentCulture.Name}) → 01:45:30", text) + Else + Assert.Contains("hh:mm:ss → 01:45:30", text) + End If + End Using + End Function + + + Public Async Function TestExample1_StringInterpolation2(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( +, showCompletionInArgumentLists:=showCompletionInArgumentLists) + + state.SendInvokeCompletionList() + state.SendTypeChars("ss") + Await state.AssertSelectedCompletionItem("ss", inlineDescription:=FeaturesResources.second_2_digits) + + Dim description = Await state.GetSelectedItemDescriptionAsync() + Dim text = description.Text + + If CultureInfo.CurrentCulture.Name <> "en-US" Then + Assert.Contains($"hh:mm:ss (en-US) → 01:45:30", text) + Assert.Contains($"hh:mm:ss ({CultureInfo.CurrentCulture.Name}) → 01:45:30", text) + Else + Assert.Contains("hh:mm:ss → 01:45:30", text) + End If + End Using + End Function + + + Public Async Function TypeChar_MiddleOfWord_StringInterpolation1(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + , showCompletionInArgumentLists:=showCompletionInArgumentLists) + + state.SendTypeChars("f") + Await state.AssertNoCompletionSession() + End Using + End Function + + + Public Async Function TypeChar_MiddleOfWord_StringInterpolation2(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + , showCompletionInArgumentLists:=showCompletionInArgumentLists) + + state.SendTypeChars("f") + Await state.AssertNoCompletionSession() + End Using + End Function End Class End Namespace diff --git a/src/EditorFeatures/Test2/IntelliSense/VisualBasicCompletionCommandHandlerTests_DateAndTime.vb b/src/EditorFeatures/Test2/IntelliSense/VisualBasicCompletionCommandHandlerTests_DateAndTime.vb new file mode 100644 index 0000000000000000000000000000000000000000..92a21f677f64807748b5a2c1088f71f6a9f080b7 --- /dev/null +++ b/src/EditorFeatures/Test2/IntelliSense/VisualBasicCompletionCommandHandlerTests_DateAndTime.vb @@ -0,0 +1,210 @@ +' 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. + +Imports System.Globalization + +Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense + <[UseExportProvider]> + Public Class VisualBasicCompletionCommandHandlerTests_DateAndTime + + Public Async Function ExplicitInvoke() As Task + Using state = TestStateFactory.CreateVisualBasicTestState( + ) + + state.SendInvokeCompletionList() + Await state.AssertSelectedCompletionItem("G", inlineDescription:=FeaturesResources.general_long_date_time) + state.SendTab() + Await state.AssertNoCompletionSession() + Assert.Contains("d.ToString(""G"")", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) + End Using + End Function + + + Public Async Function ExplicitInvoke_OverwriteExisting() As Task + Using state = TestStateFactory.CreateVisualBasicTestState( + ) + + state.SendInvokeCompletionList() + Await state.AssertSelectedCompletionItem("ff") + state.SendDownKey() + Await state.AssertSelectedCompletionItem("FF") + state.SendTab() + Await state.AssertNoCompletionSession() + Assert.Contains("d.ToString("":FF"")", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) + End Using + End Function + + + Public Async Function TypeChar_BeginningOfWord() As Task + Using state = TestStateFactory.CreateVisualBasicTestState( + ) + + state.SendTypeChars("f") + Await state.AssertCompletionSession() + Await state.AssertSelectedCompletionItem("f") + End Using + End Function + + + Public Async Function TypeChar_MiddleOfWord() As Task + Using state = TestStateFactory.CreateVisualBasicTestState( + ) + + state.SendTypeChars("f") + Await state.AssertNoCompletionSession() + End Using + End Function + + + Public Async Function TestExample1() As Task + Using state = TestStateFactory.CreateVisualBasicTestState( +) + + state.SendInvokeCompletionList() + state.SendTypeChars("ss") + Await state.AssertSelectedCompletionItem("ss", inlineDescription:=FeaturesResources.second_2_digits) + + Dim description = Await state.GetSelectedItemDescriptionAsync() + Dim text = description.Text + + If CultureInfo.CurrentCulture.Name <> "en-US" Then + Assert.Contains($"hh:mm:ss (en-US) → 01:45:30", text) + Assert.Contains($"hh:mm:ss ({CultureInfo.CurrentCulture.Name}) → 01:45:30", text) + Else + Assert.Contains("hh:mm:ss → 01:45:30", text) + End If + End Using + End Function + + + Public Async Function ExplicitInvoke_StringInterpolation() As Task + Using state = TestStateFactory.CreateVisualBasicTestState( + ) + + state.SendInvokeCompletionList() + Await state.AssertSelectedCompletionItem("G", inlineDescription:=FeaturesResources.general_long_date_time) + state.SendTab() + Await state.AssertNoCompletionSession() + Assert.Contains("Dim str = $""Text {d:G}""", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) + End Using + End Function + + + Public Async Function ExplicitInvoke_OverwriteExisting_StringInterpolation() As Task + Using state = TestStateFactory.CreateVisualBasicTestState( + ) + + state.SendInvokeCompletionList() + Await state.AssertSelectedCompletionItem("ff") + state.SendDownKey() + Await state.AssertSelectedCompletionItem("FF") + state.SendTab() + Await state.AssertNoCompletionSession() + Assert.Contains("Dim str = $""Text {d:FF}""", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) + End Using + End Function + + + Public Async Function TypeChar_BeginningOfWord_StringInterpolation() As Task + Using state = TestStateFactory.CreateVisualBasicTestState( + ) + + state.SendTypeChars("f") + Await state.AssertCompletionSession() + Await state.AssertSelectedCompletionItem("f") + End Using + End Function + + + Public Async Function TestExample1_StringInterpolation() As Task + Using state = TestStateFactory.CreateVisualBasicTestState( +) + + state.SendInvokeCompletionList() + state.SendTypeChars("ss") + Await state.AssertSelectedCompletionItem("ss", inlineDescription:=FeaturesResources.second_2_digits) + + Dim description = Await state.GetSelectedItemDescriptionAsync() + Dim text = description.Text + + If CultureInfo.CurrentCulture.Name <> "en-US" Then + Assert.Contains($"hh:mm:ss (en-US) → 01:45:30", text) + Assert.Contains($"hh:mm:ss ({CultureInfo.CurrentCulture.Name}) → 01:45:30", text) + Else + Assert.Contains("hh:mm:ss → 01:45:30", text) + End If + End Using + End Function + + + Public Async Function TypeChar_MiddleOfWord_StringInterpolation() As Task + Using state = TestStateFactory.CreateVisualBasicTestState( + ) + + state.SendTypeChars("f") + Await state.AssertNoCompletionSession() + End Using + End Function + End Class +End Namespace diff --git a/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/DateAndTimeEmbeddedCompletionProvider.cs b/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/DateAndTimeEmbeddedCompletionProvider.cs index 265038edfe578d39cbbdadab53d5682b8f83c432..fbde229e581a366ce28643721745915ae44018f2 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/DateAndTimeEmbeddedCompletionProvider.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/DateAndTimeEmbeddedCompletionProvider.cs @@ -10,8 +10,10 @@ using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Completion.Providers; using Microsoft.CodeAnalysis.EmbeddedLanguages.DateAndTime; +using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -80,9 +82,15 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) if (stringTokenOpt == null) return; + var syntaxFacts = document.GetRequiredLanguageService(); var stringToken = stringTokenOpt.Value; - if (position <= stringToken.SpanStart || position >= stringToken.Span.End) - return; + + // If we're not in an interpolation, at least make sure we're within the bounds of the string. + if (stringToken.RawKind != syntaxFacts.SyntaxKinds.InterpolatedStringTextToken) + { + if (position <= stringToken.SpanStart || position >= stringToken.Span.End) + return; + } // Note: it's acceptable if this fails to convert. We just won't show the example in that case. var virtualChars = _language.Info.VirtualCharService.TryConvertToVirtualChars(stringToken); diff --git a/src/Workspaces/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimeEmbeddedLanguage.cs b/src/Workspaces/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimeEmbeddedLanguage.cs index d9511cfc8e75f72a9eb62a4a43c59e78ab334f4e..e0f5a878eef9d83cd27a9116a00137027a867c6d 100644 --- a/src/Workspaces/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimeEmbeddedLanguage.cs +++ b/src/Workspaces/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimeEmbeddedLanguage.cs @@ -4,6 +4,7 @@ #nullable enable +using System; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Classification.Classifiers; @@ -28,16 +29,42 @@ public DateAndTimeEmbeddedLanguage(EmbeddedLanguageInfo info) internal async Task TryGetDateAndTimeTokenAtPositionAsync( Document document, int position, CancellationToken cancellationToken) { - var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var token = root.FindToken(position); var syntaxFacts = document.GetRequiredLanguageService(); - if (!DateAndTimePatternDetector.IsPossiblyDateAndTimeToken(token, syntaxFacts, out _, out _)) + + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var token = GetToken(syntaxFacts, root, position); + if (!DateAndTimePatternDetector.IsPossiblyDateAndTimeArgumentToken(token, syntaxFacts, out _, out _) && + token.RawKind != syntaxFacts.SyntaxKinds.InterpolatedStringTextToken) + { return null; + } var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var detector = DateAndTimePatternDetector.TryGetOrCreate(semanticModel, this.Info); - return detector != null && detector.IsDateAndTimeToken(token, cancellationToken) + return detector != null && detector.IsDateAndTimeToken(token, syntaxFacts, cancellationToken) ? token : (SyntaxToken?)null; } + + private static SyntaxToken GetToken(ISyntaxFactsService syntaxFacts, SyntaxNode root, int position) + { + var token = root.FindToken(position); + var syntaxKinds = syntaxFacts.SyntaxKinds; + + if (token.RawKind == syntaxKinds.CloseBraceToken) + { + // Might be here: $"Date is: {date:$$}" or + // $"Date is: {date:G$$}" + // + // If so, we want to return the InterpolatedStringTextToken following the `:` + var previous = token.GetPreviousToken(); + if (previous.RawKind == syntaxKinds.InterpolatedStringTextToken) + return previous; + + if (previous.RawKind == syntaxKinds.ColonToken) + return previous.GetNextToken(includeZeroWidth: true); + } + + return token; + } } } diff --git a/src/Workspaces/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimePatternDetector.cs b/src/Workspaces/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimePatternDetector.cs index 2e608aec657b19d02d2472d22f75384a1dfb77da..c7352c0dbc78184b9816cc6da174584cf9bf4c82 100644 --- a/src/Workspaces/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimePatternDetector.cs +++ b/src/Workspaces/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimePatternDetector.cs @@ -77,7 +77,7 @@ internal sealed class DateAndTimePatternDetector /// format string passed into an method call. If so, and will be the argument and invocatoin the string literal was passed as. /// - public static bool IsPossiblyDateAndTimeToken( + public static bool IsPossiblyDateAndTimeArgumentToken( SyntaxToken token, ISyntaxFacts syntaxFacts, [NotNullWhen(true)] out SyntaxNode? argumentNode, [NotNullWhen(true)] out SyntaxNode? invocationExpression) @@ -131,34 +131,40 @@ private static bool IsMethodArgument(SyntaxToken token, ISyntaxFacts syntaxFacts => syntaxFacts.IsLiteralExpression(token.Parent) && syntaxFacts.IsArgument(token.Parent!.Parent); - public bool IsDateAndTimeToken(SyntaxToken token, CancellationToken cancellationToken) + public bool IsDateAndTimeToken(SyntaxToken token, ISyntaxFacts syntaxFacts, CancellationToken cancellationToken) { - if (!IsPossiblyDateAndTimeToken( + if (IsPossiblyDateAndTimeArgumentToken( token, _info.SyntaxFacts, out var argumentNode, out var invocationOrCreation)) { - return false; - } - - // if we couldn't determine the arg name or arg index, can't proceed. - var (argName, argIndex) = GetArgumentNameOrIndex(argumentNode); - if (argName == null && argIndex == null) - return false; - - // If we had a specified arg name and it isn't 'format', then it's not a DateTime - // 'format' param we care about. - if (argName != null && argName != FormatName) - return false; - - var symbolInfo = _semanticModel.GetSymbolInfo(invocationOrCreation, cancellationToken); - var method = symbolInfo.Symbol; - if (TryAnalyzeInvocation(method, argName, argIndex)) - return true; + // if we couldn't determine the arg name or arg index, can't proceed. + var (argName, argIndex) = GetArgumentNameOrIndex(argumentNode); + if (argName == null && argIndex == null) + return false; + + // If we had a specified arg name and it isn't 'format', then it's not a DateTime + // 'format' param we care about. + if (argName != null && argName != FormatName) + return false; + + var symbolInfo = _semanticModel.GetSymbolInfo(invocationOrCreation, cancellationToken); + var method = symbolInfo.Symbol; + if (TryAnalyzeInvocation(method, argName, argIndex)) + return true; - foreach (var candidate in symbolInfo.CandidateSymbols) + foreach (var candidate in symbolInfo.CandidateSymbols) + { + if (TryAnalyzeInvocation(candidate, argName, argIndex)) + return true; + } + } + else if (token.RawKind == syntaxFacts.SyntaxKinds.InterpolatedStringTextToken) { - if (TryAnalyzeInvocation(candidate, argName, argIndex)) - return true; + var interpolationFormatClause = token.Parent!; + var interpolation = interpolationFormatClause.Parent!; + var expression = syntaxFacts.GetExpressionOfInterpolation(interpolation); + var type = _semanticModel.GetTypeInfo(expression, cancellationToken).Type; + return IsDateTimeType(type); } return false; @@ -187,8 +193,8 @@ private bool TryAnalyzeInvocation(ISymbol? symbol, string? argName, int? argInde IsDateTimeType(method.ContainingType) && AnalyzeStringLiteral(method, argName, argIndex); - private bool IsDateTimeType(INamedTypeSymbol containingType) - => _dateTimeType.Equals(containingType) || _dateTimeOffsetType.Equals(containingType); + private bool IsDateTimeType(ITypeSymbol? type) + => _dateTimeType.Equals(type) || _dateTimeOffsetType.Equals(type); private static bool AnalyzeStringLiteral(IMethodSymbol method, string? argName, int? argIndex) { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/EmbeddedLanguages/VirtualChars/CSharpVirtualCharService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/EmbeddedLanguages/VirtualChars/CSharpVirtualCharService.cs index 06f24bdaaa8d4c795e57753df24b0f9ea234c89e..f3e0ba619b3d10ff430d67a905f8b33fa52cba14 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/EmbeddedLanguages/VirtualChars/CSharpVirtualCharService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/EmbeddedLanguages/VirtualChars/CSharpVirtualCharService.cs @@ -39,9 +39,7 @@ protected override VirtualCharSequence TryConvertToVirtualCharsWorker(SyntaxToke // we won't classify any escape characters. And there is no way that these strings would // be Regex/Json snippets. So it's easier to just bail out and return nothing. if (IsInDirective(token.Parent)) - { return default; - } Debug.Assert(!token.ContainsDiagnostics); if (token.Kind() == SyntaxKind.StringLiteralToken) @@ -52,16 +50,15 @@ protected override VirtualCharSequence TryConvertToVirtualCharsWorker(SyntaxToke } if (token.Kind() == SyntaxKind.CharacterLiteralToken) - { return TryConvertStringToVirtualChars(token, "'", "'", escapeBraces: false); - } if (token.Kind() == SyntaxKind.InterpolatedStringTextToken) { - // The sections between `}` and `{` are InterpolatedStringTextToken *as are* the - // format specifiers in an interpolated string. We only want to get the virtual - // chars for this first type. - if (token.Parent.Parent is InterpolatedStringExpressionSyntax interpolatedString) + var parent = token.Parent; + if (parent is InterpolationFormatClauseSyntax) + parent = parent.Parent; + + if (parent.Parent is InterpolatedStringExpressionSyntax interpolatedString) { return interpolatedString.StringStartToken.Kind() == SyntaxKind.InterpolatedVerbatimStringStartToken ? TryConvertVerbatimStringToVirtualChars(token, "", "", escapeBraces: true) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxKinds.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxKinds.cs index 19068c7cfd8b18203c61a20663fc03a258f22641..c49794f836e5592213a6e81d907476bc9daf34b2 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxKinds.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxKinds.cs @@ -28,6 +28,8 @@ protected CSharpSyntaxKinds() public int SingleLineCommentTrivia => (int)SyntaxKind.SingleLineCommentTrivia; public int? MultiLineCommentTrivia => (int)SyntaxKind.MultiLineCommentTrivia; + public int CloseBraceToken => (int)SyntaxKind.CloseBraceToken; + public int ColonToken => (int)SyntaxKind.ColonToken; public int CharacterLiteralToken => (int)SyntaxKind.CharacterLiteralToken; public int DotToken => (int)SyntaxKind.DotToken; public int InterpolatedStringTextToken => (int)SyntaxKind.InterpolatedStringTextToken; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxKinds.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxKinds.cs index 57769b66c2cf9e56b96675f3f02bc1d5d57c8c7f..d4f73a8d165318756b02a11ef6182f3d2f3dc896 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxKinds.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxKinds.cs @@ -52,6 +52,8 @@ internal interface ISyntaxKinds #region tokens + int CloseBraceToken { get; } + int ColonToken { get; } int DotToken { get; } int EndOfFileToken { get; } int HashToken { get; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/EmbeddedLanguages/VirtualChars/VisualBasicVirtualCharService.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/EmbeddedLanguages/VirtualChars/VisualBasicVirtualCharService.vb index b39967bd7c37e76dc2403c34a92cbb4c6dc9d647..294ace7927880bcd96b3d96a4ec0f05e2aa6aa65 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/EmbeddedLanguages/VirtualChars/VisualBasicVirtualCharService.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/EmbeddedLanguages/VirtualChars/VisualBasicVirtualCharService.vb @@ -32,8 +32,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EmbeddedLanguages.VirtualChars Return TryConvertSimpleDoubleQuoteString(token, """", """", escapeBraces:=False) End If - If token.Kind() = SyntaxKind.InterpolatedStringTextToken AndAlso - TypeOf token.Parent.Parent Is InterpolatedStringExpressionSyntax Then + If token.Kind() = SyntaxKind.InterpolatedStringTextToken Then Return TryConvertSimpleDoubleQuoteString(token, "", "", escapeBraces:=True) End If diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxKinds.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxKinds.vb index f53501d16703972da61cc887133c40637ed2343b..4c0033c41086c732e118d423b458f3809a001f7c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxKinds.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxKinds.vb @@ -26,6 +26,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageServices Public ReadOnly Property SingleLineCommentTrivia As Integer = SyntaxKind.CommentTrivia Implements ISyntaxKinds.SingleLineCommentTrivia Private ReadOnly Property MultiLineCommentTrivia As Integer? = Nothing Implements ISyntaxKinds.MultiLineCommentTrivia + Public ReadOnly Property CloseBraceToken As Integer = SyntaxKind.CloseBraceToken Implements ISyntaxKinds.CloseBraceToken + Public ReadOnly Property ColonToken As Integer = SyntaxKind.ColonToken Implements ISyntaxKinds.ColonToken Public ReadOnly Property CharacterLiteralToken As Integer = SyntaxKind.CharacterLiteralToken Implements ISyntaxKinds.CharacterLiteralToken Public ReadOnly Property DotToken As Integer = SyntaxKind.DotToken Implements ISyntaxKinds.DotToken Public ReadOnly Property InterpolatedStringTextToken As Integer = SyntaxKind.InterpolatedStringTextToken Implements ISyntaxKinds.InterpolatedStringTextToken