提交 90538fb3 编写于 作者: C Cyrus Najmabadi

Reduce allocations from symbolkeys

上级 9c541aae
......@@ -4,6 +4,7 @@
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.PooledObjects;
namespace Microsoft.CodeAnalysis
{
......@@ -29,18 +30,23 @@ public static void Create(INamedTypeSymbol symbol, SymbolKeyWriter visitor)
public static SymbolKeyResolution Resolve(SymbolKeyReader reader)
{
var propertyTypeSymbols = reader.ReadSymbolKeyArray();
var propertyTypes = propertyTypeSymbols.Select(r => GetFirstSymbol<ITypeSymbol>(r)).ToImmutableArray();
var propertyNames = reader.ReadStringArray();
var propertyIsReadOnly = reader.ReadBooleanArray();
var propertyLocations = reader.ReadLocationArray();
using var propertyTypes = PooledArrayBuilder<ITypeSymbol>.GetInstance();
using var propertyNames = PooledArrayBuilder<string>.GetInstance();
using var propertyIsReadOnly = PooledArrayBuilder<bool>.GetInstance();
using var propertyLocations = PooledArrayBuilder<Location>.GetInstance();
if (propertyTypes.Length == propertyNames.Length)
reader.FillSymbolArray(propertyTypes);
reader.FillStringArray(propertyNames);
reader.FillBooleanArray(propertyIsReadOnly);
reader.FillLocationArray(propertyLocations);
if (propertyTypes.Count == propertyNames.Count)
{
try
{
var anonymousType = reader.Compilation.CreateAnonymousTypeSymbol(
propertyTypes, propertyNames, propertyIsReadOnly, propertyLocations);
propertyTypes.ToImmutable(), propertyNames.ToImmutable(),
propertyIsReadOnly.ToImmutable(), propertyLocations.ToImmutable());
return new SymbolKeyResolution(anonymousType);
}
catch (ArgumentException)
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
namespace Microsoft.CodeAnalysis
{
internal partial struct SymbolKey
......@@ -19,8 +17,16 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader)
var elementTypeResolution = reader.ReadSymbolKey();
var rank = reader.ReadInteger();
return CreateSymbolInfo(GetAllSymbols<ITypeSymbol>(elementTypeResolution)
.Select(s => reader.Compilation.CreateArrayTypeSymbol(s, rank)));
using var result = PooledArrayBuilder<IArrayTypeSymbol>.GetInstance(elementTypeResolution.SymbolCount);
foreach (var symbol in elementTypeResolution)
{
if (symbol is ITypeSymbol typeSymbol)
{
result.AddIfNotNull(reader.Compilation.CreateArrayTypeSymbol(typeSymbol, rank));
}
}
return CreateSymbolInfo(result);
}
}
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis
......@@ -19,17 +20,13 @@ public static void Create(IAssemblySymbol symbol, SymbolKeyWriter visitor)
public static SymbolKeyResolution Resolve(SymbolKeyReader reader)
{
var assemblyName = reader.ReadString();
var compilation = reader.Compilation;
var ignoreAssemblyKey = reader.IgnoreAssemblyKey;
return CreateSymbolInfo(GetAssemblySymbols(
assemblyName, reader.Compilation, reader.IgnoreAssemblyKey));
}
private static IEnumerable<IAssemblySymbol> GetAssemblySymbols(
string assemblyName, Compilation compilation, bool ignoreAssemblyKey)
{
using var result = PooledArrayBuilder<IAssemblySymbol>.GetInstance();
if (ignoreAssemblyKey || compilation.Assembly.Identity.Name == assemblyName)
{
yield return compilation.Assembly;
result.AddIfNotNull(compilation.Assembly);
}
// Might need keys for symbols from previous script compilations.
......@@ -37,9 +34,11 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader)
{
if (ignoreAssemblyKey || assembly.Identity.Name == assemblyName)
{
yield return assembly;
result.AddIfNotNull(assembly);
}
}
return CreateSymbolInfo(result);
}
}
}
......
......@@ -6,16 +6,14 @@ internal partial struct SymbolKey
{
private static class DynamicTypeSymbolKey
{
private static readonly object instance = new object();
public static void Create(SymbolKeyWriter visitor)
public static void Create(SymbolKeyWriter _)
{
// No need to encode anything here. There is only ever one dynamic-symbol
// per compilation.
}
public static SymbolKeyResolution Resolve(SymbolKeyReader reader)
{
return new SymbolKeyResolution(reader.Compilation.DynamicType);
}
=> new SymbolKeyResolution(reader.Compilation.DynamicType);
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
namespace Microsoft.CodeAnalysis
{
......@@ -22,7 +20,7 @@ public static void Create(INamedTypeSymbol symbol, SymbolKeyWriter visitor)
}
else
{
visitor.WriteSymbolKeyArray(default(ImmutableArray<ITypeSymbol>));
visitor.WriteSymbolKeyArray(ImmutableArray<ITypeSymbol>.Empty);
}
}
......@@ -31,42 +29,54 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader)
var name = reader.ReadString();
var containingSymbolResolution = reader.ReadSymbolKey();
var arity = reader.ReadInteger();
var typeArgumentResolutions = reader.ReadSymbolKeyArray();
var errorTypes = ResolveErrorTypes(reader, containingSymbolResolution, name, arity);
using var typeArguments = PooledArrayBuilder<ITypeSymbol>.GetInstance();
using var errorTypes = PooledArrayBuilder<INamedTypeSymbol>.GetInstance();
if (typeArgumentResolutions.IsDefault)
reader.FillSymbolArray(typeArguments);
ResolveErrorTypes(errorTypes, reader, containingSymbolResolution, name, arity);
if (typeArguments.Count != arity)
{
return default;
}
if (arity == 0)
{
return CreateSymbolInfo(errorTypes);
}
var typeArguments = typeArgumentResolutions.Select(
r => GetFirstSymbol<ITypeSymbol>(r)).ToArray();
if (typeArguments.Any(s_typeIsNull))
using var result = PooledArrayBuilder<INamedTypeSymbol>.GetInstance();
var typeArgumentsArray = typeArguments.Builder.ToArray();
foreach (var type in errorTypes)
{
return default;
result.AddIfNotNull(type.Construct(typeArgumentsArray));
}
return CreateSymbolInfo(errorTypes.Select(t => t.Construct(typeArguments)));
return CreateSymbolInfo(result);
}
private static IEnumerable<INamedTypeSymbol> ResolveErrorTypes(
private static void ResolveErrorTypes(
PooledArrayBuilder<INamedTypeSymbol> errorTypes,
SymbolKeyReader reader,
SymbolKeyResolution containingSymbolResolution, string name, int arity)
SymbolKeyResolution containingSymbolResolution,
string name, int arity)
{
if (containingSymbolResolution.GetAnySymbol() == null)
{
yield return reader.Compilation.CreateErrorTypeSymbol(null, name, arity);
errorTypes.AddIfNotNull(reader.Compilation.CreateErrorTypeSymbol(null, name, arity));
}
else
{
foreach (var container in containingSymbolResolution.GetAllSymbols().OfType<INamespaceOrTypeSymbol>())
foreach (var container in containingSymbolResolution)
{
yield return reader.Compilation.CreateErrorTypeSymbol(container, name, arity);
if (container is INamespaceOrTypeSymbol containerTypeOrNS)
{
errorTypes.AddIfNotNull(reader.Compilation.CreateErrorTypeSymbol(containerTypeOrNS, name, arity));
}
}
}
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
namespace Microsoft.CodeAnalysis
{
internal partial struct SymbolKey
......@@ -19,9 +17,22 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader)
var metadataName = reader.ReadString();
var containingTypeResolution = reader.ReadSymbolKey();
var events = GetAllSymbols<INamedTypeSymbol>(containingTypeResolution)
.SelectMany(t => t.GetMembers(metadataName)).OfType<IEventSymbol>();
return CreateSymbolInfo(events);
using var result = PooledArrayBuilder<IEventSymbol>.GetInstance();
foreach (var containingSymbol in containingTypeResolution)
{
if (containingSymbol is INamedTypeSymbol containingType)
{
foreach (var member in containingType.GetMembers(metadataName))
{
if (member is IEventSymbol ev)
{
result.AddIfNotNull(ev);
}
}
}
}
return CreateSymbolInfo(result);
}
}
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
namespace Microsoft.CodeAnalysis
{
internal partial struct SymbolKey
......@@ -19,9 +17,22 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader)
var metadataName = reader.ReadString();
var containingTypeResolution = reader.ReadSymbolKey();
var fields = GetAllSymbols<INamedTypeSymbol>(containingTypeResolution)
.SelectMany(t => t.GetMembers(metadataName)).OfType<IFieldSymbol>();
return CreateSymbolInfo(fields);
using var result = PooledArrayBuilder<IFieldSymbol>.GetInstance();
foreach (var containingSymbol in containingTypeResolution)
{
if (containingSymbol is INamedTypeSymbol containingType)
{
foreach (var member in containingType.GetMembers(metadataName))
{
if (member is IFieldSymbol field)
{
result.AddIfNotNull(field);
}
}
}
}
return CreateSymbolInfo(result);
}
}
}
......
......@@ -4,6 +4,7 @@
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.PooledObjects;
namespace Microsoft.CodeAnalysis
{
......@@ -24,12 +25,20 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader)
var reducedFromResolution = reader.ReadSymbolKey();
var receiverTypeResolution = reader.ReadSymbolKey();
var q = from m in reducedFromResolution.GetAllSymbols().OfType<IMethodSymbol>()
from t in receiverTypeResolution.GetAllSymbols().OfType<ITypeSymbol>()
let r = m.ReduceExtensionMethod(t)
select r;
using var result = PooledArrayBuilder<IMethodSymbol>.GetInstance();
foreach (var reducedFromSymbol in reducedFromResolution)
{
foreach (var receiverSymbol in receiverTypeResolution)
{
if (reducedFromSymbol is IMethodSymbol reducedFrom &&
receiverSymbol is ITypeSymbol receiverType)
{
result.AddIfNotNull(reducedFrom.ReduceExtensionMethod(receiverType));
}
}
}
return CreateSymbolInfo(q);
return CreateSymbolInfo(result);
}
}
}
......@@ -46,22 +55,24 @@ public static void Create(IMethodSymbol symbol, SymbolKeyWriter visitor)
public static SymbolKeyResolution Resolve(SymbolKeyReader reader)
{
var constructedFromResolution = reader.ReadSymbolKey();
var typeArgumentResolutions = reader.ReadSymbolKeyArray();
using var typeArguments = PooledArrayBuilder<ITypeSymbol>.GetInstance();
Debug.Assert(!typeArgumentResolutions.IsDefault);
var typeArguments = typeArgumentResolutions.Select(
r => GetFirstSymbol<ITypeSymbol>(r)).ToArray();
var constructedFromResolution = reader.ReadSymbolKey();
reader.FillSymbolArray(typeArguments);
if (typeArguments.Any(s_typeIsNull))
var typeArgumentArray = typeArguments.Builder.ToArray();
using var result = PooledArrayBuilder<IMethodSymbol>.GetInstance();
foreach (var symbol in constructedFromResolution)
{
return default;
if (symbol is IMethodSymbol method)
{
if (method.TypeParameters.Length == typeArguments.Count)
{
result.AddIfNotNull(method.Construct(typeArgumentArray));
}
}
}
var result = constructedFromResolution.GetAllSymbols()
.OfType<IMethodSymbol>()
.Select(m => m.Construct(typeArguments));
return CreateSymbolInfo(result);
}
}
......@@ -105,11 +116,13 @@ public static void Create(IMethodSymbol symbol, SymbolKeyWriter visitor)
public static SymbolKeyResolution Resolve(SymbolKeyReader reader)
{
using var parameterRefKinds = PooledArrayBuilder<RefKind>.GetInstance();
var metadataName = reader.ReadString();
var containingSymbolResolution = reader.ReadSymbolKey();
var arity = reader.ReadInteger();
var isPartialMethodImplementationPart = reader.ReadBoolean();
var parameterRefKinds = reader.ReadRefKindArray();
reader.FillRefKindArray(parameterRefKinds);
// For each method that we look at, we'll have to resolve the parameter list and
// return type in the context of that method. i.e. if we have Goo<T>(IList<T> list)
......@@ -121,21 +134,23 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader)
// point.
var beforeParametersPosition = reader.Position;
var result = new List<IMethodSymbol>();
using var result = PooledArrayBuilder<IMethodSymbol>.GetInstance();
var namedTypes = containingSymbolResolution.GetAllSymbols().OfType<INamedTypeSymbol>();
foreach (var namedType in namedTypes)
foreach (var symbol in containingSymbolResolution)
{
var method = Resolve(reader, metadataName, arity, isPartialMethodImplementationPart,
parameterRefKinds, beforeParametersPosition, namedType);
// Note: after finding the first method that matches we stop. That's necessary
// as we cache results while searching. We don't want to override these positive
// matches with a negative ones if we were to continue searching.
if (method != null)
if (symbol is INamedTypeSymbol namedType)
{
result.Add(method);
break;
var method = Resolve(reader, metadataName, arity, isPartialMethodImplementationPart,
parameterRefKinds, beforeParametersPosition, namedType);
// Note: after finding the first method that matches we stop. That's necessary
// as we cache results while searching. We don't want to override these positive
// matches with a negative ones if we were to continue searching.
if (method != null)
{
result.AddIfNotNull(method);
break;
}
}
}
......@@ -150,8 +165,10 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader)
// read out the values. We don't actually need to use them, but we have
// to effectively read past them in the string.
_ = reader.ReadSymbolKeyArray();
_ = GetFirstSymbol<ITypeSymbol>(reader.ReadSymbolKey());
using var parameterTypes = PooledArrayBuilder<ITypeSymbol>.GetInstance();
reader.FillSymbolArray(parameterTypes);
_ = reader.ReadSymbolKey();
reader.PopMethod(methodOpt: null);
}
......@@ -160,7 +177,7 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader)
private static IMethodSymbol Resolve(
SymbolKeyReader reader, string metadataName, int arity, bool isPartialMethodImplementationPart,
ImmutableArray<RefKind> parameterRefKinds, int beforeParametersPosition,
PooledArrayBuilder<RefKind> parameterRefKinds, int beforeParametersPosition,
INamedTypeSymbol namedType)
{
foreach (var method in namedType.GetMembers().OfType<IMethodSymbol>())
......@@ -179,7 +196,7 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader)
private static IMethodSymbol Resolve(
SymbolKeyReader reader, string metadataName, int arity, bool isPartialMethodImplementationPart,
ImmutableArray<RefKind> parameterRefKinds, int beforeParametersPosition,
PooledArrayBuilder<RefKind> parameterRefKinds, int beforeParametersPosition,
IMethodSymbol method)
{
if (method.Arity == arity &&
......@@ -213,30 +230,24 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader)
}
private static IMethodSymbol Resolve(
SymbolKeyReader reader, bool isPartialMethodImplementationPart,
IMethodSymbol method)
SymbolKeyReader reader, bool isPartialMethodImplementationPart, IMethodSymbol method)
{
var originalParameterTypeResolutions = reader.ReadSymbolKeyArray();
var returnType = GetFirstSymbol<ITypeSymbol>(reader.ReadSymbolKey());
using var originalParameterTypes = PooledArrayBuilder<ITypeSymbol>.GetInstance();
reader.FillSymbolArray(originalParameterTypes);
var returnType = (ITypeSymbol)reader.ReadSymbolKey().GetAnySymbol();
var originalParameterTypes = originalParameterTypeResolutions.Select(
r => GetFirstSymbol<ITypeSymbol>(r)).ToArray();
if (!originalParameterTypes.Any(s_typeIsNull))
if (reader.ParameterTypesMatch(method.OriginalDefinition.Parameters, originalParameterTypes))
{
if (reader.ParameterTypesMatch(method.OriginalDefinition.Parameters, originalParameterTypes))
if (returnType == null ||
reader.Comparer.Equals(returnType, method.ReturnType))
{
if (returnType == null ||
reader.Comparer.Equals(returnType, method.ReturnType))
if (isPartialMethodImplementationPart)
{
if (isPartialMethodImplementationPart)
{
method = method.PartialImplementationPart ?? method;
}
Debug.Assert(method != null);
return method;
method = method.PartialImplementationPart ?? method;
}
Debug.Assert(method != null);
return method;
}
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
namespace Microsoft.CodeAnalysis
{
internal partial struct SymbolKey
......@@ -9,20 +7,24 @@ internal partial struct SymbolKey
private static class ModuleSymbolKey
{
public static void Create(IModuleSymbol symbol, SymbolKeyWriter visitor)
{
visitor.WriteSymbolKey(symbol.ContainingSymbol);
}
=> visitor.WriteSymbolKey(symbol.ContainingSymbol);
public static SymbolKeyResolution Resolve(SymbolKeyReader reader)
{
var containingSymbolResolution = reader.ReadSymbolKey();
// Don't check ModuleIds for equality because in practice, no-one uses them,
// and there is no way to set netmodule name programmatically using Roslyn
var modules = GetAllSymbols<IAssemblySymbol>(containingSymbolResolution)
.SelectMany(a => a.Modules);
using var result = PooledArrayBuilder<IModuleSymbol>.GetInstance();
foreach (var containingSymbol in containingSymbolResolution)
{
if (containingSymbol is IAssemblySymbol assembly)
{
// Don't check ModuleIds for equality because in practice, no-one uses them,
// and there is no way to set netmodule name programmatically using Roslyn
result.AddValuesIfNotNull(assembly.Modules);
}
}
return CreateSymbolInfo(modules);
return CreateSymbolInfo(result);
}
}
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System;
using System.Collections.Immutable;
using System.Linq;
namespace Microsoft.CodeAnalysis
{
......@@ -19,11 +18,13 @@ public static void Create(INamedTypeSymbol symbol, SymbolKeyWriter visitor)
if (!symbol.Equals(symbol.ConstructedFrom) && !symbol.IsUnboundGenericType)
{
visitor.WriteBoolean(/*instantiate*/true);
visitor.WriteSymbolKeyArray(symbol.TypeArguments);
}
else
{
visitor.WriteSymbolKeyArray(default(ImmutableArray<ITypeSymbol>));
visitor.WriteBoolean(/*instantiate*/false);
visitor.WriteSymbolKeyArray(ImmutableArray<ITypeSymbol>.Empty);
}
}
......@@ -33,25 +34,49 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader)
var containingSymbolResolution = reader.ReadSymbolKey();
var arity = reader.ReadInteger();
var isUnboundGenericType = reader.ReadBoolean();
var typeArgumentsOpt = reader.ReadSymbolKeyArray();
var instantiate = reader.ReadBoolean();
var types = GetAllSymbols<INamespaceOrTypeSymbol>(containingSymbolResolution).SelectMany(
s => Resolve(s, metadataName, arity, isUnboundGenericType, typeArgumentsOpt));
return CreateSymbolInfo(types);
using var typeArguments = PooledArrayBuilder<ITypeSymbol>.GetInstance();
reader.FillSymbolArray(typeArguments);
if (instantiate && arity != typeArguments.Count)
{
return default;
}
var typeArgumentArray = typeArguments.Count == 0
? Array.Empty<ITypeSymbol>()
: typeArguments.Builder.ToArray();
using var result = PooledArrayBuilder<INamedTypeSymbol>.GetInstance();
foreach (var resolution in containingSymbolResolution)
{
if (resolution is INamespaceOrTypeSymbol nsOrType)
{
Resolve(
result, nsOrType, metadataName, arity,
isUnboundGenericType, instantiate, typeArgumentArray);
}
}
return CreateSymbolInfo(result);
}
private static IEnumerable<INamedTypeSymbol> Resolve(
private static void Resolve(
PooledArrayBuilder<INamedTypeSymbol> result,
INamespaceOrTypeSymbol container,
string metadataName,
int arity,
bool isUnboundGenericType,
ImmutableArray<SymbolKeyResolution> typeArguments)
bool instantiate,
ITypeSymbol[] typeArguments)
{
var types = container.GetTypeMembers(GetName(metadataName), arity);
var result = InstantiateTypes(types, arity, typeArguments);
foreach (var type in container.GetTypeMembers(GetName(metadataName), arity))
{
var currentType = instantiate ? type.Construct(typeArguments) : type;
currentType = isUnboundGenericType ? currentType.ConstructUnboundGenericType() : currentType;
return isUnboundGenericType
? result.Select(t => t.ConstructUnboundGenericType())
: result;
result.AddIfNotNull(currentType);
}
}
}
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis
{
......@@ -64,32 +61,32 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader)
return new SymbolKeyResolution(reader.Compilation.GlobalNamespace);
}
var namespaces = GetAllSymbols(containingSymbolResolution).SelectMany(
s => Resolve(s, metadataName));
return CreateSymbolInfo(namespaces);
}
private static IEnumerable<INamespaceSymbol> Resolve(ISymbol container, string metadataName)
{
if (container is IAssemblySymbol assembly)
using var result = PooledArrayBuilder<INamespaceSymbol>.GetInstance();
foreach (var container in containingSymbolResolution)
{
Debug.Assert(metadataName == string.Empty);
return SpecializedCollections.SingletonEnumerable(assembly.GlobalNamespace);
}
else if (container is IModuleSymbol module)
{
Debug.Assert(metadataName == string.Empty);
return SpecializedCollections.SingletonEnumerable(module.GlobalNamespace);
}
else if (container is INamespaceSymbol namespaceSymbol)
{
return namespaceSymbol.GetMembers(metadataName).OfType<INamespaceSymbol>();
}
else
{
return SpecializedCollections.EmptyEnumerable<INamespaceSymbol>();
switch (container)
{
case IAssemblySymbol assembly:
Debug.Assert(metadataName == string.Empty);
result.AddIfNotNull(assembly.GlobalNamespace);
break;
case IModuleSymbol module:
Debug.Assert(metadataName == string.Empty);
result.AddIfNotNull(module.GlobalNamespace);
break;
case INamespaceSymbol namespaceSymbol:
foreach (var member in namespaceSymbol.GetMembers(metadataName))
{
if (member is INamespaceSymbol childNamespace)
{
result.AddIfNotNull(childNamespace);
}
}
break;
}
}
return CreateSymbolInfo(result);
}
}
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq;
using Roslyn.Utilities;
using System.Collections.Immutable;
namespace Microsoft.CodeAnalysis
{
......@@ -21,48 +19,54 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader)
var metadataName = reader.ReadString();
var containingSymbolResolution = reader.ReadSymbolKey();
var parameters = GetAllSymbols(containingSymbolResolution).SelectMany(
s => Resolve(reader, s, metadataName));
return CreateSymbolInfo(parameters);
using var result = PooledArrayBuilder<IParameterSymbol>.GetInstance();
foreach (var container in containingSymbolResolution)
{
switch (container)
{
case IMethodSymbol method:
Resolve(result, reader, metadataName, method.Parameters);
break;
case IPropertySymbol property:
Resolve(result, reader, metadataName, property.Parameters);
break;
case IEventSymbol eventSymbol:
// Parameters can be owned by events in VB. i.e. it's legal in VB to have:
//
// Public Event E(a As Integer, b As Integer);
//
// In this case it's equivalent to:
//
// Public Delegate UnutterableCompilerName(a As Integer, b As Integer)
// public Event E As UnutterableCompilerName
//
// So, in this case, to resolve the parameter, we go have to map the event,
// then find the delegate it returns, then find the parameter in the delegate's
// 'Invoke' method.
var delegateInvoke = (eventSymbol.Type as INamedTypeSymbol)?.DelegateInvokeMethod;
if (delegateInvoke != null)
{
Resolve(result, reader, metadataName, delegateInvoke.Parameters);
}
break;
}
}
return CreateSymbolInfo(result);
}
private static IEnumerable<IParameterSymbol> Resolve(
SymbolKeyReader reader, ISymbol container, string metadataName)
private static void Resolve(
PooledArrayBuilder<IParameterSymbol> result, SymbolKeyReader reader,
string metadataName, ImmutableArray<IParameterSymbol> parameters)
{
if (container is IMethodSymbol method)
foreach (var parameter in parameters)
{
return method.Parameters.Where(
p => SymbolKey.Equals(reader.Compilation, p.MetadataName, metadataName));
}
else if (container is IPropertySymbol property)
{
return property.Parameters.Where(
p => SymbolKey.Equals(reader.Compilation, p.MetadataName, metadataName));
}
else if (container is IEventSymbol eventSymbol)
{
// Parameters can be owned by events in VB. i.e. it's legal in VB to have:
//
// Public Event E(a As Integer, b As Integer);
//
// In this case it's equivalent to:
//
// Public Delegate UnutterableCompilerName(a As Integer, b As Integer)
// public Event E As UnutterableCompilerName
//
// So, in this case, to resolve the parameter, we go have to map the event,
// then find the delegate it returns, then find the parameter in the delegate's
// 'Invoke' method.
var delegateInvoke = (eventSymbol.Type as INamedTypeSymbol)?.DelegateInvokeMethod;
if (delegateInvoke != null)
if (SymbolKey.Equals(reader.Compilation, parameter.MetadataName, metadataName))
{
return delegateInvoke.Parameters.Where(
p => SymbolKey.Equals(reader.Compilation, p.MetadataName, metadataName));
result.AddIfNotNull(parameter);
}
}
return SpecializedCollections.EmptyEnumerable<IParameterSymbol>();
}
}
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
namespace Microsoft.CodeAnalysis
{
internal partial struct SymbolKey
......@@ -9,16 +7,22 @@ internal partial struct SymbolKey
private static class PointerTypeSymbolKey
{
public static void Create(IPointerTypeSymbol symbol, SymbolKeyWriter visitor)
{
visitor.WriteSymbolKey(symbol.PointedAtType);
}
=> visitor.WriteSymbolKey(symbol.PointedAtType);
public static SymbolKeyResolution Resolve(SymbolKeyReader reader)
{
var pointedAtTypeResolution = reader.ReadSymbolKey();
return CreateSymbolInfo(GetAllSymbols<ITypeSymbol>(pointedAtTypeResolution)
.Select(reader.Compilation.CreatePointerTypeSymbol));
using var result = PooledArrayBuilder<IPointerTypeSymbol>.GetInstance(pointedAtTypeResolution.SymbolCount);
foreach (var symbol in pointedAtTypeResolution)
{
if (symbol is ITypeSymbol typeSymbol)
{
result.AddIfNotNull(reader.Compilation.CreatePointerTypeSymbol(typeSymbol));
}
}
return CreateSymbolInfo(result);
}
}
}
......
......@@ -22,26 +22,41 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader)
var metadataName = reader.ReadString();
var containingSymbolResolution = reader.ReadSymbolKey();
var isIndexer = reader.ReadBoolean();
var refKinds = reader.ReadRefKindArray();
var originalParameterTypes = reader.ReadSymbolKeyArray().Select(
r => GetFirstSymbol<ITypeSymbol>(r)).ToArray();
if (originalParameterTypes.Any(s_typeIsNull))
using var refKinds = PooledArrayBuilder<RefKind>.GetInstance();
using var parameterTypes = PooledArrayBuilder<ITypeSymbol>.GetInstance();
reader.FillRefKindArray(refKinds);
reader.FillSymbolArray(parameterTypes);
if (refKinds.Count != parameterTypes.Count)
{
return default;
}
var properties = containingSymbolResolution.GetAllSymbols().OfType<INamedTypeSymbol>()
.SelectMany(t => t.GetMembers())
.OfType<IPropertySymbol>()
.Where(p => p.Parameters.Length == refKinds.Length &&
p.MetadataName == metadataName &&
p.IsIndexer == isIndexer);
var matchingProperties = properties.Where(p =>
ParameterRefKindsMatch(p.OriginalDefinition.Parameters, refKinds) &&
reader.ParameterTypesMatch(p.OriginalDefinition.Parameters, originalParameterTypes));
return CreateSymbolInfo(matchingProperties);
using var result = PooledArrayBuilder<IPropertySymbol>.GetInstance();
foreach (var containingSymbol in containingSymbolResolution)
{
if (containingSymbol is INamedTypeSymbol containingNamedType)
{
foreach (var member in containingNamedType.GetMembers())
{
if (member is IPropertySymbol property)
{
if (property.Parameters.Length == refKinds.Count &&
property.MetadataName == metadataName &&
property.IsIndexer == isIndexer &&
ParameterRefKindsMatch(property.OriginalDefinition.Parameters, refKinds) &&
reader.ParameterTypesMatch(property.OriginalDefinition.Parameters, parameterTypes))
{
result.AddIfNotNull(property);
}
}
}
}
}
return CreateSymbolInfo(result);
}
}
}
......
......@@ -173,46 +173,36 @@ private void EatDoubleQuote()
Eat(DoubleQuoteChar);
}
public ImmutableArray<TStringResult> ReadStringArray()
{
return ReadArray(_readString);
}
public void FillStringArray(PooledArrayBuilder<TStringResult> builder)
=> FillArray(builder, _readString);
public ImmutableArray<bool> ReadBooleanArray()
{
return ReadArray(_readBoolean);
}
public void FillBooleanArray(PooledArrayBuilder<bool> builder)
=> FillArray(builder, _readBoolean);
public ImmutableArray<RefKind> ReadRefKindArray()
{
return ReadArray(_readRefKind);
}
public void FillRefKindArray(PooledArrayBuilder<RefKind> builder)
=> FillArray(builder, _readRefKind);
public ImmutableArray<T> ReadArray<T>(Func<T> readFunction)
/// <summary>
/// Returns false if this was an encoded 'null' (as opposed to an empty array).
/// </summary>
public void FillArray<T>(
PooledArrayBuilder<T> builder, Func<T> readFunction)
{
EatSpace();
if ((SymbolKeyType)Data[Position] == SymbolKeyType.Null)
{
Eat(SymbolKeyType.Null);
return default;
}
Debug.Assert((SymbolKeyType)Data[Position] != SymbolKeyType.Null);
EatOpenParen();
Eat(SymbolKeyType.Array);
var length = ReadInteger();
var builder = ImmutableArray.CreateBuilder<T>(length);
for (var i = 0; i < length; i++)
{
CancellationToken.ThrowIfCancellationRequested();
builder.Add(readFunction());
builder.Builder.Add(readFunction());
}
EatCloseParen();
return builder.MoveToImmutable();
}
}
......@@ -351,9 +341,9 @@ public override void Dispose()
internal bool ParameterTypesMatch(
ImmutableArray<IParameterSymbol> parameters,
ITypeSymbol[] originalParameterTypes)
PooledArrayBuilder<ITypeSymbol> originalParameterTypes)
{
if (parameters.Length != originalParameterTypes.Length)
if (parameters.Length != originalParameterTypes.Count)
{
return false;
}
......@@ -364,7 +354,7 @@ public override void Dispose()
// compare method type parameters by ordinal.
var signatureComparer = Comparer.SignatureTypeEquivalenceComparer;
for (var i = 0; i < originalParameterTypes.Length; i++)
for (var i = 0; i < originalParameterTypes.Count; i++)
{
if (!signatureComparer.Equals(originalParameterTypes[i], parameters[i].Type))
{
......@@ -456,8 +446,19 @@ private SymbolKeyResolution ReadWorker(SymbolKeyType type)
_ => throw new NotImplementedException(),
};
public ImmutableArray<SymbolKeyResolution> ReadSymbolKeyArray()
=> ReadArray(_readSymbolKey);
public void FillSymbolArray<TSymbol>(PooledArrayBuilder<TSymbol> builder) where TSymbol : ISymbol
{
using var resolutions = PooledArrayBuilder<SymbolKeyResolution>.GetInstance();
FillArray(resolutions, _readSymbolKey);
foreach (var resolution in resolutions)
{
if (resolution.GetAnySymbol() is TSymbol castedSymbol)
{
builder.AddIfNotNull(castedSymbol);
}
}
}
#endregion
......@@ -532,8 +533,8 @@ public Location ReadLocation()
return Location.None;
}
public ImmutableArray<Location> ReadLocationArray()
=> ReadArray(_readLocation);
public void FillLocationArray(PooledArrayBuilder<Location> builder)
=> FillArray(builder, _readLocation);
#endregion
}
......
......@@ -297,11 +297,7 @@ internal void WriteRefKindArray(ImmutableArray<IParameterSymbol> values)
where T : U
{
WriteSpace();
if (array.IsDefault)
{
WriteType(SymbolKeyType.Null);
return;
}
Debug.Assert(!array.IsDefault);
StartKey();
WriteType(SymbolKeyType.Array);
......
......@@ -5,7 +5,6 @@
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis
{
......@@ -54,16 +53,20 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader)
var isError = reader.ReadBoolean();
if (isError)
{
var elementTypes = reader.ReadSymbolKeyArray().SelectAsArray(r => r.GetAnySymbol() as ITypeSymbol);
var elementNames = reader.ReadStringArray();
using var elementTypes = PooledArrayBuilder<ITypeSymbol>.GetInstance();
using var elementNames = PooledArrayBuilder<string>.GetInstance();
reader.FillSymbolArray(elementTypes);
reader.FillStringArray(elementNames);
var elementLocations = ReadElementLocations(reader);
if (!elementTypes.Any(t => t == null))
if (elementTypes.Count == elementNames.Count)
{
try
{
var result = reader.Compilation.CreateTupleTypeSymbol(
elementTypes, elementNames, elementLocations);
elementTypes.ToImmutable(), elementNames.ToImmutable(), elementLocations);
return new SymbolKeyResolution(result);
}
catch (ArgumentException)
......@@ -73,14 +76,26 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader)
}
else
{
using var elementNamesBuilder = PooledArrayBuilder<string>.GetInstance();
var underlyingTypeResolution = reader.ReadSymbolKey();
var elementNames = reader.ReadStringArray();
reader.FillStringArray(elementNamesBuilder);
var elementLocations = ReadElementLocations(reader);
try
{
var result = GetAllSymbols<INamedTypeSymbol>(underlyingTypeResolution).Select(
t => reader.Compilation.CreateTupleTypeSymbol(t, elementNames, elementLocations));
using var result = PooledArrayBuilder<INamedTypeSymbol>.GetInstance();
var elementNames = elementNamesBuilder.ToImmutable();
foreach (var symbol in underlyingTypeResolution)
{
if (symbol is INamedTypeSymbol namedType)
{
result.AddIfNotNull(reader.Compilation.CreateTupleTypeSymbol(
namedType, elementNames, elementLocations));
}
}
return CreateSymbolInfo(result);
}
catch (ArgumentException)
......@@ -93,15 +108,17 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader)
private static ImmutableArray<Location> ReadElementLocations(SymbolKeyReader reader)
{
using var elementLocations = PooledArrayBuilder<Location>.GetInstance();
// Compiler API requires that all the locations are non-null, or that there is a default
// immutable array passed in.
var elementLocations = reader.ReadLocationArray();
if (elementLocations.All(loc => loc == null))
reader.FillLocationArray(elementLocations);
if (elementLocations.Builder.All(loc => loc == null))
{
elementLocations = default;
return default;
}
return elementLocations;
return elementLocations.ToImmutable();
}
}
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis
......@@ -20,22 +21,18 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader)
var metadataName = reader.ReadString();
var containingSymbolResolution = reader.ReadSymbolKey();
var result = containingSymbolResolution.GetAllSymbols()
.SelectMany(s =>
using var result = PooledArrayBuilder<ITypeParameterSymbol>.GetInstance();
foreach (var containingSymbol in containingSymbolResolution)
{
foreach (var typeParam in containingSymbol.GetTypeParameters())
{
if (s is INamedTypeSymbol namedType)
if (typeParam.MetadataName == metadataName)
{
return namedType.TypeParameters.Where(p => p.MetadataName == metadataName);
result.AddIfNotNull(typeParam);
}
else if (s is IMethodSymbol method)
{
return method.TypeParameters.Where(p => p.MetadataName == metadataName);
}
else
{
return SpecializedCollections.EmptyEnumerable<ITypeParameterSymbol>();
}
});
}
}
return CreateSymbolInfo(result);
}
}
......
......@@ -6,6 +6,7 @@
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Roslyn.Utilities;
......@@ -201,25 +202,49 @@ private static IEnumerable<ISymbol> GetAllSymbols(SymbolKeyResolution info)
}
}
private static IEnumerable<TType> GetAllSymbols<TType>(SymbolKeyResolution info)
=> GetAllSymbols(info).OfType<TType>();
//private static IEnumerable<TType> GetAllSymbols<TType>(SymbolKeyResolution info)
// => GetAllSymbols(info).OfType<TType>();
private static SymbolKeyResolution CreateSymbolInfo(IEnumerable<ISymbol> symbols)
private static SymbolKeyResolution CreateSymbolInfo<TSymbol>(PooledArrayBuilder<TSymbol> symbols)
where TSymbol : class, ISymbol
{
return symbols == null
? default
: CreateSymbolInfo(symbols.WhereNotNull().ToArray());
}
foreach (var symbol in symbols)
{
Debug.Assert(symbol != null);
}
private static SymbolKeyResolution CreateSymbolInfo(ISymbol[] symbols)
{
return symbols.Length == 0
? default
: symbols.Length == 1
? new SymbolKeyResolution(symbols[0])
: new SymbolKeyResolution(ImmutableArray.Create<ISymbol>(symbols), CandidateReason.Ambiguous);
if (symbols.Builder.Count == 0)
{
return default;
}
else if (symbols.Builder.Count == 1)
{
return new SymbolKeyResolution(symbols.Builder[0]);
}
else
{
return new SymbolKeyResolution(
ImmutableArray<ISymbol>.CastUp(symbols.Builder.ToImmutable()),
CandidateReason.Ambiguous);
}
}
//private static SymbolKeyResolution CreateSymbolInfo(IEnumerable<ISymbol> symbols)
//{
// return symbols == null
// ? default
// : CreateSymbolInfo(symbols.WhereNotNull().ToArray());
//}
//private static SymbolKeyResolution CreateSymbolInfo(ISymbol[] symbols)
//{
// return symbols.Length == 0
// ? default
// : symbols.Length == 1
// ? new SymbolKeyResolution(symbols[0])
// : new SymbolKeyResolution(ImmutableArray.Create<ISymbol>(symbols), CandidateReason.Ambiguous);
//}
private static bool Equals(Compilation compilation, string name1, string name2)
=> Equals(compilation.IsCaseSensitive, name1, name2);
......@@ -234,41 +259,16 @@ private static string GetName(string metadataName)
: metadataName;
}
private static IEnumerable<INamedTypeSymbol> InstantiateTypes(
ImmutableArray<INamedTypeSymbol> types,
int arity,
ImmutableArray<SymbolKeyResolution> typeArgumentKeys)
{
if (arity == 0 || typeArgumentKeys.IsDefault || typeArgumentKeys.IsEmpty)
{
return types;
}
// TODO(cyrusn): We're only accepting a type argument if it resolves unambiguously.
// However, we could consider the case where they resolve ambiguously and return
// different named type instances when that happens.
var typeArguments = typeArgumentKeys.Select(a => GetFirstSymbol<ITypeSymbol>(a)).ToArray();
return typeArguments.Any(s_typeIsNull)
? SpecializedCollections.EmptyEnumerable<INamedTypeSymbol>()
: types.Select(t => t.Construct(typeArguments));
}
private static TSymbol GetFirstSymbol<TSymbol>(SymbolKeyResolution resolution)
where TSymbol : ISymbol
{
return resolution.GetAllSymbols().OfType<TSymbol>().FirstOrDefault();
}
private static bool ParameterRefKindsMatch(
ImmutableArray<IParameterSymbol> parameters,
ImmutableArray<RefKind> refKinds)
PooledArrayBuilder<RefKind> refKinds)
{
if (parameters.Length != refKinds.Length)
if (parameters.Length != refKinds.Count)
{
return false;
}
for (var i = 0; i < refKinds.Length; i++)
for (var i = 0; i < refKinds.Count; i++)
{
// The ref-out distinction is not interesting for SymbolKey because you can't overload
// based on the difference.
......@@ -281,5 +281,52 @@ private static TSymbol GetFirstSymbol<TSymbol>(SymbolKeyResolution resolution)
return true;
}
private ref struct PooledArrayBuilder<T>
{
public readonly ArrayBuilder<T> Builder;
private PooledArrayBuilder(ArrayBuilder<T> builder)
=> Builder = builder;
public int Count => Builder.Count;
public T this[int index] => Builder[index];
public void AddIfNotNull(T value)
{
if (value != null)
{
Builder.Add(value);
}
}
public void Dispose() => Builder.Free();
public ImmutableArray<T> ToImmutable() => Builder.ToImmutable();
public ArrayBuilder<T>.Enumerator GetEnumerator() => Builder.GetEnumerator();
public static PooledArrayBuilder<T> GetInstance()
=> new PooledArrayBuilder<T>(ArrayBuilder<T>.GetInstance());
public static PooledArrayBuilder<T> GetInstance(int capacity)
=> new PooledArrayBuilder<T>(ArrayBuilder<T>.GetInstance(capacity));
public void AddValuesIfNotNull(IEnumerable<T> values)
{
foreach (var value in values)
{
AddIfNotNull(value);
}
}
public void AddValuesIfNotNull(ImmutableArray<T> values)
{
foreach (var value in values)
{
AddIfNotNull(value);
}
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.CodeAnalysis
{
internal partial struct SymbolKeyResolution
{
public struct Enumerator
{
private readonly SymbolKeyResolution _symbolKeyResolution;
private int _index;
public Enumerator(SymbolKeyResolution symbolKeyResolution)
{
_symbolKeyResolution = symbolKeyResolution;
_index = -1;
}
public bool MoveNext()
{
_index++;
if (_symbolKeyResolution.Symbol != null)
{
return _index == 0;
}
return _index < _symbolKeyResolution.CandidateSymbols.Length;
}
public ISymbol Current
{
get
{
if (_symbolKeyResolution.Symbol != null)
{
return _symbolKeyResolution.Symbol;
}
return _symbolKeyResolution.CandidateSymbols[_index];
}
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Threading;
namespace Microsoft.CodeAnalysis
......@@ -15,24 +17,34 @@ namespace Microsoft.CodeAnalysis
/// If no symbol can be found <see cref="Symbol"/> will be <c>null</c> and <see cref="CandidateSymbols"/>
/// will be empty.
/// </summary>
internal struct SymbolKeyResolution
internal partial struct SymbolKeyResolution
{
internal SymbolKeyResolution(ISymbol symbol) : this()
private readonly ImmutableArray<ISymbol> _candidateSymbols;
internal SymbolKeyResolution(ISymbol symbol)
{
Symbol = symbol;
CandidateSymbols = ImmutableArray<ISymbol>.Empty;
_candidateSymbols = default;
CandidateReason = CandidateReason.None;
}
internal SymbolKeyResolution(ImmutableArray<ISymbol> candidateSymbols, CandidateReason candidateReason)
{
Symbol = null;
CandidateSymbols = candidateSymbols.NullToEmpty();
_candidateSymbols = candidateSymbols;
CandidateReason = candidateReason;
Debug.Assert(CandidateSymbols.All(s => s != null));
}
internal int SymbolCount => Symbol != null ? 1 : CandidateSymbols.Length;
public ISymbol Symbol { get; }
public ImmutableArray<ISymbol> CandidateSymbols { get; }
public CandidateReason CandidateReason { get; }
public ImmutableArray<ISymbol> CandidateSymbols => _candidateSymbols.NullToEmpty();
public Enumerator GetEnumerator()
{
return new Enumerator(this);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册