提交 95530c5a 编写于 作者: C Cyrus Najmabadi

Add callout (unimplemented) to finding rename locations

上级 0812ebfd
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Remote;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Rename
{
internal interface IRemoteRenamer
{
Task<SerializableRenameLocations> FindRenameLocationsAsync(
PinnedSolutionInfo solutionInfo, SerializableSymbolAndProjectId symbol, SerializableRenameOptionSet options, CancellationToken cancellationToken);
}
internal struct SerializableRenameOptionSet
{
public bool RenameOverloads;
public bool RenameInStrings;
public bool RenameInComments;
public bool RenameFile;
public static SerializableRenameOptionSet Dehydrate(RenameOptionSet optionSet)
=> new SerializableRenameOptionSet
{
RenameOverloads = optionSet.RenameOverloads,
RenameInStrings = optionSet.RenameInStrings,
RenameInComments = optionSet.RenameInComments,
RenameFile = optionSet.RenameFile,
};
public RenameOptionSet Rehydrate()
=> new RenameOptionSet(RenameOverloads, RenameInStrings, RenameInComments, RenameFile);
}
internal class SerializableSearchResult
{
// We use arrays so we can represent default immutable arrays.
public SerializableRenameLocation[] Locations;
public SerializableReferenceLocation[] ImplicitLocations;
public SerializableSymbolAndProjectId[] ReferencedSymbols;
public static SerializableSearchResult Dehydrate(Solution solution, RenameLocations.SearchResult result, CancellationToken cancellationToken)
=> result == null ? null : new SerializableSearchResult
{
Locations = result.Locations?.Select(loc => SerializableRenameLocation.Dehydrate(loc)).ToArray(),
ImplicitLocations = result.ImplicitLocations.IsDefault ? null : result.ImplicitLocations.Select(loc => SerializableReferenceLocation.Dehydrate(loc, cancellationToken)).ToArray(),
ReferencedSymbols = result.ReferencedSymbols.IsDefault ? null : result.ReferencedSymbols.Select(s => SerializableSymbolAndProjectId.Dehydrate(solution, s, cancellationToken)).ToArray(),
};
public async Task<RenameLocations.SearchResult> RehydrateAsync(Solution solution, CancellationToken cancellationToken)
{
ImmutableHashSet<RenameLocation> locations = null;
ImmutableArray<ReferenceLocation> implicitLocations = default;
ImmutableArray<ISymbol> referencedSymbols = default;
if (Locations != null)
{
using var _ = ArrayBuilder<RenameLocation>.GetInstance(out var builder);
foreach (var loc in Locations)
builder.Add(await loc.RehydrateAsync(solution, cancellationToken).ConfigureAwait(false));
locations = builder.ToImmutableHashSet();
}
if (ImplicitLocations != null)
{
using var _ = ArrayBuilder<ReferenceLocation>.GetInstance(out var builder);
foreach (var loc in ImplicitLocations)
builder.Add(await loc.RehydrateAsync(solution, cancellationToken).ConfigureAwait(false));
implicitLocations = builder.ToImmutable();
}
if (ReferencedSymbols != null)
{
using var _ = ArrayBuilder<ISymbol>.GetInstance(out var builder);
foreach (var symbol in ReferencedSymbols)
builder.AddIfNotNull(await symbol.TryRehydrateAsync(solution, cancellationToken).ConfigureAwait(false));
referencedSymbols = builder.ToImmutable();
}
return new RenameLocations.SearchResult(locations, implicitLocations, referencedSymbols);
}
}
internal struct SerializableRenameLocation
{
public TextSpan Location;
public DocumentId DocumentId;
public CandidateReason CandidateReason;
public bool IsRenamableAliasUsage;
public bool IsRenamableAccessor;
public TextSpan ContainingLocationForStringOrComment;
public bool IsWrittenTo;
public static SerializableRenameLocation Dehydrate(RenameLocation location)
=> new SerializableRenameLocation
{
Location = location.Location.SourceSpan,
DocumentId = location.DocumentId,
CandidateReason = location.CandidateReason,
IsRenamableAliasUsage = location.IsRenamableAliasUsage,
IsRenamableAccessor = location.IsRenamableAccessor,
ContainingLocationForStringOrComment = location.ContainingLocationForStringOrComment,
IsWrittenTo = location.IsWrittenTo,
};
public async Task<RenameLocation> RehydrateAsync(Solution solution, CancellationToken cancellation)
{
var document = solution.GetDocument(DocumentId);
var tree = await document.GetSyntaxTreeAsync(cancellation).ConfigureAwait(false);
return new RenameLocation(
CodeAnalysis.Location.Create(tree, Location),
DocumentId,
CandidateReason,
IsRenamableAliasUsage,
IsRenamableAccessor,
IsWrittenTo,
ContainingLocationForStringOrComment);
}
}
internal partial class RenameLocations
{
public static SerializableRenameLocations Dehydrate(Solution solution, RenameLocations locations, CancellationToken cancellationToken)
=> new SerializableRenameLocations
{
Symbol = SerializableSymbolAndProjectId.Dehydrate(solution, locations.Symbol, cancellationToken),
Options = SerializableRenameOptionSet.Dehydrate(locations.Options),
OriginalSymbolResult = SerializableSearchResult.Dehydrate(solution, locations._originalSymbolResult, cancellationToken),
MergedResult = SerializableSearchResult.Dehydrate(solution, locations._mergedResult, cancellationToken),
OverloadsResult = locations._overloadsResult.IsDefault ? null : locations._overloadsResult.Select(r => SerializableSearchResult.Dehydrate(solution, r, cancellationToken)).ToArray(),
StringsResult = locations._stringsResult.IsDefault ? null : locations._stringsResult.Select(r => SerializableRenameLocation.Dehydrate(r)).ToArray(),
CommentsResult = locations._commentsResult.IsDefault ? null : locations._commentsResult.Select(r => SerializableRenameLocation.Dehydrate(r)).ToArray(),
};
internal static async Task<RenameLocations> RehydrateAsync(Solution solution, SerializableRenameLocations locations, CancellationToken cancellationToken)
{
var symbol = await locations.Symbol.TryRehydrateAsync(solution, cancellationToken).ConfigureAwait(false);
if (symbol == null)
return null;
ImmutableArray<SearchResult> overloadsResult = default;
ImmutableArray<RenameLocation> stringsResult = default;
ImmutableArray<RenameLocation> commentsResult = default;
if (locations.OverloadsResult != null)
{
using var _ = ArrayBuilder<SearchResult>.GetInstance(out var builder);
foreach (var res in locations.OverloadsResult)
builder.Add(await res.RehydrateAsync(solution, cancellationToken).ConfigureAwait(false));
overloadsResult = builder.ToImmutable();
}
if (locations.StringsResult != null)
{
using var _ = ArrayBuilder<RenameLocation>.GetInstance(out var builder);
foreach (var res in locations.StringsResult)
builder.Add(await res.RehydrateAsync(solution, cancellationToken).ConfigureAwait(false));
stringsResult = builder.ToImmutable();
}
if (locations.CommentsResult != null)
{
using var _ = ArrayBuilder<RenameLocation>.GetInstance(out var builder);
foreach (var res in locations.CommentsResult)
builder.Add(await res.RehydrateAsync(solution, cancellationToken).ConfigureAwait(false));
commentsResult = builder.ToImmutable();
}
return new RenameLocations(
symbol,
solution,
locations.Options.Rehydrate(),
await locations.OriginalSymbolResult.RehydrateAsync(solution, cancellationToken).ConfigureAwait(false),
await locations.MergedResult.RehydrateAsync(solution, cancellationToken).ConfigureAwait(false),
overloadsResult,
stringsResult,
commentsResult);
}
}
internal struct SerializableRenameLocations
{
public SerializableSymbolAndProjectId Symbol;
public SerializableRenameOptionSet Options;
public SerializableSearchResult OriginalSymbolResult;
public SerializableSearchResult MergedResult;
// We use arrays so we can represent default immutable arrays.
public SerializableSearchResult[] OverloadsResult;
public SerializableRenameLocation[] StringsResult;
public SerializableRenameLocation[] CommentsResult;
}
}
......@@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Rename
{
internal sealed partial class RenameLocations
{
private class SearchResult
public class SearchResult
{
public readonly ImmutableHashSet<RenameLocation> Locations;
public readonly ImmutableArray<ReferenceLocation> ImplicitLocations;
......
......@@ -24,9 +24,8 @@ namespace Microsoft.CodeAnalysis.Rename
/// </summary>
internal sealed partial class RenameLocations
{
public readonly ISymbol Symbol;
public readonly Solution Solution;
public readonly ISymbol Symbol;
public readonly RenameOptionSet Options;
// possibly null
......@@ -49,8 +48,8 @@ internal sealed partial class RenameLocations
ImmutableArray<RenameLocation> stringsResult,
ImmutableArray<RenameLocation> commentsResult)
{
Symbol = symbol;
Solution = solution;
Symbol = symbol;
Options = options;
_originalSymbolResult = originalSymbolResult;
_mergedResult = mergedResult;
......
......@@ -6,7 +6,9 @@
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Remote;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Rename
......@@ -34,7 +36,7 @@ public static class Renamer
return RenameSymbolAsync(solution, symbol, newName, renameOptions, nonConflictSymbols: null, cancellationToken);
}
internal static Task<RenameLocations> FindRenameLocationsAsync(
internal static async Task<RenameLocations> FindRenameLocationsAsync(
Solution solution, ISymbol symbol, RenameOptionSet options, CancellationToken cancellationToken)
{
Contract.ThrowIfNull(solution);
......@@ -43,8 +45,34 @@ public static class Renamer
cancellationToken.ThrowIfCancellationRequested();
return RenameLocations.FindLocationsInCurrentProcessAsync(
symbol, solution, options, cancellationToken);
using (Logger.LogBlock(FunctionId.Renamer_FindRenameLocationsAsync, cancellationToken))
{
var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false);
if (client != null)
{
var result = await client.TryRunRemoteAsync<SerializableRenameLocations>(
WellKnownServiceHubServices.CodeAnalysisService,
nameof(IRemoteRenamer.FindRenameLocationsAsync),
solution,
new object[]
{
SerializableSymbolAndProjectId.Dehydrate(solution, symbol, cancellationToken),
SerializableRenameOptionSet.Dehydrate(options),
},
callbackTarget: null,
cancellationToken).ConfigureAwait(false);
if (result.HasValue)
{
return await RenameLocations.RehydrateAsync(
solution, result.Value, cancellationToken).ConfigureAwait(false);
}
}
}
// Couldn't effectively search in OOP. Perform the search in-proc.
return await RenameLocations.FindLocationsInCurrentProcessAsync(
symbol, solution, options, cancellationToken).ConfigureAwait(false);
}
internal static async Task<Solution> RenameAsync(
......
......@@ -479,5 +479,8 @@ internal enum FunctionId
CodeFixes_AddExplicitCast = 384,
ToolsOptions_GenerateEditorconfig = 385,
Renamer_RenameSymbolAsync = 386,
Renamer_FindRenameLocationsAsync = 386,
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册