diff --git a/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs b/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs index a720fcd4e3b29cc04e775d4a3613881b8bcc1fc1..4a62e076c65c2d6aea34158cddb01d1cba28902a 100644 --- a/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs +++ b/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs @@ -1251,6 +1251,12 @@ public async Task TestNullLiteral() MainDescription("class System.String")); } + [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] + public async Task TestNullLiteralWithVar() + { + await TestInMethodAsync(@"var f = null$$"); + } + [WorkItem(26027, "https://github.com/dotnet/roslyn/issues/26027")] [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] public async Task TestDefaultLiteral() diff --git a/src/EditorFeatures/Test2/Extensions/ISymbolExtensionsTests.vb b/src/EditorFeatures/Test2/Extensions/ISymbolExtensionsTests.vb index 60f38805c4515bfd46493abcb4c3beb27dcc0fc9..581f40eeaa6959839726cb0ca12e531cf8d341df 100644 --- a/src/EditorFeatures/Test2/Extensions/ISymbolExtensionsTests.vb +++ b/src/EditorFeatures/Test2/Extensions/ISymbolExtensionsTests.vb @@ -3,6 +3,7 @@ Imports System.Threading Imports System.Threading.Tasks Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.FindSymbols Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces <[UseExportProvider]> @@ -15,12 +16,8 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Dim cursorPosition = cursorDocument.CursorPosition.Value Dim document = workspace.CurrentSolution.GetDocument(cursorDocument.Id) - Dim tree = Await document.GetSyntaxTreeAsync() - Dim commonSyntaxToken = Await tree.GetTouchingTokenAsync(cursorPosition, Nothing) - Dim semanticModel = Await document.GetSemanticModelAsync() - Dim symbol = semanticModel.GetSemanticInfo(commonSyntaxToken, document.Project.Solution.Workspace, Nothing). - GetAnySymbol(includeType:=False) + Dim symbol = Await SymbolFinder.FindSymbolAtPositionAsync(document, cursorPosition) Dim namedTypeSymbol = semanticModel.GetEnclosingNamedType(cursorPosition, CancellationToken.None) Dim actualVisible = symbol.IsAccessibleWithin(namedTypeSymbol) diff --git a/src/EditorFeatures/Test2/Workspaces/SymbolDescriptionServiceTests.vb b/src/EditorFeatures/Test2/Workspaces/SymbolDescriptionServiceTests.vb index 831460042a882c47c1e4c30f35db59bd0b6f28ef..b6bb976e5d5e41b83c01868f693873b89daff98b 100644 --- a/src/EditorFeatures/Test2/Workspaces/SymbolDescriptionServiceTests.vb +++ b/src/EditorFeatures/Test2/Workspaces/SymbolDescriptionServiceTests.vb @@ -3,6 +3,7 @@ Imports System.Threading Imports System.Threading.Tasks Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.FindSymbols Imports Microsoft.CodeAnalysis.Host Imports Microsoft.CodeAnalysis.LanguageServices @@ -19,21 +20,8 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Dim cursorBuffer = cursorDocument.TextBuffer Dim document = workspace.CurrentSolution.GetDocument(cursorDocument.Id) - - ' using GetTouchingWord instead of FindToken allows us to test scenarios where cursor is at the end of token (E.g: Goo$$) - Dim tree = Await document.GetSyntaxTreeAsync() - Dim commonSyntaxToken = Await tree.GetTouchingWordAsync(cursorPosition, languageServiceProvider.GetService(Of ISyntaxFactsService), Nothing) - - ' For String Literals GetTouchingWord returns Nothing, we still need this for Quick Info. Quick Info code does exactly the following. - ' caveat: The comment above the previous line of code. Do not put the cursor at the end of the token. - If commonSyntaxToken = Nothing Then - commonSyntaxToken = (Await document.GetSyntaxRootAsync()).FindToken(cursorPosition) - End If - Dim semanticModel = Await document.GetSemanticModelAsync() - Dim symbol = semanticModel.GetSemanticInfo(commonSyntaxToken, document.Project.Solution.Workspace, CancellationToken.None). - GetSymbols(includeType:=True). - AsImmutable() + Dim symbol = Await SymbolFinder.FindSymbolAtPositionAsync(document, cursorPosition) Dim symbolDescriptionService = languageServiceProvider.GetService(Of ISymbolDisplayService)() @@ -108,44 +96,6 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Await TestCSharpAsync(workspace, $"({FeaturesResources.local_constant}) int x = 2") End Function - - Public Async Function TestCSharpNullLiteralVar() As Task - Dim workspace = - - - - class Goo - { - void Method() - { - var x = nu$$ll - } - } - - - - Await TestCSharpAsync(workspace, "") - End Function - - - Public Async Function TestCSharpNullLiteralString() As Task - Dim workspace = - - - - class Goo - { - void Method() - { - string x = nu$$ll - } - } - - - - Await TestCSharpAsync(workspace, "class System.String") - End Function - Public Async Function TestCSharpStaticField() As Task Dim workspace = @@ -649,125 +599,6 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Await TestBasicAsync(workspace, $"({FeaturesResources.local_variable}) x As String") End Function - - Public Async Function TestStringLiteral() As Task - Dim workspace = - - - - Class Goo - Sub Method() - Dim x As String = "Hel$$lo" - End Sub - End Class - - - - Await TestBasicAsync(workspace, "Class System.String") - End Function - - - Public Async Function TestIntegerLiteral() As Task - Dim workspace = - - - - Class Goo - Sub Method() - Dim x = 4$$2 - End Sub - End Class - - - - Await TestBasicAsync(workspace, "Structure System.Int32") - End Function - - - Public Async Function TestDateLiteral() As Task - Dim workspace = - - - - Class Goo - Sub Method() - Dim d As Date - d = #8/23/1970 $$3:45:39 AM# - End Sub - End Class - - - - Await TestBasicAsync(workspace, "Structure System.DateTime") - End Function - - - Public Async Function TestNothingLiteralDim() As Task - Dim workspace = - - - - Class Goo - Sub Method() - Dim x = Nothin$$g - End Sub - End Class - - - - Await TestBasicAsync(workspace, "Class System.Object") - End Function - - - Public Async Function TestNothingLiteralDimAsString() As Task - Dim workspace = - - - - Class Goo - Sub Method() - Dim x As String = Nothin$$g - End Sub - End Class - - - - Await TestBasicAsync(workspace, "Class System.String") - End Function - - - Public Async Function TestNothingLiteralFieldDimOptionStrict() As Task - Dim workspace = - - - - Option Strict On - Class Goo - Dim x = Nothin$$g - End Class - - - - Await TestBasicAsync(workspace, "Class System.Object") - End Function - - - Public Async Function TestTrueKeyword() As Task - Dim workspace = - - - - Class Goo - Sub Method() - Dim x = Tr$$ue - End Sub - End Class - - - - Await TestBasicAsync(workspace, "Structure System.Boolean") - End Function - Public Async Function TestMethod() As Task diff --git a/src/EditorFeatures/VisualBasicTest/QuickInfo/SemanticQuickInfoSourceTests.vb b/src/EditorFeatures/VisualBasicTest/QuickInfo/SemanticQuickInfoSourceTests.vb index 0a05c06a8a2ad1f2b55f7a2451d45a36d87667bd..c560587de5abe9d5608900429c521067bb460320 100644 --- a/src/EditorFeatures/VisualBasicTest/QuickInfo/SemanticQuickInfoSourceTests.vb +++ b/src/EditorFeatures/VisualBasicTest/QuickInfo/SemanticQuickInfoSourceTests.vb @@ -1751,6 +1751,12 @@ End Class]]>.NormalizedValue(), MainDescription("Structure System.Int32")) End Function + + Public Async Function TestDateLiteral() As Task + Await TestInMethodAsync("Dim f = #8/23/1970 $$3:45:39 AM#", + MainDescription("Structure System.DateTime")) + End Function + Public Async Function TestTrueKeyword() As Task Await TestInMethodAsync("Dim f = True$$", @@ -1770,6 +1776,22 @@ End Class]]>.NormalizedValue(), MainDescription("Class System.String")) End Function + + Public Async Function TestNothingLiteralWithNoType() As Task + Await TestInMethodAsync("Dim f = Nothing$$", + MainDescription("Class System.Object")) + End Function + + + Public Async Function TestNothingLiteralFieldDimOptionStrict() As Task + Await TestAsync(" +Option Strict On +Class C + Dim f = Nothing$$ +End Class", + MainDescription("Class System.Object")) + End Function + ''' ''' As a part of fix for 756226, quick info for VB Await keyword now displays the type inferred from the AwaitExpression. This is C# behavior. ''' In Dev12, quick info for VB Await keyword was the syntactic help "Await <expression>". diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/SemanticModelExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/SemanticModelExtensions.cs index 82f3da5a459a474d51196756a383f27d264dc5ca..ab783bf1059bff3427d82340a3093eaf89f8434c 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/SemanticModelExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/SemanticModelExtensions.cs @@ -6,62 +6,11 @@ using System.Threading; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Operations; -using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Utilities; -using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.Extensions { - internal struct TokenSemanticInfo - { - public static readonly TokenSemanticInfo Empty = new TokenSemanticInfo( - null, null, ImmutableArray.Empty, null, null, default(TextSpan)); - - public readonly ISymbol DeclaredSymbol; - public readonly IAliasSymbol AliasSymbol; - public readonly ImmutableArray ReferencedSymbols; - public readonly ITypeSymbol Type; - public readonly ITypeSymbol ConvertedType; - public readonly TextSpan Span; - - public TokenSemanticInfo( - ISymbol declaredSymbol, - IAliasSymbol aliasSymbol, - ImmutableArray referencedSymbols, - ITypeSymbol type, - ITypeSymbol convertedType, - TextSpan span) - { - DeclaredSymbol = declaredSymbol; - AliasSymbol = aliasSymbol; - ReferencedSymbols = referencedSymbols; - Type = type; - ConvertedType = convertedType; - Span = span; - } - - public ImmutableArray GetSymbols(bool includeType) - { - var result = ArrayBuilder.GetInstance(); - result.AddIfNotNull(DeclaredSymbol); - result.AddIfNotNull(AliasSymbol); - result.AddRange(ReferencedSymbols); - - if (includeType) - { - result.AddIfNotNull(Type ?? ConvertedType); - } - - return result.ToImmutableAndFree(); - } - - public ISymbol GetAnySymbol(bool includeType) - { - return GetSymbols(includeType).FirstOrDefault(); - } - } - internal static class SemanticModelExtensions { public static SemanticMap GetSemanticMap(this SemanticModel semanticModel, SyntaxNode node, CancellationToken cancellationToken) @@ -124,26 +73,6 @@ public static INamespaceSymbol GetEnclosingNamespace(this SemanticModel semantic return typeInfo.Type ?? symbolInfo.GetAnySymbol().ConvertToType(semanticModel.Compilation); } - public static TokenSemanticInfo GetSemanticInfo( - this SemanticModel semanticModel, - SyntaxToken token, - Workspace workspace, - CancellationToken cancellationToken) - { - var languageServices = workspace.Services.GetLanguageServices(token.Language); - var syntaxFacts = languageServices.GetService(); - if (!syntaxFacts.IsBindableToken(token)) - { - return TokenSemanticInfo.Empty; - } - - var semanticFacts = languageServices.GetService(); - - return GetSemanticInfo( - semanticModel, semanticFacts, syntaxFacts, - token, cancellationToken); - } - private static ISymbol MapSymbol(ISymbol symbol, ITypeSymbol type) { if (symbol.IsConstructor() && symbol.ContainingType.IsAnonymousType) @@ -192,13 +121,21 @@ private static ISymbol MapSymbol(ISymbol symbol, ITypeSymbol type) return symbol; } - private static TokenSemanticInfo GetSemanticInfo( - SemanticModel semanticModel, - ISemanticFactsService semanticFacts, - ISyntaxFactsService syntaxFacts, + public static TokenSemanticInfo GetSemanticInfo( + this SemanticModel semanticModel, SyntaxToken token, + Workspace workspace, CancellationToken cancellationToken) { + var languageServices = workspace.Services.GetLanguageServices(token.Language); + var syntaxFacts = languageServices.GetService(); + if (!syntaxFacts.IsBindableToken(token)) + { + return TokenSemanticInfo.Empty; + } + + var semanticFacts = languageServices.GetService(); + IAliasSymbol aliasSymbol; ITypeSymbol type; ITypeSymbol convertedType; diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/TokenSemanticInfo.cs b/src/Workspaces/Core/Portable/Shared/Extensions/TokenSemanticInfo.cs new file mode 100644 index 0000000000000000000000000000000000000000..8cf6fddc4db4d0a26b71a12b095cff5e354c8621 --- /dev/null +++ b/src/Workspaces/Core/Portable/Shared/Extensions/TokenSemanticInfo.cs @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Immutable; +using System.Linq; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Shared.Extensions +{ + internal struct TokenSemanticInfo + { + public static readonly TokenSemanticInfo Empty = new TokenSemanticInfo( + null, null, ImmutableArray.Empty, null, null, default(TextSpan)); + + public readonly ISymbol DeclaredSymbol; + public readonly IAliasSymbol AliasSymbol; + public readonly ImmutableArray ReferencedSymbols; + public readonly ITypeSymbol Type; + public readonly ITypeSymbol ConvertedType; + public readonly TextSpan Span; + + public TokenSemanticInfo( + ISymbol declaredSymbol, + IAliasSymbol aliasSymbol, + ImmutableArray referencedSymbols, + ITypeSymbol type, + ITypeSymbol convertedType, + TextSpan span) + { + DeclaredSymbol = declaredSymbol; + AliasSymbol = aliasSymbol; + ReferencedSymbols = referencedSymbols; + Type = type; + ConvertedType = convertedType; + Span = span; + } + + public ImmutableArray GetSymbols(bool includeType) + { + var result = ArrayBuilder.GetInstance(); + result.AddIfNotNull(DeclaredSymbol); + result.AddIfNotNull(AliasSymbol); + result.AddRange(ReferencedSymbols); + + if (includeType) + { + result.AddIfNotNull(Type ?? ConvertedType); + } + + return result.ToImmutableAndFree(); + } + + public ISymbol GetAnySymbol(bool includeType) + { + return GetSymbols(includeType).FirstOrDefault(); + } + } +}