未验证 提交 479b3994 编写于 作者: M msftbot[bot] 提交者: GitHub

Merge pull request #42852 from CyrusNajmabadi/symbolEquivStackOverflow

Symbol equiv stack overflow
......@@ -2,6 +2,7 @@
// 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;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
......@@ -43,6 +44,7 @@ public virtual IAsyncEnumerable<ExternalReferenceItem> FindReferencesByMoniker(D
internal class DefaultFindSymbolMonikerUsagesService : AbstractFindSymbolMonikerUsagesService
{
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public DefaultFindSymbolMonikerUsagesService()
{
}
......
......@@ -345,6 +345,44 @@ namespace System
<%= tuple2 %>
</Document>
</Project>
</Workspace>
Await TestAPIAndFeature(input, kind, host)
End Function
<WorkItem(41598, "https://github.com/dotnet/roslyn/issues/41598")>
<WpfTheory, CombinatorialData, Trait(Traits.Feature, Traits.Features.FindReferences)>
Public Async Function TestTuplesAcrossCoreAndStandard1(kind As TestKind, host As TestHost) As Task
Dim input =
<Workspace>
<Project Language="C#" CommonReferencesNetCoreApp30="true">
<Document><![CDATA[
using System;
class Program
{
static void Main(string[] args)
{
}
public [|ValueTuple|]<int, int> XXX() => default;
}
]]>
</Document>
</Project>
<Project Language="C#" CommonReferencesNetStandard20="true">
<Document><![CDATA[
using System;
class Program
{
static void Test()
{
$$var a = (1, 1);
}
}
]]>
</Document>
</Project>
</Workspace>
Await TestAPIAndFeature(input, kind, host)
End Function
......
......@@ -50,6 +50,8 @@ public partial class TestWorkspace
private const string CommonReferencesWinRTAttributeName = "CommonReferencesWinRT";
private const string CommonReferencesNet45AttributeName = "CommonReferencesNet45";
private const string CommonReferencesPortableAttributeName = "CommonReferencesPortable";
private const string CommonReferencesNetCoreApp30Name = "CommonReferencesNetCoreApp30";
private const string CommonReferencesNetStandard20Name = "CommonReferencesNetStandard20";
private const string FilePathAttributeName = "FilePath";
private const string FoldersAttributeName = "Folders";
private const string KindAttributeName = "Kind";
......
......@@ -1009,6 +1009,22 @@ private static IList<MetadataReference> CreateCommonReferences(TestWorkspace wor
references.AddRange(TestBase.PortableRefsMinimal);
}
var netcore30 = element.Attribute(CommonReferencesNetCoreApp30Name);
if (netcore30 != null &&
((bool?)netcore30).HasValue &&
((bool?)netcore30).Value)
{
references = TargetFrameworkUtil.NetCoreApp30References.ToList();
}
var netstandard20 = element.Attribute(CommonReferencesNetStandard20Name);
if (netstandard20 != null &&
((bool?)netstandard20).HasValue &&
((bool?)netstandard20).Value)
{
references = TargetFrameworkUtil.NetStandard20References.ToList();
}
return references;
}
......
......@@ -35,6 +35,7 @@ internal partial class VisualStudioFindSymbolMonikerUsagesService : AbstractFind
private CancellationTokenSource? _lastNavigationCancellationSource;
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public VisualStudioFindSymbolMonikerUsagesService(
[Import(AllowDefault = true)] ICodeIndexProvider? codeIndexProvider)
{
......
......@@ -10,6 +10,7 @@
using System.Collections.Immutable;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Threading;
......
......@@ -716,5 +716,17 @@ private static bool VerifyGetAwaiter(IMethodSymbol getAwaiter)
// void GetResult() || T GetResult()
return methods.Any(m => m.Name == WellKnownMemberNames.GetResult && !m.Parameters.Any());
}
public static bool IsKind<TSymbol>(this ISymbol symbol, SymbolKind kind, [NotNullWhen(true)] out TSymbol? result) where TSymbol : class, ISymbol
{
if (!symbol.IsKind(kind))
{
result = null;
return false;
}
result = (TSymbol)symbol;
return true;
}
}
}
......@@ -4,6 +4,7 @@
////#define TRACKDEPTH
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
......@@ -76,9 +77,13 @@ public bool AreEquivalent(ISymbol x, ISymbol y, Dictionary<INamedTypeSymbol, INa
// Special case. If we're comparing signatures then we want to compare 'object'
// and 'dynamic' as the same. However, since they're different types, we don't
// want to bail out using the above check.
return _objectAndDynamicCompareEqually &&
((yKind == SymbolKind.DynamicType && xKind == SymbolKind.NamedType && ((ITypeSymbol)x).SpecialType == SpecialType.System_Object) ||
(xKind == SymbolKind.DynamicType && yKind == SymbolKind.NamedType && ((ITypeSymbol)y).SpecialType == SpecialType.System_Object));
if (_objectAndDynamicCompareEqually)
{
return (xKind == SymbolKind.DynamicType && IsObjectType(y)) ||
(yKind == SymbolKind.DynamicType && IsObjectType(x));
}
return false;
}
return AreEquivalentWorker(x, y, xKind, equivalentTypesWithDifferingAssemblies);
......@@ -119,46 +124,28 @@ internal bool AreEquivalent(ImmutableArray<CustomModifier> x, ImmutableArray<Cus
private bool AreEquivalentWorker(ISymbol x, ISymbol y, SymbolKind k, Dictionary<INamedTypeSymbol, INamedTypeSymbol> equivalentTypesWithDifferingAssemblies)
{
Debug.Assert(x.Kind == y.Kind && x.Kind == k);
switch (k)
{
case SymbolKind.ArrayType:
return ArrayTypesAreEquivalent((IArrayTypeSymbol)x, (IArrayTypeSymbol)y, equivalentTypesWithDifferingAssemblies);
case SymbolKind.Assembly:
return AssembliesAreEquivalent((IAssemblySymbol)x, (IAssemblySymbol)y);
case SymbolKind.DynamicType:
return DynamicTypesAreEquivalent((IDynamicTypeSymbol)x, (IDynamicTypeSymbol)y);
case SymbolKind.Event:
return EventsAreEquivalent((IEventSymbol)x, (IEventSymbol)y, equivalentTypesWithDifferingAssemblies);
case SymbolKind.Field:
return FieldsAreEquivalent((IFieldSymbol)x, (IFieldSymbol)y, equivalentTypesWithDifferingAssemblies);
case SymbolKind.Label:
return LabelsAreEquivalent((ILabelSymbol)x, (ILabelSymbol)y);
case SymbolKind.Local:
return LocalsAreEquivalent((ILocalSymbol)x, (ILocalSymbol)y);
case SymbolKind.Method:
return MethodsAreEquivalent((IMethodSymbol)x, (IMethodSymbol)y, equivalentTypesWithDifferingAssemblies);
case SymbolKind.NetModule:
return ModulesAreEquivalent((IModuleSymbol)x, (IModuleSymbol)y);
case SymbolKind.NamedType:
case SymbolKind.ErrorType: // ErrorType is handled in NamedTypesAreEquivalent
return NamedTypesAreEquivalent((INamedTypeSymbol)x, (INamedTypeSymbol)y, equivalentTypesWithDifferingAssemblies);
case SymbolKind.Namespace:
return NamespacesAreEquivalent((INamespaceSymbol)x, (INamespaceSymbol)y, equivalentTypesWithDifferingAssemblies);
case SymbolKind.Parameter:
return ParametersAreEquivalent((IParameterSymbol)x, (IParameterSymbol)y, equivalentTypesWithDifferingAssemblies);
case SymbolKind.PointerType:
return PointerTypesAreEquivalent((IPointerTypeSymbol)x, (IPointerTypeSymbol)y, equivalentTypesWithDifferingAssemblies);
case SymbolKind.Property:
return PropertiesAreEquivalent((IPropertySymbol)x, (IPropertySymbol)y, equivalentTypesWithDifferingAssemblies);
case SymbolKind.RangeVariable:
return RangeVariablesAreEquivalent((IRangeVariableSymbol)x, (IRangeVariableSymbol)y);
case SymbolKind.TypeParameter:
return TypeParametersAreEquivalent((ITypeParameterSymbol)x, (ITypeParameterSymbol)y, equivalentTypesWithDifferingAssemblies);
case SymbolKind.Preprocessing:
return PreprocessingSymbolsAreEquivalent((IPreprocessingSymbol)x, (IPreprocessingSymbol)y);
default:
return false;
}
return k switch
{
SymbolKind.ArrayType => ArrayTypesAreEquivalent((IArrayTypeSymbol)x, (IArrayTypeSymbol)y, equivalentTypesWithDifferingAssemblies),
SymbolKind.Assembly => AssembliesAreEquivalent((IAssemblySymbol)x, (IAssemblySymbol)y),
SymbolKind.DynamicType => DynamicTypesAreEquivalent((IDynamicTypeSymbol)x, (IDynamicTypeSymbol)y),
SymbolKind.Event => EventsAreEquivalent((IEventSymbol)x, (IEventSymbol)y, equivalentTypesWithDifferingAssemblies),
SymbolKind.Field => FieldsAreEquivalent((IFieldSymbol)x, (IFieldSymbol)y, equivalentTypesWithDifferingAssemblies),
SymbolKind.Label => LabelsAreEquivalent((ILabelSymbol)x, (ILabelSymbol)y),
SymbolKind.Local => LocalsAreEquivalent((ILocalSymbol)x, (ILocalSymbol)y),
SymbolKind.Method => MethodsAreEquivalent((IMethodSymbol)x, (IMethodSymbol)y, equivalentTypesWithDifferingAssemblies),
SymbolKind.NetModule => ModulesAreEquivalent((IModuleSymbol)x, (IModuleSymbol)y),
SymbolKind.NamedType => NamedTypesAreEquivalent((INamedTypeSymbol)x, (INamedTypeSymbol)y, equivalentTypesWithDifferingAssemblies),
SymbolKind.ErrorType => NamedTypesAreEquivalent((INamedTypeSymbol)x, (INamedTypeSymbol)y, equivalentTypesWithDifferingAssemblies),
SymbolKind.Namespace => NamespacesAreEquivalent((INamespaceSymbol)x, (INamespaceSymbol)y, equivalentTypesWithDifferingAssemblies),
SymbolKind.Parameter => ParametersAreEquivalent((IParameterSymbol)x, (IParameterSymbol)y, equivalentTypesWithDifferingAssemblies),
SymbolKind.PointerType => PointerTypesAreEquivalent((IPointerTypeSymbol)x, (IPointerTypeSymbol)y, equivalentTypesWithDifferingAssemblies),
SymbolKind.Property => PropertiesAreEquivalent((IPropertySymbol)x, (IPropertySymbol)y, equivalentTypesWithDifferingAssemblies),
SymbolKind.RangeVariable => RangeVariablesAreEquivalent((IRangeVariableSymbol)x, (IRangeVariableSymbol)y),
SymbolKind.TypeParameter => TypeParametersAreEquivalent((ITypeParameterSymbol)x, (ITypeParameterSymbol)y, equivalentTypesWithDifferingAssemblies),
SymbolKind.Preprocessing => PreprocessingSymbolsAreEquivalent((IPreprocessingSymbol)x, (IPreprocessingSymbol)y),
_ => false,
};
}
private bool ArrayTypesAreEquivalent(IArrayTypeSymbol x, IArrayTypeSymbol y, Dictionary<INamedTypeSymbol, INamedTypeSymbol> equivalentTypesWithDifferingAssemblies)
......@@ -360,56 +347,22 @@ private bool HandleNamedTypesWorker(INamedTypeSymbol x, INamedTypeSymbol y, Dict
{
Debug.Assert(GetTypeKind(x) == GetTypeKind(y));
if (x.IsTupleType || y.IsTupleType)
{
if (x.IsTupleType != y.IsTupleType)
{
return false;
}
var xElements = x.TupleElements;
var yElements = y.TupleElements;
if (xElements.Length != yElements.Length)
{
return false;
}
var tupleNamesMustMatch = _symbolEquivalenceComparer._tupleNamesMustMatch;
for (var i = 0; i < xElements.Length; i++)
{
var xElement = xElements[i];
var yElement = yElements[i];
if (tupleNamesMustMatch &&
xElement.Name != yElement.Name)
{
return false;
}
if (!AreEquivalent(xElement.Type, yElement.Type, equivalentTypesWithDifferingAssemblies))
{
return false;
}
}
return true;
}
if (x.IsDefinition != y.IsDefinition ||
IsConstructedFromSelf(x) != IsConstructedFromSelf(y) ||
x.Arity != y.Arity ||
x.Name != y.Name ||
x.IsAnonymousType != y.IsAnonymousType ||
x.IsUnboundGenericType != y.IsUnboundGenericType)
x.IsUnboundGenericType != y.IsUnboundGenericType ||
x.IsTupleType != y.IsTupleType)
{
return false;
}
if (x.IsTupleType)
return HandleTupleTypes(x, y, equivalentTypesWithDifferingAssemblies);
if (!AreEquivalent(x.ContainingSymbol, y.ContainingSymbol, equivalentTypesWithDifferingAssemblies))
{
return false;
}
// Above check makes sure that the containing assemblies are considered the same by the assembly comparer being used.
// If they are in fact not the same (have different name) and the caller requested to know about such types add {x, y}
......@@ -424,9 +377,7 @@ private bool HandleNamedTypesWorker(INamedTypeSymbol x, INamedTypeSymbol y, Dict
}
if (x.IsAnonymousType)
{
return HandleAnonymousTypes(x, y, equivalentTypesWithDifferingAssemblies);
}
// They look very similar at this point. In the case of non constructed types, we're
// done. However, if they are constructed, then their type arguments have to match
......@@ -437,6 +388,48 @@ private bool HandleNamedTypesWorker(INamedTypeSymbol x, INamedTypeSymbol y, Dict
TypeArgumentsAreEquivalent(x.TypeArguments, y.TypeArguments, equivalentTypesWithDifferingAssemblies);
}
private bool HandleTupleTypes(INamedTypeSymbol x, INamedTypeSymbol y, Dictionary<INamedTypeSymbol, INamedTypeSymbol> equivalentTypesWithDifferingAssemblies)
{
Debug.Assert(y.IsTupleType);
var xElements = x.TupleElements;
var yElements = y.TupleElements;
if (xElements.Length != yElements.Length)
return false;
// Check names first if necessary.
if (_symbolEquivalenceComparer._tupleNamesMustMatch)
{
for (var i = 0; i < xElements.Length; i++)
{
var xElement = xElements[i];
var yElement = yElements[i];
if (xElement.Name != yElement.Name)
return false;
}
}
// If we're validating the actual unconstructed ValueTuple type itself, we're done at this point. No
// need to check field types.
//
// For VB we have to unwrap tuples to their underlying types to do this check.
// https://github.com/dotnet/roslyn/issues/42860
if (IsConstructedFromSelf(x.TupleUnderlyingType ?? x))
return true;
for (var i = 0; i < xElements.Length; i++)
{
var xElement = xElements[i];
var yElement = yElements[i];
if (!AreEquivalent(xElement.Type, yElement.Type, equivalentTypesWithDifferingAssemblies))
return false;
}
return true;
}
private bool ParametersAreEquivalent(
ImmutableArray<IParameterSymbol> xParameters,
ImmutableArray<IParameterSymbol> yParameters,
......
......@@ -36,9 +36,7 @@ private class GetHashCodeVisitor
public int GetHashCode(ISymbol x, int currentHash)
{
if (x == null)
{
return 0;
}
x = UnwrapAlias(x);
......@@ -56,45 +54,26 @@ public int GetHashCode(ISymbol x, int currentHash)
}
private int GetHashCodeWorker(ISymbol x, int currentHash)
{
switch (x.Kind)
=> x.Kind switch
{
case SymbolKind.ArrayType:
return CombineHashCodes((IArrayTypeSymbol)x, currentHash);
case SymbolKind.Assembly:
return CombineHashCodes((IAssemblySymbol)x, currentHash);
case SymbolKind.Event:
return CombineHashCodes((IEventSymbol)x, currentHash);
case SymbolKind.Field:
return CombineHashCodes((IFieldSymbol)x, currentHash);
case SymbolKind.Label:
return CombineHashCodes((ILabelSymbol)x, currentHash);
case SymbolKind.Local:
return CombineHashCodes((ILocalSymbol)x, currentHash);
case SymbolKind.Method:
return CombineHashCodes((IMethodSymbol)x, currentHash);
case SymbolKind.NetModule:
return CombineHashCodes((IModuleSymbol)x, currentHash);
case SymbolKind.NamedType:
return CombineHashCodes((INamedTypeSymbol)x, currentHash);
case SymbolKind.Namespace:
return CombineHashCodes((INamespaceSymbol)x, currentHash);
case SymbolKind.Parameter:
return CombineHashCodes((IParameterSymbol)x, currentHash);
case SymbolKind.PointerType:
return CombineHashCodes((IPointerTypeSymbol)x, currentHash);
case SymbolKind.Property:
return CombineHashCodes((IPropertySymbol)x, currentHash);
case SymbolKind.RangeVariable:
return CombineHashCodes((IRangeVariableSymbol)x, currentHash);
case SymbolKind.TypeParameter:
return CombineHashCodes((ITypeParameterSymbol)x, currentHash);
case SymbolKind.Preprocessing:
return CombineHashCodes((IPreprocessingSymbol)x, currentHash);
default:
return -1;
}
}
SymbolKind.ArrayType => CombineHashCodes((IArrayTypeSymbol)x, currentHash),
SymbolKind.Assembly => CombineHashCodes((IAssemblySymbol)x, currentHash),
SymbolKind.Event => CombineHashCodes((IEventSymbol)x, currentHash),
SymbolKind.Field => CombineHashCodes((IFieldSymbol)x, currentHash),
SymbolKind.Label => CombineHashCodes((ILabelSymbol)x, currentHash),
SymbolKind.Local => CombineHashCodes((ILocalSymbol)x, currentHash),
SymbolKind.Method => CombineHashCodes((IMethodSymbol)x, currentHash),
SymbolKind.NetModule => CombineHashCodes((IModuleSymbol)x, currentHash),
SymbolKind.NamedType => CombineHashCodes((INamedTypeSymbol)x, currentHash),
SymbolKind.Namespace => CombineHashCodes((INamespaceSymbol)x, currentHash),
SymbolKind.Parameter => CombineHashCodes((IParameterSymbol)x, currentHash),
SymbolKind.PointerType => CombineHashCodes((IPointerTypeSymbol)x, currentHash),
SymbolKind.Property => CombineHashCodes((IPropertySymbol)x, currentHash),
SymbolKind.RangeVariable => CombineHashCodes((IRangeVariableSymbol)x, currentHash),
SymbolKind.TypeParameter => CombineHashCodes((ITypeParameterSymbol)x, currentHash),
SymbolKind.Preprocessing => CombineHashCodes((IPreprocessingSymbol)x, currentHash),
_ => -1,
};
private int CombineHashCodes(IArrayTypeSymbol x, int currentHash)
{
......
......@@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.Shared.Utilities
{
......@@ -125,17 +126,13 @@ internal partial class SymbolEquivalenceComparer :
}
public bool ReturnTypeEquals(IMethodSymbol x, IMethodSymbol y, Dictionary<INamedTypeSymbol, INamedTypeSymbol> equivalentTypesWithDifferingAssemblies = null)
{
return GetEquivalenceVisitor().ReturnTypesAreEquivalent(x, y, equivalentTypesWithDifferingAssemblies);
}
=> GetEquivalenceVisitor().ReturnTypesAreEquivalent(x, y, equivalentTypesWithDifferingAssemblies);
/// <summary>
/// Compares given symbols <paramref name="x"/> and <paramref name="y"/> for equivalence.
/// </summary>
public bool Equals(ISymbol x, ISymbol y)
{
return EqualsCore(x, y, null);
}
=> EqualsCore(x, y, equivalentTypesWithDifferingAssemblies: null);
/// <summary>
/// Compares given symbols <paramref name="x"/> and <paramref name="y"/> for equivalence and populates <paramref name="equivalentTypesWithDifferingAssemblies"/>
......@@ -150,26 +147,13 @@ public bool Equals(ISymbol x, ISymbol y, Dictionary<INamedTypeSymbol, INamedType
}
private bool EqualsCore(ISymbol x, ISymbol y, Dictionary<INamedTypeSymbol, INamedTypeSymbol> equivalentTypesWithDifferingAssemblies)
{
return GetEquivalenceVisitor().AreEquivalent(x, y, equivalentTypesWithDifferingAssemblies);
}
=> GetEquivalenceVisitor().AreEquivalent(x, y, equivalentTypesWithDifferingAssemblies);
public int GetHashCode(ISymbol x)
{
return GetGetHashCodeVisitor(compareMethodTypeParametersByIndex: false, objectAndDynamicCompareEqually: false).GetHashCode(x, currentHash: 0);
}
=> GetGetHashCodeVisitor(compareMethodTypeParametersByIndex: false, objectAndDynamicCompareEqually: false).GetHashCode(x, currentHash: 0);
private static ISymbol UnwrapAlias(ISymbol symbol)
{
if (symbol.Kind == SymbolKind.Alias)
{
return ((IAliasSymbol)symbol).Target;
}
else
{
return symbol;
}
}
=> symbol.IsKind(SymbolKind.Alias, out IAliasSymbol alias) ? alias.Target : symbol;
private static SymbolKind GetKindAndUnwrapAlias(ref ISymbol symbol)
{
......@@ -184,19 +168,13 @@ private static SymbolKind GetKindAndUnwrapAlias(ref ISymbol symbol)
}
private static bool IsConstructedFromSelf(INamedTypeSymbol symbol)
{
return symbol.Equals(symbol.ConstructedFrom);
}
=> symbol.Equals(symbol.ConstructedFrom);
private static bool IsConstructedFromSelf(IMethodSymbol symbol)
{
return symbol.Equals(symbol.ConstructedFrom);
}
=> symbol.Equals(symbol.ConstructedFrom);
private static bool IsObjectType(ISymbol symbol)
{
return symbol.Kind == SymbolKind.NamedType && ((ITypeSymbol)symbol).SpecialType == SpecialType.System_Object;
}
=> symbol.IsKind(SymbolKind.NamedType, out ITypeSymbol typeSymbol) && typeSymbol.SpecialType == SpecialType.System_Object;
private static bool CheckContainingType(IMethodSymbol x)
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册