提交 e4adebbe 编写于 作者: C CyrusNajmabadi 提交者: GitHub

Merge pull request #13059 from CyrusNajmabadi/clearerFuzzyMatches

Make fuzzy add-using matches clearer

Fixes #12985
......@@ -47,21 +47,11 @@ protected override CodeActionPriority GetPriority(Document document)
if (document.Project.Id == _project.Id)
{
if (!SearchResult.DesiredNameDiffersFromSourceName())
if (SearchResult.DesiredNameMatchesSourceName(document))
{
// The name doesn't change. This is a normal priority action.
return CodeActionPriority.Medium;
}
// We need to update the source name. If all we're doing is changing the
// casing, and this is a case insensitive language, then this is just a
// normal priority action. Otherwise, this wil be low priority.
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
if (!syntaxFacts.IsCaseSensitive &&
SearchResult.DesiredNameDiffersFromSourceNameOnlyByCase())
{
return CodeActionPriority.Medium;
}
}
// This is a weaker match. This should be lower than all other fixes.
......
......@@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.CodeFixes.AddImport
{
internal abstract partial class AbstractAddImportCodeFixProvider<TSimpleNameSyntax>
{
private abstract class Reference : IComparable<Reference>, IEquatable<Reference>
private abstract class Reference : IEquatable<Reference>
{
protected readonly AbstractAddImportCodeFixProvider<TSimpleNameSyntax> provider;
public readonly SearchResult SearchResult;
......@@ -24,7 +24,7 @@ protected Reference(AbstractAddImportCodeFixProvider<TSimpleNameSyntax> provider
this.SearchResult = searchResult;
}
public virtual int CompareTo(Reference other)
public int CompareTo(Document document, Reference other)
{
// If references have different weights, order by the ones with lower weight (i.e.
// they are better matches).
......@@ -38,7 +38,36 @@ public virtual int CompareTo(Reference other)
return 1;
}
// If the weight are the same, just order them based on their names.
if (this.SearchResult.DesiredNameMatchesSourceName(document))
{
if (!other.SearchResult.DesiredNameMatchesSourceName(document))
{
// Prefer us as our name doesn't need to change.
return -1;
}
}
else
{
if (other.SearchResult.DesiredNameMatchesSourceName(document))
{
// Prefer them as their name doesn't need to change.
return 1;
}
else
{
// Both our names need to change. Sort by the name we're
// changing to.
var diff = StringComparer.OrdinalIgnoreCase.Compare(
this.SearchResult.DesiredName, other.SearchResult.DesiredName);
if (diff != 0)
{
return diff;
}
}
}
// If the weights are the same and no names changed, just order
// them based on the namespace we're adding an import for.
return INamespaceOrTypeSymbolExtensions.CompareNameParts(
this.SearchResult.NameParts, other.SearchResult.NameParts);
}
......
......@@ -26,19 +26,6 @@ public SymbolReference(AbstractAddImportCodeFixProvider<TSimpleNameSyntax> provi
protected abstract Glyph? GetGlyph(Document document);
protected abstract bool CheckForExistingImport(Project project);
public override int CompareTo(Reference other)
{
var diff = base.CompareTo(other);
if (diff != 0)
{
return diff;
}
var name1 = this.SymbolResult.DesiredName;
var name2 = (other as SymbolReference)?.SymbolResult.DesiredName;
return StringComparer.Ordinal.Compare(name1, name2);
}
public override bool Equals(object obj)
{
var equals = base.Equals(obj);
......@@ -88,6 +75,13 @@ public override int GetHashCode()
return null;
}
if (!this.SearchResult.DesiredNameMatchesSourceName(document))
{
// The name is going to change. Make it clear in the description that
// this is going to happen.
description = $"{this.SearchResult.DesiredName} - {description}";
}
return new OperationBasedCodeAction(description, GetGlyph(document), GetPriority(document),
c => this.GetOperationsAsync(document, node, placeSystemNamespaceFirst, c),
this.GetIsApplicableCheck(document.Project));
......
......@@ -74,10 +74,10 @@ private INamespaceSymbol MapToCompilationNamespaceIfPossible(INamespaceSymbol co
return _semanticModel.Compilation.GetCompilationNamespace(containingNamespace) ?? containingNamespace;
}
internal Task<List<SymbolReference>> FindInAllSymbolsInProjectAsync(
Project project, bool exact, CancellationToken cancellationToken)
internal Task<List<SymbolReference>> FindInAllSymbolsInStartingProjectAsync(
bool exact, CancellationToken cancellationToken)
{
var searchScope = new AllSymbolsProjectSearchScope(_owner, project, exact, cancellationToken);
var searchScope = new AllSymbolsProjectSearchScope(_owner, _document.Project, exact, cancellationToken);
return DoAsync(searchScope);
}
......@@ -91,11 +91,11 @@ private INamespaceSymbol MapToCompilationNamespaceIfPossible(INamespaceSymbol co
}
internal Task<List<SymbolReference>> FindInMetadataSymbolsAsync(
Solution solution, IAssemblySymbol assembly, PortableExecutableReference metadataReference,
IAssemblySymbol assembly, PortableExecutableReference metadataReference,
bool exact, CancellationToken cancellationToken)
{
var searchScope = new MetadataSymbolsSearchScope(
_owner, solution, assembly, metadataReference, exact, cancellationToken);
_owner, _document.Project.Solution, assembly, metadataReference, exact, cancellationToken);
return DoAsync(searchScope);
}
......@@ -153,7 +153,7 @@ private List<SymbolReference> DeDupeAndSortReferences(List<SymbolReference> allR
.Distinct()
.Where(NotNull)
.Where(NotGlobalNamespace)
.Order()
.OrderBy((r1, r2) => r1.CompareTo(_document, r2))
.ToList();
}
......
......@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.CodeFixes.AddImport
......@@ -49,6 +50,27 @@ public bool DesiredNameDiffersFromSourceNameOnlyByCase()
return StringComparer.OrdinalIgnoreCase.Equals(
this.NameNode.GetFirstToken().ValueText, this.DesiredName);
}
public bool DesiredNameMatchesSourceName(Document document)
{
if (!this.DesiredNameDiffersFromSourceName())
{
// Names match in any language.
return true;
}
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
// Names differ. But in a case insensitive language they may match.
if (!syntaxFacts.IsCaseSensitive &&
this.DesiredNameDiffersFromSourceNameOnlyByCase())
{
return true;
}
// Name are totally different in any language.
return false;
}
}
private struct SymbolResult<T> where T : ISymbol
......
......@@ -160,8 +160,8 @@ private static bool IsHostOrTestWorkspace(Project project)
// First search the current project to see if any symbols (source or metadata) match the
// search string.
await FindResultsInAllProjectSymbolsAsync(
project, allReferences, finder, exact, cancellationToken).ConfigureAwait(false);
await FindResultsInAllSymbolsInStartingProjectAsync(
allReferences, finder, exact, cancellationToken).ConfigureAwait(false);
// Only bother doing this for host workspaces. We don't want this for
// things like the Interactive workspace as we can't even add project
......@@ -186,11 +186,11 @@ private static bool IsHostOrTestWorkspace(Project project)
return allReferences;
}
private async Task FindResultsInAllProjectSymbolsAsync(
Project project, List<Reference> allSymbolReferences,
SymbolReferenceFinder finder, bool exact, CancellationToken cancellationToken)
private async Task FindResultsInAllSymbolsInStartingProjectAsync(
List<Reference> allSymbolReferences, SymbolReferenceFinder finder,
bool exact, CancellationToken cancellationToken)
{
var references = await finder.FindInAllSymbolsInProjectAsync(project, exact, cancellationToken).ConfigureAwait(false);
var references = await finder.FindInAllSymbolsInStartingProjectAsync(exact, cancellationToken).ConfigureAwait(false);
AddRange(allSymbolReferences, references);
}
......@@ -272,7 +272,7 @@ private static bool IsHostOrTestWorkspace(Project project)
if (assembly != null)
{
findTasks.Add(finder.FindInMetadataSymbolsAsync(
project.Solution, assembly, reference, exact, linkedTokenSource.Token));
assembly, reference, exact, linkedTokenSource.Token));
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册