提交 c5273fc3 编写于 作者: M Manish Vasani

Merge remote-tracking branch 'upstream/master' into RegisterAdditionalFileAction

......@@ -25,6 +25,8 @@ public ExtensionMethodImportCompletionProviderTests(CSharpTestWorkspaceFixture w
{
}
private const string NonBreakingSpaceString = "\x00A0";
private bool? ShowImportCompletionItemsOptionValue { get; set; } = true;
private bool IsExpandedCompletion { get; set; } = true;
......@@ -1667,6 +1669,61 @@ public void M(int x)
expectedDescriptionOrNull: $"({CSharpFeaturesResources.extension}) bool int.ExtentionMethod<int>()");
}
[InlineData(ReferenceType.Project)]
[InlineData(ReferenceType.Metadata)]
[Theory, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task TestDescriptionOfOverloads(ReferenceType refType)
{
var refDoc = @"
using System;
namespace NS2
{
public static class Extensions
{
public static bool ExtentionMethod(this int t) => false;
public static bool ExtentionMethod(this int t, int a) => false;
public static bool ExtentionMethod(this int t, int a, int b) => false;
public static bool ExtentionMethod<T>(this int t, T a) => false;
public static bool ExtentionMethod<T>(this int t, T a, T b) => false;
public static bool ExtentionMethod<T1, T2>(this int t, T1 a, T2 b) => false;
}
}";
var srcDoc = @"
namespace NS1
{
public class C
{
public void M(int x)
{
x.$$
}
}
}";
var markup = refType switch
{
ReferenceType.Project => CreateMarkupForProjectWithProjectReference(srcDoc, refDoc, LanguageNames.CSharp, LanguageNames.CSharp),
ReferenceType.Metadata => CreateMarkupForProjectWithMetadataReference(srcDoc, refDoc, LanguageNames.CSharp, LanguageNames.CSharp),
_ => null,
};
await VerifyImportItemExistsAsync(
markup,
"ExtentionMethod",
glyph: (int)Glyph.ExtensionMethodPublic,
inlineDescription: "NS2",
expectedDescriptionOrNull: $"({CSharpFeaturesResources.extension}) bool int.ExtentionMethod() (+{NonBreakingSpaceString}2{NonBreakingSpaceString}{FeaturesResources.overloads_})");
await VerifyImportItemExistsAsync(
markup,
"ExtentionMethod",
displayTextSuffix: "<>",
glyph: (int)Glyph.ExtensionMethodPublic,
inlineDescription: "NS2",
expectedDescriptionOrNull: $"({CSharpFeaturesResources.extension}) bool int.ExtentionMethod<T>(T a) (+{NonBreakingSpaceString}2{NonBreakingSpaceString}{FeaturesResources.generic_overloads})");
}
private Task VerifyImportItemExistsAsync(string markup, string expectedItem, int glyph, string inlineDescription, string displayTextSuffix = null, string expectedDescriptionOrNull = null)
=> VerifyItemExistsAsync(markup, expectedItem, displayTextSuffix: displayTextSuffix, glyph: glyph, inlineDescription: inlineDescription, expectedDescriptionOrNull: expectedDescriptionOrNull);
......
......@@ -503,7 +503,7 @@ class D
public int P2 { get; set; }
}
";
await VerifyItemExistsAsync(markup, "P1");
await VerifyNoItemsExistAsync(markup);
}
[Fact]
......
......@@ -29,15 +29,12 @@ internal enum ActionInfo
TargetTypeCompletionTicks,
ExtensionMethodCompletionSuccessCount,
// following are only reported when successful (i.e. filter is available)
ExtensionMethodCompletionTicks,
ExtensionMethodCompletionMethodsProvided,
ExtensionMethodCompletionGetFilterTicks,
ExtensionMethodCompletionGetSymbolTicks,
ExtensionMethodCompletionTypesChecked,
ExtensionMethodCompletionMethodsChecked,
ExtensionMethodCompletionGetSymbolsTicks,
ExtensionMethodCompletionCreateItemsTicks,
CommitsOfExtensionMethodImportCompletionItem,
ExtensionMethodCompletionPartialResultCount,
}
internal static void LogTypeImportCompletionTicksDataPoint(int count)
......@@ -61,9 +58,6 @@ internal static void LogTypeImportCompletionTicksDataPoint(int count)
internal static void LogTargetTypeCompletionTicksDataPoint(int count) =>
s_statisticLogAggregator.AddDataPoint((int)ActionInfo.TargetTypeCompletionTicks, count);
internal static void LogExtensionMethodCompletionSuccess() =>
s_logAggregator.IncreaseCount((int)ActionInfo.ExtensionMethodCompletionSuccessCount);
internal static void LogExtensionMethodCompletionTicksDataPoint(int count)
{
s_histogramLogAggregator.IncreaseCount((int)ActionInfo.ExtensionMethodCompletionTicks, count);
......@@ -73,21 +67,18 @@ internal static void LogExtensionMethodCompletionTicksDataPoint(int count)
internal static void LogExtensionMethodCompletionMethodsProvidedDataPoint(int count) =>
s_statisticLogAggregator.AddDataPoint((int)ActionInfo.ExtensionMethodCompletionMethodsProvided, count);
internal static void LogExtensionMethodCompletionGetFilterTicksDataPoint(int count) =>
s_statisticLogAggregator.AddDataPoint((int)ActionInfo.ExtensionMethodCompletionGetFilterTicks, count);
internal static void LogExtensionMethodCompletionGetSymbolTicksDataPoint(int count) =>
s_statisticLogAggregator.AddDataPoint((int)ActionInfo.ExtensionMethodCompletionGetSymbolTicks, count);
internal static void LogExtensionMethodCompletionGetSymbolsTicksDataPoint(int count) =>
s_statisticLogAggregator.AddDataPoint((int)ActionInfo.ExtensionMethodCompletionGetSymbolsTicks, count);
internal static void LogExtensionMethodCompletionTypesCheckedDataPoint(int count) =>
s_statisticLogAggregator.AddDataPoint((int)ActionInfo.ExtensionMethodCompletionTypesChecked, count);
internal static void LogExtensionMethodCompletionMethodsCheckedDataPoint(int count) =>
s_statisticLogAggregator.AddDataPoint((int)ActionInfo.ExtensionMethodCompletionMethodsChecked, count);
internal static void LogExtensionMethodCompletionCreateItemsTicksDataPoint(int count) =>
s_statisticLogAggregator.AddDataPoint((int)ActionInfo.ExtensionMethodCompletionCreateItemsTicks, count);
internal static void LogCommitOfExtensionMethodImportCompletionItem() =>
s_logAggregator.IncreaseCount((int)ActionInfo.CommitsOfExtensionMethodImportCompletionItem);
internal static void LogExtensionMethodCompletionPartialResultCount() =>
s_logAggregator.IncreaseCount((int)ActionInfo.ExtensionMethodCompletionPartialResultCount);
internal static void ReportTelemetry()
{
Logger.Log(FunctionId.Intellisense_CompletionProviders_Data, KeyValueLogMessage.Create(m =>
......
......@@ -39,7 +39,7 @@ protected override void LogCommit()
var syntaxFacts = completionContext.Document.GetRequiredLanguageService<ISyntaxFactsService>();
if (TryGetReceiverTypeSymbol(syntaxContext, syntaxFacts, cancellationToken, out var receiverTypeSymbol))
{
var items = await ExtensionMethodImportCompletionHelper.GetUnimportedExtensionMethodsAsync(
var (items, counter) = await ExtensionMethodImportCompletionHelper.GetUnimportedExtensionMethodsAsync(
completionContext.Document,
completionContext.Position,
receiverTypeSymbol,
......@@ -113,6 +113,6 @@ private CompletionItem Convert(SerializableImportCompletionItem serializableItem
serializableItem.Glyph,
GenericSuffix,
CompletionItemFlags.Expanded,
(serializableItem.SymbolKeyData, receiverTypeSymbolKey));
(serializableItem.SymbolKeyData, receiverTypeSymbolKey, serializableItem.AdditionalOverloadCount));
}
}
......@@ -30,6 +30,8 @@ internal static partial class ExtensionMethodImportCompletionHelper
/// </summary>
public readonly MultiDictionary<string, DeclaredSymbolInfo> ReceiverTypeNameToExtensionMethodMap { get; }
public bool ContainsExtensionMethod => !ReceiverTypeNameToExtensionMethodMap.IsEmpty;
private CacheEntry(
Checksum checksum,
string language,
......
......@@ -22,11 +22,19 @@ internal static class ImportCompletionItem
private const string AttributeFullName = nameof(AttributeFullName);
private const string MethodKey = nameof(MethodKey);
private const string ReceiverKey = nameof(ReceiverKey);
private const string OverloadCountKey = nameof(OverloadCountKey);
public static CompletionItem Create(INamedTypeSymbol typeSymbol, string containingNamespace, string genericTypeSuffix)
=> Create(typeSymbol.Name, typeSymbol.Arity, containingNamespace, typeSymbol.GetGlyph(), genericTypeSuffix, CompletionItemFlags.CachedAndExpanded, extensionMethodData: null);
public static CompletionItem Create(string name, int arity, string containingNamespace, Glyph glyph, string genericTypeSuffix, CompletionItemFlags flags, (string methodSymbolKey, string receiverTypeSymbolKey)? extensionMethodData)
public static CompletionItem Create(
string name,
int arity,
string containingNamespace,
Glyph glyph,
string genericTypeSuffix,
CompletionItemFlags flags,
(string methodSymbolKey, string receiverTypeSymbolKey, int overloadCount)? extensionMethodData)
{
ImmutableDictionary<string, string>? properties = null;
......@@ -38,6 +46,11 @@ public static CompletionItem Create(string name, int arity, string containingNam
{
builder.Add(MethodKey, extensionMethodData.Value.methodSymbolKey);
builder.Add(ReceiverKey, extensionMethodData.Value.receiverTypeSymbolKey);
if (extensionMethodData.Value.overloadCount > 0)
{
builder.Add(OverloadCountKey, extensionMethodData.Value.overloadCount.ToString());
}
}
else
{
......@@ -102,21 +115,18 @@ public static string GetContainingNamespace(CompletionItem item)
public static async Task<CompletionDescription> GetCompletionDescriptionAsync(Document document, CompletionItem item, CancellationToken cancellationToken)
{
var compilation = (await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false));
var symbol = GetSymbol(item, compilation);
var (symbol, overloadCount) = GetSymbolAndOverloadCount(item, compilation);
if (symbol != null)
{
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
// We choose not to display the number of "type overloads" for simplicity.
// Otherwise, we need additional logic to track internal and public visible
// types separately, and cache both completion items.
return await CommonCompletionUtilities.CreateDescriptionAsync(
document.Project.Solution.Workspace,
semanticModel,
position: 0,
symbol,
overloadCount: 0,
overloadCount,
supportedPlatforms: null,
cancellationToken).ConfigureAwait(false);
}
......@@ -127,7 +137,7 @@ public static async Task<CompletionDescription> GetCompletionDescriptionAsync(Do
private static string GetFullyQualifiedName(string namespaceName, string typeName)
=> namespaceName.Length == 0 ? typeName : namespaceName + "." + typeName;
private static ISymbol? GetSymbol(CompletionItem item, Compilation compilation)
private static (ISymbol? symbol, int overloadCount) GetSymbolAndOverloadCount(CompletionItem item, Compilation compilation)
{
// If we have SymbolKey data (i.e. this is an extension method item), use it to recover symbol
if (item.Properties.TryGetValue(MethodKey, out var methodSymbolKey))
......@@ -136,17 +146,21 @@ private static string GetFullyQualifiedName(string namespaceName, string typeNam
if (methodSymbol != null)
{
var overloadCount = item.Properties.TryGetValue(OverloadCountKey, out var overloadCountString) && int.TryParse(overloadCountString, out var count) ? count : 0;
// Get reduced extension method symbol for the given receiver type.
if (item.Properties.TryGetValue(ReceiverKey, out var receiverTypeKey))
{
if (SymbolKey.ResolveString(receiverTypeKey, compilation).GetAnySymbol() is ITypeSymbol receiverTypeSymbol)
{
return methodSymbol.ReduceExtensionMethod(receiverTypeSymbol) ?? methodSymbol;
return (methodSymbol.ReduceExtensionMethod(receiverTypeSymbol) ?? methodSymbol, overloadCount);
}
}
return (methodSymbol, overloadCount);
}
return methodSymbol;
return default;
}
// Otherwise, this is a type item, so we don't have SymbolKey data. But we should still have all
......@@ -154,12 +168,16 @@ private static string GetFullyQualifiedName(string namespaceName, string typeNam
var containingNamespace = GetContainingNamespace(item);
var typeName = item.Properties.TryGetValue(AttributeFullName, out var attributeFullName) ? attributeFullName : item.DisplayText;
var fullyQualifiedName = GetFullyQualifiedName(containingNamespace, typeName);
// We choose not to display the number of "type overloads" for simplicity.
// Otherwise, we need additional logic to track internal and public visible
// types separately, and cache both completion items.
if (item.Properties.TryGetValue(TypeAritySuffixName, out var aritySuffix))
{
return compilation.GetTypeByMetadataName(fullyQualifiedName + aritySuffix);
return (compilation.GetTypeByMetadataName(fullyQualifiedName + aritySuffix), 0);
}
return compilation.GetTypeByMetadataName(fullyQualifiedName);
return (compilation.GetTypeByMetadataName(fullyQualifiedName), 0);
}
}
}
......@@ -13,14 +13,16 @@ namespace Microsoft.CodeAnalysis.Completion.Providers
public readonly string Name;
public readonly Glyph Glyph;
public readonly string ContainingNamespace;
public readonly int AdditionalOverloadCount;
public SerializableImportCompletionItem(string symbolKeyData, string name, int arity, Glyph glyph, string containingNamespace)
public SerializableImportCompletionItem(string symbolKeyData, string name, int arity, Glyph glyph, string containingNamespace, int additionalOverloadCount)
{
SymbolKeyData = symbolKeyData;
Arity = arity;
Name = name;
Glyph = glyph;
ContainingNamespace = containingNamespace;
AdditionalOverloadCount = additionalOverloadCount;
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册