Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Classification;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.SemanticSearch;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
Expand All @@ -24,9 +22,6 @@ public sealed class CSharpSemanticSearchServiceTests
private static readonly string s_referenceAssembliesDir = Path.Combine(Path.GetDirectoryName(typeof(CSharpSemanticSearchServiceTests).Assembly.Location!)!, "SemanticSearchRefs");
private static readonly char[] s_lineBreaks = ['\r', '\n'];

private static string Inspect(DefinitionItem def)
=> string.Join("", def.DisplayParts.Select(p => p.Text));

private static string InspectLine(int position, string text)
{
var lineStart = text.LastIndexOfAny(s_lineBreaks, position, position) + 1;
Expand Down Expand Up @@ -68,22 +63,21 @@ private static async Task VerifyCompileAndExecuteQueryAsync(
string query,
string[] expectedItems)
{
var items = new List<DefinitionItem>();
var observer = new MockSemanticSearchResultsObserver() { OnDefinitionFoundImpl = items.Add };
var symbols = new List<ISymbol>();
var observer = new MockSemanticSearchResultsObserver() { OnDefinitionFoundImpl = symbols.Add };

var solution = workspace.CurrentSolution;
var service = solution.Services.GetRequiredLanguageService<ISemanticSearchService>(LanguageNames.CSharp);
var options = workspace.GlobalOptions.GetClassificationOptionsProvider();
var traceSource = new TraceSource("test");

var compileResult = service.CompileQuery(solution.Services, query, s_referenceAssembliesDir, traceSource, CancellationToken.None);
Assert.Equal(LanguageNames.CSharp, compileResult.QueryId.Language);
Assert.Empty(compileResult.CompilationErrors);

var executeResult = await service.ExecuteQueryAsync(solution, compileResult.QueryId, observer, options, traceSource, CancellationToken.None);
var executeResult = await service.ExecuteQueryAsync(solution, compileResult.QueryId, observer, traceSource, CancellationToken.None);
Assert.Null(executeResult.ErrorMessage);

AssertEx.Equal(expectedItems, items.Select(Inspect).OrderBy(s => s));
AssertEx.Equal(expectedItems, symbols.Select(s => s.ToTestDisplayString()).OrderBy(s => s));
}

[ConditionalFact(typeof(CoreClrOnly))]
Expand All @@ -95,7 +89,7 @@ static IEnumerable<ISymbol> Find(Compilation compilation)
{
return compilation.GlobalNamespace.GetMembers("N");
}
""", ["namespace N"]);
""", ["N"]);
}

[ConditionalFact(typeof(CoreClrOnly))]
Expand All @@ -107,7 +101,7 @@ static IEnumerable<ISymbol> Find(INamespaceSymbol n)
{
return n.GetMembers("C");
}
""", ["class C"]);
""", ["N.C"]);
}

[ConditionalFact(typeof(CoreClrOnly))]
Expand All @@ -119,7 +113,7 @@ static IEnumerable<ISymbol> Find(INamedTypeSymbol type)
{
return type.GetMembers("F");
}
""", ["int C.F"]);
""", ["System.Int32 N.C.F"]);
}

[ConditionalFact(typeof(CoreClrOnly))]
Expand All @@ -133,11 +127,11 @@ static IEnumerable<ISymbol> Find(IMethodSymbol method)
}
""",
[
"C.C()",
"int C.P.get",
"void C.E.add",
"void C.E.remove",
"void C.VisibleMethod(int)",
"N.C..ctor()",
"System.Int32 N.C.P.get",
"void N.C.E.add",
"void N.C.E.remove",
"void N.C.VisibleMethod(System.Int32 param)"
]);
}

Expand All @@ -152,8 +146,8 @@ static IEnumerable<ISymbol> Find(IFieldSymbol field)
}
""",
[
"int C.F",
"readonly int C.P.field",
"System.Int32 N.C.<P>k__BackingField",
"System.Int32 N.C.F",
]);
}

Expand All @@ -168,7 +162,7 @@ static IEnumerable<ISymbol> Find(IPropertySymbol prop)
}
""",
[
"int C.P { get; }"
"System.Int32 N.C.P { get; }"
]);
}

Expand All @@ -183,7 +177,7 @@ static IEnumerable<ISymbol> Find(IEventSymbol e)
}
""",
[
"event Action C.E"
"event System.Action N.C.E"
]);
}

Expand Down Expand Up @@ -275,13 +269,12 @@ static IEnumerable<ISymbol> Find(Compilation compilation)
};

var traceSource = new TraceSource("test");
var options = workspace.GlobalOptions.GetClassificationOptionsProvider();

var compileResult = service.CompileQuery(solution.Services, query, s_referenceAssembliesDir, traceSource, CancellationToken.None);
Assert.Empty(compileResult.CompilationErrors);

await Assert.ThrowsAsync<TaskCanceledException>(
() => service.ExecuteQueryAsync(solution, compileResult.QueryId, observer, options, traceSource, cancellationSource.Token));
() => service.ExecuteQueryAsync(solution, compileResult.QueryId, observer, traceSource, cancellationSource.Token));

Assert.Empty(exceptions);
}
Expand Down Expand Up @@ -324,12 +317,11 @@ void F(long x)
};

var traceSource = new TraceSource("test");
var options = workspace.GlobalOptions.GetClassificationOptionsProvider();

var compileResult = service.CompileQuery(solution.Services, query, s_referenceAssembliesDir, traceSource, CancellationToken.None);
Assert.Empty(compileResult.CompilationErrors);

var result = await service.ExecuteQueryAsync(solution, compileResult.QueryId, observer, options, traceSource, CancellationToken.None);
var result = await service.ExecuteQueryAsync(solution, compileResult.QueryId, observer, traceSource, CancellationToken.None);
var expectedMessage = new InsufficientExecutionStackException().Message;
AssertEx.Equal(string.Format(FeaturesResources.Semantic_search_query_terminated_with_exception, "CSharpAssembly1", expectedMessage), result.ErrorMessage);

Expand Down Expand Up @@ -393,12 +385,11 @@ static ISymbol F(ISymbol s)
};

var traceSource = new TraceSource("test");
var options = workspace.GlobalOptions.GetClassificationOptionsProvider();

var compileResult = service.CompileQuery(solution.Services, query, s_referenceAssembliesDir, traceSource, CancellationToken.None);
Assert.Empty(compileResult.CompilationErrors);

var result = await service.ExecuteQueryAsync(solution, compileResult.QueryId, observer, options, traceSource, CancellationToken.None);
var result = await service.ExecuteQueryAsync(solution, compileResult.QueryId, observer, traceSource, CancellationToken.None);
var expectedMessage = new NullReferenceException().Message;
AssertEx.Equal(string.Format(FeaturesResources.Semantic_search_query_terminated_with_exception, "CSharpAssembly1", expectedMessage), result.ErrorMessage);

Expand Down Expand Up @@ -450,18 +441,16 @@ static IEnumerable<ISymbol> Find(IMethodSymbol method)
}
""";

var results = new List<DefinitionItem>();
var observer = new MockSemanticSearchResultsObserver() { OnDefinitionFoundImpl = results.Add };
var symbols = new List<ISymbol>();
var observer = new MockSemanticSearchResultsObserver() { OnDefinitionFoundImpl = symbols.Add };
var traceSource = new TraceSource("test");

var options = workspace.GlobalOptions.GetClassificationOptionsProvider();

var compileResult = service.CompileQuery(solution.Services, query, s_referenceAssembliesDir, traceSource, CancellationToken.None);
Assert.Empty(compileResult.CompilationErrors);

var result = await service.ExecuteQueryAsync(solution, compileResult.QueryId, observer, options, traceSource, CancellationToken.None);
var result = await service.ExecuteQueryAsync(solution, compileResult.QueryId, observer, traceSource, CancellationToken.None);

Assert.Null(result.ErrorMessage);
AssertEx.Equal(["void C.VisibleMethod(int)"], results.Select(Inspect));
AssertEx.Equal(["void N.C.VisibleMethod(System.Int32 param)"], symbols.Select(s => s.ToTestDisplayString()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.SemanticSearch;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.SemanticSearch;

internal sealed class MockSemanticSearchResultsObserver : ISemanticSearchResultsObserver
internal sealed class MockSemanticSearchResultsObserver() : ISemanticSearchResultsObserver
{
public Action<DefinitionItem>? OnDefinitionFoundImpl { get; set; }
public Action<ISymbol>? OnDefinitionFoundImpl { get; set; }
public Action<UserCodeExceptionInfo>? OnUserCodeExceptionImpl { get; set; }
public Action<ImmutableArray<QueryCompilationError>>? OnCompilationFailureImpl { get; set; }
public Action<int>? ItemsCompletedImpl { get; set; }
Expand All @@ -32,9 +31,9 @@ public ValueTask ItemsCompletedAsync(int itemCount, CancellationToken cancellati
return ValueTaskFactory.CompletedTask;
}

public ValueTask OnDefinitionFoundAsync(DefinitionItem definition, CancellationToken cancellationToken)
public ValueTask OnSymbolFoundAsync(Solution solution, ISymbol symbol, CancellationToken cancellationToken)
{
OnDefinitionFoundImpl?.Invoke(definition);
OnDefinitionFoundImpl?.Invoke(symbol);
return ValueTaskFactory.CompletedTask;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,6 @@ public async Task<ExecuteQueryResult> ExecuteQueryAsync(
Solution solution,
CompiledQueryId queryId,
ISemanticSearchResultsObserver observer,
OptionsProvider<ClassificationOptions> classificationOptions,
TraceSource traceSource,
CancellationToken cancellationToken)
{
Expand Down Expand Up @@ -179,7 +178,7 @@ public async Task<ExecuteQueryResult> ExecuteQueryAsync(
return CreateResult(errorMessage, errorMessageArgs);
}

var invocationContext = new QueryExecutionContext(query.Text, findMethod, observer, classificationOptions, traceSource);
var invocationContext = new QueryExecutionContext(query.Text, findMethod, observer, traceSource);
try
{
await invocationContext.InvokeAsync(solution, queryKind, cancellationToken).ConfigureAwait(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public ValueTask<ClassificationOptions> GetClassificationOptionsAsync(RemoteServ
=> ((ServerCallback)GetCallback(callbackId)).GetClassificationOptionsAsync(language, cancellationToken);
}

internal sealed class ServerCallback(Solution solution, ISemanticSearchResultsObserver observer, OptionsProvider<ClassificationOptions> classificationOptions)
internal sealed class ServerCallback(Solution solution, ISemanticSearchResultsDefinitionObserver observer)
{
public async ValueTask OnDefinitionFoundAsync(SerializableDefinitionItem definition, CancellationToken cancellationToken)
{
Expand Down Expand Up @@ -105,7 +105,7 @@ public async ValueTask<ClassificationOptions> GetClassificationOptionsAsync(stri
{
try
{
return await classificationOptions.GetOptionsAsync(solution.Services.GetLanguageServices(language), cancellationToken).ConfigureAwait(false);
return await observer.GetClassificationOptionsAsync(solution.Services.GetLanguageServices(language), cancellationToken).ConfigureAwait(false);
}
catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken))
{
Expand Down Expand Up @@ -139,12 +139,12 @@ await client.TryInvokeAsync<IRemoteSemanticSearchService>(
cancellationToken).ConfigureAwait(false);
}

public static async ValueTask<ExecuteQueryResult> ExecuteQueryAsync(Solution solution, CompiledQueryId queryId, ISemanticSearchResultsObserver results, OptionsProvider<ClassificationOptions> classificationOptions, CancellationToken cancellationToken)
public static async ValueTask<ExecuteQueryResult> ExecuteQueryAsync(Solution solution, CompiledQueryId queryId, ISemanticSearchResultsDefinitionObserver results, CancellationToken cancellationToken)
{
var client = await RemoteHostClient.TryGetClientAsync(solution.Services, cancellationToken).ConfigureAwait(false);
Contract.ThrowIfNull(client);

var serverCallback = new ServerCallback(solution, results, classificationOptions);
var serverCallback = new ServerCallback(solution, results);

var result = await client.TryInvokeAsync<IRemoteSemanticSearchService, ExecuteQueryResult>(
solution,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,31 @@
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Classification;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Text;

namespace Microsoft.CodeAnalysis.SemanticSearch;

internal interface ISemanticSearchResultsObserver
internal interface ISemanticSearchResultsCommonObserver
{
ValueTask OnUserCodeExceptionAsync(UserCodeExceptionInfo exception, CancellationToken cancellationToken);
ValueTask OnDefinitionFoundAsync(DefinitionItem definition, CancellationToken cancellationToken);
ValueTask AddItemsAsync(int itemCount, CancellationToken cancellationToken);
ValueTask ItemsCompletedAsync(int itemCount, CancellationToken cancellationToken);
}

internal interface ISemanticSearchResultsObserver : ISemanticSearchResultsCommonObserver
{
ValueTask OnSymbolFoundAsync(Solution solution, ISymbol symbol, CancellationToken cancellationToken);
}

internal interface ISemanticSearchResultsDefinitionObserver : ISemanticSearchResultsCommonObserver
{
ValueTask<ClassificationOptions> GetClassificationOptionsAsync(LanguageServices language, CancellationToken cancellationToken);
ValueTask OnDefinitionFoundAsync(DefinitionItem definition, CancellationToken cancellationToken);
}

[DataContract]
internal readonly record struct UserCodeExceptionInfo(
[property: DataMember(Order = 0)] string ProjectDisplayName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Classification;
using Microsoft.CodeAnalysis.Host;

namespace Microsoft.CodeAnalysis.SemanticSearch;
Expand All @@ -30,13 +29,11 @@ CompileQueryResult CompileQuery(
/// <param name="solution">The solution snapshot.</param>
/// <param name="queryId">Id of a compiled query.</param>
/// <param name="observer">Observer of the found symbols.</param>
/// <param name="classificationOptions">Options to use to classify the textual representation of the found symbols.</param>
/// <param name="cancellationToken">Cancellation token.</param>
Task<ExecuteQueryResult> ExecuteQueryAsync(
Solution solution,
CompiledQueryId queryId,
ISemanticSearchResultsObserver observer,
OptionsProvider<ClassificationOptions> classificationOptions,
TraceSource traceSource,
CancellationToken cancellationToken);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,8 @@ internal sealed class QueryExecutionContext(
SourceText queryText,
MethodInfo method,
ISemanticSearchResultsObserver resultsObserver,
OptionsProvider<ClassificationOptions> classificationOptions,
TraceSource traceSource)
{
private static readonly FindReferencesSearchOptions s_findReferencesSearchOptions = new()
{
DisplayAllDefinitions = true,
};

private const int StackDisplayDepthLimit = 32;

private long _executionTime;
Expand Down Expand Up @@ -154,10 +148,7 @@ private async ValueTask InvokeAsync(Project project, Compilation compilation, ob

try
{
var definitionItem = await symbol.ToClassifiedDefinitionItemAsync(
classificationOptions, project.Solution, s_findReferencesSearchOptions, isPrimary: true, includeHiddenLocations: false, cancellationToken).ConfigureAwait(false);

await resultsObserver.OnDefinitionFoundAsync(definitionItem, cancellationToken).ConfigureAwait(false);
await resultsObserver.OnSymbolFoundAsync(project.Solution, symbol, cancellationToken).ConfigureAwait(false);
}
catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken))
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// 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;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Classification;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.FindUsages;

namespace Microsoft.CodeAnalysis.SemanticSearch;

internal static class SemanticSearchDefinitionItemFactory
{
private static readonly FindReferencesSearchOptions s_findReferencesSearchOptions = new()
{
DisplayAllDefinitions = true,
};

public static ValueTask<DefinitionItem> CreateAsync(Solution solution, ISymbol symbol, OptionsProvider<ClassificationOptions> classificationOptions, CancellationToken cancellationToken)
=> symbol.ToClassifiedDefinitionItemAsync(
classificationOptions, solution, s_findReferencesSearchOptions, isPrimary: true, includeHiddenLocations: false, cancellationToken);
}
Loading
Loading