提交 d2785c62 编写于 作者: G Gen Lu

Address some review comments

上级 216344dc
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Completion.Providers;
......@@ -14,7 +17,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers
internal sealed class ExtensionMethodImportCompletionProvider : AbstractExtensionMethodImportCompletionProvider
{
internal override bool IsInsertionTrigger(SourceText text, int characterPosition, OptionSet options)
=> ImportCompletionProviderHelper.IsInsertionTrigger(text, characterPosition, options);
=> CompletionUtilities.IsTriggerCharacter(text, characterPosition, options);
protected override ImmutableArray<string> GetImportedNamespaces(
SyntaxNode location,
......@@ -28,20 +31,17 @@ protected override Task<SyntaxContext> CreateContextAsync(Document document, int
protected override Task<bool> IsInImportsDirectiveAsync(Document document, int position, CancellationToken cancellationToken)
=> ImportCompletionProviderHelper.IsInImportsDirectiveAsync(document, position, cancellationToken);
protected override bool TryGetReceiverTypeSymbol(SyntaxContext syntaxContext, out ITypeSymbol receiverTypeSymbol)
protected override bool TryGetReceiverTypeSymbol(SyntaxContext syntaxContext, [NotNullWhen(true)] out ITypeSymbol? receiverTypeSymbol)
{
if (syntaxContext.TargetToken.Parent is MemberAccessExpressionSyntax memberAccess)
{
var symbol = syntaxContext.SemanticModel.GetSymbolInfo(memberAccess.Expression).Symbol;
switch (symbol?.Kind)
if (symbol == null ||
symbol.Kind != SymbolKind.NamedType && symbol.Kind != SymbolKind.TypeParameter)
{
case null:
case SymbolKind.Field:
case SymbolKind.Local:
case SymbolKind.Parameter:
case SymbolKind.Property:
receiverTypeSymbol = syntaxContext.SemanticModel.GetTypeInfo(memberAccess.Expression).Type;
return receiverTypeSymbol != null;
receiverTypeSymbol = syntaxContext.SemanticModel.GetTypeInfo(memberAccess.Expression).Type;
return receiverTypeSymbol != null;
}
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers
{
internal static class ImportCompletionProviderHelper
{
public static bool IsInsertionTrigger(SourceText text, int characterPosition, OptionSet options)
=> CompletionUtilities.IsTriggerCharacter(text, characterPosition, options);
public static ImmutableArray<string> GetImportedNamespaces(
SyntaxNode location,
SemanticModel semanticModel,
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
......@@ -13,7 +15,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers
internal sealed class TypeImportCompletionProvider : AbstractTypeImportCompletionProvider
{
internal override bool IsInsertionTrigger(SourceText text, int characterPosition, OptionSet options)
=> ImportCompletionProviderHelper.IsInsertionTrigger(text, characterPosition, options);
=> CompletionUtilities.IsTriggerCharacter(text, characterPosition, options);
protected override ImmutableArray<string> GetImportedNamespaces(
SyntaxNode location,
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System.Composition;
using Microsoft.CodeAnalysis.Completion.Providers.ImportCompletion;
using Microsoft.CodeAnalysis.Host;
......
......@@ -20,7 +20,7 @@ namespace Microsoft.CodeAnalysis.Completion.Providers
{
internal abstract class AbstractExtensionMethodImportCompletionProvider : AbstractImportCompletionProvider
{
protected abstract bool TryGetReceiverTypeSymbol(SyntaxContext syntaxContext, out ITypeSymbol receiverTypeSymbol);
protected abstract bool TryGetReceiverTypeSymbol(SyntaxContext syntaxContext, [NotNullWhen(true)] out ITypeSymbol? receiverTypeSymbol);
protected override bool ShouldProvideCompletion(Document document, SyntaxContext syntaxContext)
=> syntaxContext.IsRightOfNameSeparator && IsAddingImportsSupported(document);
......@@ -40,8 +40,8 @@ protected override bool ShouldProvideCompletion(Document document, SyntaxContext
var tick = Environment.TickCount;
using var allTypeNamesDisposer = PooledHashSet<string>.GetInstance(out var allTypeNames);
allTypeNames.Add(GetSimpleTypeName(receiverTypeSymbol));
allTypeNames.AddRange(receiverTypeSymbol.GetBaseTypes().Concat(receiverTypeSymbol.GetAllInterfacesIncludingThis()).Select(t => t.MetadataName));
allTypeNames.Add(receiverTypeSymbol.MetadataName);
allTypeNames.AddRange(receiverTypeSymbol.GetBaseTypes().Concat(receiverTypeSymbol.GetAllInterfacesIncludingThis()).Select(s => s.MetadataName));
// interface doesn't inherit from object, but is implicitly convertable to object type.
if (receiverTypeSymbol.IsInterfaceType())
......@@ -66,14 +66,13 @@ protected override bool ShouldProvideCompletion(Document document, SyntaxContext
telemetryCounter.TotalExtensionMethodsProvided = items.Count;
}
static string GetSimpleTypeName(ITypeSymbol typeSymbol)
static string GetMetadataNameWithoutBackticks(ITypeSymbol typeSymbol)
{
if (typeSymbol is IArrayTypeSymbol arraySymbol)
{
return GetSimpleTypeName(arraySymbol.ElementType);
}
return typeSymbol.MetadataName;
var name = typeSymbol.MetadataName;
var backtickIndex = name.IndexOf('`');
return backtickIndex == -1
? name
: name.Substring(0, backtickIndex);
}
}
......@@ -231,7 +230,6 @@ static string GetSimpleTypeName(ITypeSymbol typeSymbol)
continue;
}
// Add simple extension methods with matching target type name
foreach (var targetTypeName in targetTypeNames)
{
foreach (var methodInfo in info.GetMatchingExtensionMethodInfo(targetTypeName))
......
......@@ -61,7 +61,7 @@ internal partial class SymbolTreeInfo : IChecksummedObject
private readonly MultiDictionary<string, ExtensionMethodInfo> _simpleTypeNameToExtensionMethodMap;
/// <summary>
/// A list of <see cref="ExtensionMethodInfo" /> for compelx methods.
/// A list of <see cref="ExtensionMethodInfo" /> for complex methods.
/// </summary>
private readonly ImmutableArray<ExtensionMethodInfo> _extensionMethodOfComplexType;
......
......@@ -697,8 +697,12 @@ private ImmutableArray<BuilderNode> GenerateUnsortedNodes(ArrayBuilder<Extension
return unsortedNodes.ToImmutableAndFree();
}
private void AddUnsortedNodes(
ArrayBuilder<BuilderNode> unsortedNodes, MultiDictionary<string, ExtensionMethodInfo> simpleBuilder, ArrayBuilder<ExtensionMethodInfo> complexBuilder, MetadataNode parentNode, int parentIndex, string fullyQualifiedContainerName)
private void AddUnsortedNodes(ArrayBuilder<BuilderNode> unsortedNodes,
MultiDictionary<string, ExtensionMethodInfo> simpleBuilder,
ArrayBuilder<ExtensionMethodInfo> complexBuilder,
MetadataNode parentNode,
int parentIndex,
string fullyQualifiedContainerName)
{
foreach (var child in _parentToChildren[parentNode])
{
......
......@@ -119,8 +119,8 @@ private static async Task<Checksum> ComputeSourceSymbolsChecksumAsync(ProjectSta
return CreateSymbolTreeInfo(
project.Solution, checksum, project.FilePath, unsortedNodes.ToImmutableAndFree(),
inheritanceMap: new OrderPreservingMultiDictionary<string, string>(),
null,
ImmutableArray<ExtensionMethodInfo>.Empty);
simpleMethods: null,
complexMethods: ImmutableArray<ExtensionMethodInfo>.Empty);
}
// generate nodes for the global namespace an all descendants
......
......@@ -11,7 +11,7 @@ internal partial class SyntaxTreeIndex
{
private readonly struct ExtensionMethodInfo
{
// We devide extension methods into two categories, simple and complex, for filtering purpose.
// We divide extension methods into two categories, simple and complex, for filtering purpose.
// Whether a method is simple is determined based on if we can determine it's target type easily
// with a pure text matching. For complex methods, we will need to rely on symbol to decide if it's
// feasible.
......@@ -28,7 +28,7 @@ internal partial class SyntaxTreeIndex
/// <summary>
/// Name of the simple method's target type name to the index of its DeclaredSymbolInfo in `_declarationInfo`.
/// All predefind types are converted to its metadata form. e.g. int => Int32. For generic types, type parameters are ignored.
/// All predefined types are converted to its metadata form. e.g. int => Int32. For generic types, type parameters are ignored.
/// </summary>
public readonly ImmutableDictionary<string, ImmutableArray<int>> SimpleExtensionMethodInfo { get; }
......@@ -37,7 +37,9 @@ internal partial class SyntaxTreeIndex
/// </summary>
public readonly ImmutableArray<int> ComplexExtensionMethodInfo { get; }
public ExtensionMethodInfo(ImmutableDictionary<string, ImmutableArray<int>> simpleExtensionMethodInfo, ImmutableArray<int> complexExtensionMethodInfo)
public ExtensionMethodInfo(
ImmutableDictionary<string, ImmutableArray<int>> simpleExtensionMethodInfo,
ImmutableArray<int> complexExtensionMethodInfo)
{
SimpleExtensionMethodInfo = simpleExtensionMethodInfo;
ComplexExtensionMethodInfo = complexExtensionMethodInfo;
......
......@@ -23,7 +23,7 @@ internal interface IDeclaredSymbolInfoFactoryService : ILanguageService
bool TryGetTargetTypeName(SyntaxNode node, out string instanceTypeName);
string GetRootNamspace(CompilationOptions compilationOptions);
string GetRootNamespace(CompilationOptions compilationOptions);
}
internal sealed partial class SyntaxTreeIndex
......@@ -68,7 +68,7 @@ internal sealed partial class SyntaxTreeIndex
var simpleExtensionMethodInfoBuilder = PooledDictionary<string, ArrayBuilder<int>>.GetInstance();
var complexExtensionMethodInfoBuilder = ArrayBuilder<int>.GetInstance();
var rootNamespace = infoFactory.GetRootNamspace(project.CompilationOptions);
var rootNamespace = infoFactory.GetRootNamespace(project.CompilationOptions);
try
{
......@@ -133,7 +133,14 @@ internal sealed partial class SyntaxTreeIndex
var declaredSymbolInfoIndex = declaredSymbolInfos.Count;
declaredSymbolInfos.Add(declaredSymbolInfo);
AddExtensionMethodInfo(infoFactory, node, containsUsingAliasDirective, declaredSymbolInfoIndex, declaredSymbolInfo, simpleExtensionMethodInfoBuilder, complexExtensionMethodInfoBuilder);
AddExtensionMethodInfo(
infoFactory,
node,
containsUsingAliasDirective,
declaredSymbolInfoIndex,
declaredSymbolInfo,
simpleExtensionMethodInfoBuilder,
complexExtensionMethodInfoBuilder);
}
else
{
......@@ -251,7 +258,7 @@ internal sealed partial class SyntaxTreeIndex
int declaredSymbolInfoIndex,
DeclaredSymbolInfo declaredSymbolInfo,
PooledDictionary<string, ArrayBuilder<int>> simpleInfoBuilder,
ArrayBuilder<int> complextInfoBuilder)
ArrayBuilder<int> complexInfoBuilder)
{
if (declaredSymbolInfo.Kind != DeclaredSymbolInfoKind.ExtensionMethod)
{
......@@ -262,27 +269,27 @@ internal sealed partial class SyntaxTreeIndex
// to the target type, simply treated it as complex type.
if (containsUsingAliasDirective || declaredSymbolInfo.TypeParameterCount > 0)
{
complextInfoBuilder.Add(declaredSymbolInfoIndex);
complexInfoBuilder.Add(declaredSymbolInfoIndex);
return;
}
if (!infoFactory.TryGetTargetTypeName(node, out var instanceTypeName))
if (!infoFactory.TryGetTargetTypeName(node, out var targetTypeName))
{
return;
}
// complex type
if (instanceTypeName == null)
if (targetTypeName == null)
{
complextInfoBuilder.Add(declaredSymbolInfoIndex);
complexInfoBuilder.Add(declaredSymbolInfoIndex);
return;
}
// simple type
if (!simpleInfoBuilder.TryGetValue(instanceTypeName, out var arrayBuilder))
if (!simpleInfoBuilder.TryGetValue(targetTypeName, out var arrayBuilder))
{
arrayBuilder = ArrayBuilder<int>.GetInstance();
simpleInfoBuilder[instanceTypeName] = arrayBuilder;
simpleInfoBuilder[targetTypeName] = arrayBuilder;
}
arrayBuilder.Add(declaredSymbolInfoIndex);
......
......@@ -9,11 +9,14 @@ internal sealed partial class SyntaxTreeIndex
{
public ImmutableArray<DeclaredSymbolInfo> DeclaredSymbolInfos => _declarationInfo.DeclaredSymbolInfos;
public ImmutableDictionary<string, ImmutableArray<int>> SimpleExtensionMethodInfo
public ImmutableDictionary<string, ImmutableArray<int>> SimpleExtensionMethodInfo
=> _extensionMethodInfo.SimpleExtensionMethodInfo;
public ImmutableArray<int> ComplexExtensionMethodInfo
=> _extensionMethodInfo.ComplexExtensionMethodInfo;
public bool ContainsExtensionMethod => SimpleExtensionMethodInfo.Count > 0 || ComplexExtensionMethodInfo.Length > 0;
public bool TryGetDeclaredSymbolInfo(int index, out DeclaredSymbolInfo declaredSymbolInfo)
{
if (index >= DeclaredSymbolInfos.Length)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册