Skip to content

Commit

Permalink
Merge pull request #44256 from 333fred/symbol-matcher
Browse files Browse the repository at this point in the history
SymbolMatcher Support
  • Loading branch information
msftbot[bot] committed May 19, 2020
2 parents 3a6317a + f1fc867 commit 373f4fd
Show file tree
Hide file tree
Showing 2 changed files with 247 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,48 @@ public override Symbol VisitPointerType(PointerTypeSymbol symbol)
return new PointerTypeSymbol(symbol.PointedAtTypeWithAnnotations.WithTypeAndModifiers(otherPointedAtType, otherModifiers));
}

public override Symbol VisitFunctionPointerType(FunctionPointerTypeSymbol symbol)
{
var sig = symbol.Signature;

var otherReturnType = (TypeSymbol)Visit(sig.ReturnType);
if (otherReturnType is null)
{
return null;
}

var otherRefCustomModifiers = VisitCustomModifiers(sig.RefCustomModifiers);
var otherReturnTypeWithAnnotations = sig.ReturnTypeWithAnnotations.WithTypeAndModifiers(otherReturnType, VisitCustomModifiers(sig.ReturnTypeWithAnnotations.CustomModifiers));

var otherParameterTypes = ImmutableArray<TypeWithAnnotations>.Empty;
ImmutableArray<ImmutableArray<CustomModifier>> otherParamRefCustomModifiers = default;

if (sig.ParameterCount > 0)
{
var otherParamsBuilder = ArrayBuilder<TypeWithAnnotations>.GetInstance(sig.ParameterCount);
var otherParamRefCustomModifiersBuilder = ArrayBuilder<ImmutableArray<CustomModifier>>.GetInstance(sig.ParameterCount);

foreach (var param in sig.Parameters)
{
var otherType = (TypeSymbol)Visit(param.Type);
if (otherType is null)
{
otherParamsBuilder.Free();
otherParamRefCustomModifiersBuilder.Free();
return null;
}

otherParamRefCustomModifiersBuilder.Add(VisitCustomModifiers(param.RefCustomModifiers));
otherParamsBuilder.Add(param.TypeWithAnnotations.WithTypeAndModifiers(otherType, VisitCustomModifiers(param.TypeWithAnnotations.CustomModifiers)));
}

otherParameterTypes = otherParamsBuilder.ToImmutableAndFree();
otherParamRefCustomModifiers = otherParamRefCustomModifiersBuilder.ToImmutableAndFree();
}

return symbol.SubstituteTypeSymbol(otherReturnTypeWithAnnotations, otherParameterTypes, otherRefCustomModifiers, otherParamRefCustomModifiers);
}

public override Symbol VisitProperty(PropertySymbol symbol)
{
return this.VisitNamedTypeMember(symbol, ArePropertiesEqual);
Expand Down Expand Up @@ -736,6 +778,49 @@ private bool ArePointerTypesEqual(PointerTypeSymbol type, PointerTypeSymbol othe
return AreTypesEqual(type.PointedAtType, other.PointedAtType);
}

private bool AreFunctionPointerTypesEqual(FunctionPointerTypeSymbol type, FunctionPointerTypeSymbol other)
{
var sig = type.Signature;
var otherSig = other.Signature;

ValidateFunctionPointerParamOrReturn(sig.ReturnTypeWithAnnotations, sig.RefKind, sig.RefCustomModifiers, allowOut: false);
ValidateFunctionPointerParamOrReturn(otherSig.ReturnTypeWithAnnotations, otherSig.RefKind, otherSig.RefCustomModifiers, allowOut: false);
if (sig.RefKind != otherSig.RefKind || !AreTypesEqual(sig.ReturnTypeWithAnnotations, otherSig.ReturnTypeWithAnnotations))
{
return false;
}

return sig.Parameters.SequenceEqual(otherSig.Parameters, AreFunctionPointerParametersEqual);
}

private bool AreFunctionPointerParametersEqual(ParameterSymbol param, ParameterSymbol otherParam)
{
ValidateFunctionPointerParamOrReturn(param.TypeWithAnnotations, param.RefKind, param.RefCustomModifiers, allowOut: true);
ValidateFunctionPointerParamOrReturn(otherParam.TypeWithAnnotations, otherParam.RefKind, otherParam.RefCustomModifiers, allowOut: true);

return param.RefKind == otherParam.RefKind && AreTypesEqual(param.TypeWithAnnotations, otherParam.TypeWithAnnotations);
}

[Conditional("DEBUG")]
private static void ValidateFunctionPointerParamOrReturn(TypeWithAnnotations type, RefKind refKind, ImmutableArray<CustomModifier> refCustomModifiers, bool allowOut)
{
Debug.Assert(type.CustomModifiers.IsEmpty);
Debug.Assert(verifyRefModifiers(refCustomModifiers, refKind, allowOut));

static bool verifyRefModifiers(ImmutableArray<CustomModifier> modifiers, RefKind refKind, bool allowOut)
{
Debug.Assert(RefKind.RefReadOnly == RefKind.In);
switch (refKind)
{
case RefKind.RefReadOnly:
case RefKind.Out when allowOut:
return modifiers.Length == 1;
default:
return modifiers.IsEmpty;
}
}
}

private bool ArePropertiesEqual(PropertySymbol property, PropertySymbol other)
{
Debug.Assert(StringOrdinalComparer.Equals(property.MetadataName, other.MetadataName));
Expand Down Expand Up @@ -781,6 +866,9 @@ private bool AreTypesEqual(TypeSymbol type, TypeSymbol other)
case SymbolKind.PointerType:
return ArePointerTypesEqual((PointerTypeSymbol)type, (PointerTypeSymbol)other);

case SymbolKind.FunctionPointer:
return AreFunctionPointerTypesEqual((FunctionPointerTypeSymbol)type, (FunctionPointerTypeSymbol)other);

case SymbolKind.NamedType:
case SymbolKind.ErrorType:
return AreNamedTypesEqual((NamedTypeSymbol)type, (NamedTypeSymbol)other);
Expand Down Expand Up @@ -915,6 +1003,35 @@ public override Symbol VisitPointerType(PointerTypeSymbol symbol)
return new PointerTypeSymbol(symbol.PointedAtTypeWithAnnotations.WithTypeAndModifiers(translatedPointedAtType, translatedModifiers));
}

public override Symbol VisitFunctionPointerType(FunctionPointerTypeSymbol symbol)
{
var sig = symbol.Signature;
var translatedReturnType = (TypeSymbol)Visit(sig.ReturnType);
var translatedReturnTypeWithAnnotations = sig.ReturnTypeWithAnnotations.WithTypeAndModifiers(translatedReturnType, VisitCustomModifiers(sig.ReturnTypeWithAnnotations.CustomModifiers));
var translatedRefCustomModifiers = VisitCustomModifiers(sig.RefCustomModifiers);

var translatedParameterTypes = ImmutableArray<TypeWithAnnotations>.Empty;
ImmutableArray<ImmutableArray<CustomModifier>> translatedParamRefCustomModifiers = default;

if (sig.ParameterCount > 0)
{
var translatedParamsBuilder = ArrayBuilder<TypeWithAnnotations>.GetInstance(sig.ParameterCount);
var translatedParamRefCustomModifiersBuilder = ArrayBuilder<ImmutableArray<CustomModifier>>.GetInstance(sig.ParameterCount);

foreach (var param in sig.Parameters)
{
var translatedParamType = (TypeSymbol)Visit(param.Type);
translatedParamsBuilder.Add(param.TypeWithAnnotations.WithTypeAndModifiers(translatedParamType, VisitCustomModifiers(param.TypeWithAnnotations.CustomModifiers)));
translatedParamRefCustomModifiersBuilder.Add(VisitCustomModifiers(param.RefCustomModifiers));
}

translatedParameterTypes = translatedParamsBuilder.ToImmutableAndFree();
translatedParamRefCustomModifiers = translatedParamRefCustomModifiersBuilder.ToImmutableAndFree();
}

return symbol.SubstituteTypeSymbol(translatedReturnTypeWithAnnotations, translatedParameterTypes, translatedRefCustomModifiers, translatedParamRefCustomModifiers);
}

public override Symbol VisitTypeParameter(TypeParameterSymbol symbol)
{
return symbol;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1272,5 +1272,135 @@ event Action F { add { } remove { } }
Assert.Same(e0, matcher.MapDefinition(e1));
Assert.Same(f0, matcher.MapDefinition(f1));
}

[Fact]
public void FunctionPointerMembersTranslated()
{
var source = @"
unsafe class C
{
delegate*<void> f1;
delegate*<C, C, C> f2;
delegate*<ref C> f3;
delegate*<ref readonly C> f4;
delegate*<ref C, void> f5;
delegate*<in C, void> f6;
delegate*<out C, void> f7;
}
";

var compilation0 = CreateCompilation(source, options: TestOptions.UnsafeDebugDll, parseOptions: TestOptions.RegularPreview);
var compilation1 = compilation0.WithSource(source);

var matcher = new CSharpSymbolMatcher(
null,
compilation1.SourceAssembly,
default,
compilation0.SourceAssembly,
default,
null);

for (int i = 1; i <= 7; i++)
{
var f_0 = compilation0.GetMember<FieldSymbol>($"C.f{i}");
var f_1 = compilation1.GetMember<FieldSymbol>($"C.f{i}");

Assert.Same(f_0, matcher.MapDefinition(f_1));
}
}

[Theory]
[InlineData("C", "void")]
[InlineData("C", "object")]
[InlineData("C", "ref C")]
[InlineData("C", "ref readonly C")]
[InlineData("ref C", "ref readonly C")]
public void FunctionPointerMembers_ReturnMismatch(string return1, string return2)
{
var source1 = $@"
unsafe class C
{{
delegate*<C, {return1}> f1;
}}";

var source2 = $@"
unsafe class C
{{
delegate*<C, {return2}> f1;
}}";

var compilation0 = CreateCompilation(source1, options: TestOptions.UnsafeDebugDll, parseOptions: TestOptions.RegularPreview);
var compilation1 = compilation0.WithSource(source2);

var matcher = new CSharpSymbolMatcher(
null,
compilation1.SourceAssembly,
default,
compilation0.SourceAssembly,
default,
null);

var f_1 = compilation1.GetMember<FieldSymbol>($"C.f1");

Assert.Null(matcher.MapDefinition(f_1));
}

[Theory]
[InlineData("C", "object")]
[InlineData("C", "ref C")]
[InlineData("C", "out C")]
[InlineData("C", "in C")]
[InlineData("ref C", "out C")]
[InlineData("ref C", "in C")]
[InlineData("out C", "in C")]
[InlineData("C, C", "C")]
public void FunctionPointerMembers_ParamMismatch(string param1, string param2)
{
var source1 = $@"
unsafe class C
{{
delegate*<{param1}, C, void>* f1;
}}";

var source2 = $@"
unsafe class C
{{
delegate*<{param2}, C, void>* f1;
}}";

verify(source1, source2);

source1 = $@"
unsafe class C
{{
delegate*<C, {param1}, void> f1;
}}";

source2 = $@"
unsafe class C
{{
delegate*<C, {param2}, void> f1;
}}";

verify(source1, source2);

static void verify(string source1, string source2)
{
var compilation0 = CreateCompilation(source1, options: TestOptions.UnsafeDebugDll, parseOptions: TestOptions.RegularPreview);
var compilation1 = compilation0.WithSource(source2);

var matcher = new CSharpSymbolMatcher(
null,
compilation1.SourceAssembly,
default,
compilation0.SourceAssembly,
default,
null);

var f_1 = compilation1.GetMember<FieldSymbol>($"C.f1");

Assert.Null(matcher.MapDefinition(f_1));
}
}
}
}

0 comments on commit 373f4fd

Please sign in to comment.