|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable disable
using System;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols.Metadata.PE
{
public class LoadingProperties : CSharpTestBase
{
[Fact]
public void TestExplicitImplementationSimple()
{
var assembly = MetadataTestHelpers.GetSymbolForReference(
TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Properties.CSharp);
var globalNamespace = assembly.GlobalNamespace;
var @interface = (NamedTypeSymbol)globalNamespace.GetTypeMembers("Interface").Single();
Assert.Equal(TypeKind.Interface, @interface.TypeKind);
var interfaceProperty = (PropertySymbol)@interface.GetMembers("Property").Single();
var @class = (NamedTypeSymbol)globalNamespace.GetTypeMembers("Class").Single();
Assert.Equal(TypeKind.Class, @class.TypeKind);
Assert.True(@class.Interfaces().Contains(@interface));
var classProperty = (PropertySymbol)@class.GetMembers("Interface.Property").Single();
var explicitImpl = classProperty.ExplicitInterfaceImplementations.Single();
Assert.Equal(interfaceProperty, explicitImpl);
}
[Fact]
public void TestExplicitImplementationGeneric()
{
var assemblies = MetadataTestHelpers.GetSymbolsForReferences(
new[]
{
NetFramework.mscorlib,
TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Properties.CSharp,
});
var globalNamespace = assemblies.ElementAt(1).GlobalNamespace;
var @interface = (NamedTypeSymbol)globalNamespace.GetTypeMembers("IGeneric").Single();
Assert.Equal(TypeKind.Interface, @interface.TypeKind);
var interfaceProperty = (PropertySymbol)@interface.GetMembers("Property").Single();
var @class = (NamedTypeSymbol)globalNamespace.GetTypeMembers("Generic").Single();
Assert.Equal(TypeKind.Class, @class.TypeKind);
var substitutedInterface = @class.Interfaces().Single();
Assert.Equal(@interface, substitutedInterface.ConstructedFrom);
var substitutedInterfaceProperty = (PropertySymbol)substitutedInterface.GetMembers("Property").Single();
Assert.Equal(interfaceProperty, substitutedInterfaceProperty.OriginalDefinition);
var classProperty = (PropertySymbol)@class.GetMembers("IGeneric<S>.Property").Single();
var explicitImpl = classProperty.ExplicitInterfaceImplementations.Single();
Assert.Equal(substitutedInterfaceProperty, explicitImpl);
}
[Fact]
public void TestExplicitImplementationConstructed()
{
var assemblies = MetadataTestHelpers.GetSymbolsForReferences(
new[]
{
NetFramework.mscorlib,
TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Properties.CSharp,
});
var globalNamespace = assemblies.ElementAt(1).GlobalNamespace;
var @interface = (NamedTypeSymbol)globalNamespace.GetTypeMembers("IGeneric").Single();
Assert.Equal(TypeKind.Interface, @interface.TypeKind);
var interfaceProperty = (PropertySymbol)@interface.GetMembers("Property").Single();
var @class = (NamedTypeSymbol)globalNamespace.GetTypeMembers("Constructed").Single();
Assert.Equal(TypeKind.Class, @class.TypeKind);
var substitutedInterface = @class.Interfaces().Single();
Assert.Equal(@interface, substitutedInterface.ConstructedFrom);
var substitutedInterfaceProperty = (PropertySymbol)substitutedInterface.GetMembers("Property").Single();
Assert.Equal(interfaceProperty, substitutedInterfaceProperty.OriginalDefinition);
var classProperty = (PropertySymbol)@class.GetMembers("IGeneric<System.Int32>.Property").Single();
var explicitImpl = classProperty.ExplicitInterfaceImplementations.Single();
Assert.Equal(substitutedInterfaceProperty, explicitImpl);
}
/// <summary>
/// A type def explicitly implements an interface, also a type def, but only
/// indirectly, via a type ref.
/// </summary>
[Fact]
public void TestExplicitImplementationDefRefDef()
{
var assemblies = MetadataTestHelpers.GetSymbolsForReferences(
new[]
{
NetFramework.mscorlib,
TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Properties.CSharp,
});
var globalNamespace = assemblies.ElementAt(1).GlobalNamespace;
var defInterface = (NamedTypeSymbol)globalNamespace.GetTypeMembers("Interface").Single();
Assert.Equal(TypeKind.Interface, defInterface.TypeKind);
var defInterfaceProperty = (PropertySymbol)defInterface.GetMembers("Property").Single();
var refInterface = (NamedTypeSymbol)globalNamespace.GetTypeMembers("IGenericInterface").Single();
Assert.Equal(TypeKind.Interface, defInterface.TypeKind);
Assert.True(refInterface.Interfaces().Contains(defInterface));
var @class = (NamedTypeSymbol)globalNamespace.GetTypeMembers("IndirectImplementation").Single();
Assert.Equal(TypeKind.Class, @class.TypeKind);
var classInterfacesConstructedFrom = @class.Interfaces().Select(i => i.ConstructedFrom);
Assert.Equal(2, classInterfacesConstructedFrom.Count());
Assert.Contains(defInterface, classInterfacesConstructedFrom);
Assert.Contains(refInterface, classInterfacesConstructedFrom);
var classProperty = (PropertySymbol)@class.GetMembers("Interface.Property").Single();
var explicitImpl = classProperty.ExplicitInterfaceImplementations.Single();
Assert.Equal(defInterfaceProperty, explicitImpl);
}
/// <summary>
/// In metadata, nested types implicitly share all type parameters of their containing types.
/// This results in some extra computations when mapping a type parameter position to a type
/// parameter symbol.
/// </summary>
[Fact]
public void TestTypeParameterPositions()
{
var assemblies = MetadataTestHelpers.GetSymbolsForReferences(
new[]
{
NetFramework.mscorlib,
TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Properties.CSharp,
});
var globalNamespace = assemblies.ElementAt(1).GlobalNamespace;
var outerInterface = (NamedTypeSymbol)globalNamespace.GetTypeMembers("IGeneric2").Single();
Assert.Equal(1, outerInterface.Arity);
Assert.Equal(TypeKind.Interface, outerInterface.TypeKind);
var outerInterfaceProperty = outerInterface.GetMembers().Single(m => m.Kind == SymbolKind.Property);
var outerClass = (NamedTypeSymbol)globalNamespace.GetTypeMembers("Outer").Single();
Assert.Equal(1, outerClass.Arity);
Assert.Equal(TypeKind.Class, outerClass.TypeKind);
var innerInterface = (NamedTypeSymbol)outerClass.GetTypeMembers("IInner").Single();
Assert.Equal(1, innerInterface.Arity);
Assert.Equal(TypeKind.Interface, innerInterface.TypeKind);
var innerInterfaceProperty = innerInterface.GetMembers().Single(m => m.Kind == SymbolKind.Property);
var innerClass1 = (NamedTypeSymbol)outerClass.GetTypeMembers("Inner1").Single();
CheckInnerClassHelper(innerClass1, "IGeneric2<A>.Property", outerInterfaceProperty);
var innerClass2 = (NamedTypeSymbol)outerClass.GetTypeMembers("Inner2").Single();
CheckInnerClassHelper(innerClass2, "IGeneric2<T>.Property", outerInterfaceProperty);
var innerClass3 = (NamedTypeSymbol)outerClass.GetTypeMembers("Inner3").Single();
CheckInnerClassHelper(innerClass3, "Outer<T>.IInner<C>.Property", innerInterfaceProperty);
var innerClass4 = (NamedTypeSymbol)outerClass.GetTypeMembers("Inner4").Single();
CheckInnerClassHelper(innerClass4, "Outer<T>.IInner<T>.Property", innerInterfaceProperty);
}
private static void CheckInnerClassHelper(NamedTypeSymbol innerClass, string methodName, Symbol interfaceProperty)
{
var @interface = interfaceProperty.ContainingType;
Assert.Equal(1, innerClass.Arity);
Assert.Equal(TypeKind.Class, innerClass.TypeKind);
Assert.Equal(@interface, innerClass.Interfaces().Single().ConstructedFrom);
var innerClassProperty = (PropertySymbol)innerClass.GetMembers(methodName).Single();
var innerClassImplementingProperty = innerClassProperty.ExplicitInterfaceImplementations.Single();
Assert.Equal(interfaceProperty, innerClassImplementingProperty.OriginalDefinition);
Assert.Equal(@interface, innerClassImplementingProperty.ContainingType.ConstructedFrom);
}
/// <summary>
/// Interface has 1{g;s}, 2{g;s}, 3{g;s}, 4{g}, 5{s}
/// Class has 1{g;s}, 2{g;s}
/// Class 1g implements Interface 1g, 2g, 4g
/// Class 1s implements Interface 1s, 3s, 5s
/// Class 2g implements Interface 2s
/// Class 2s implements Interface 3g
/// </summary>
[Fact]
public void TestExplicitImplementationMultipleAndPartial()
{
var assemblies = MetadataTestHelpers.GetSymbolsForReferences(
new[]
{
NetFramework.mscorlib,
TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Properties.IL,
});
var globalNamespace = assemblies.ElementAt(1).GlobalNamespace;
var @interface = (NamedTypeSymbol)globalNamespace.GetTypeMembers("Interface").Single();
Assert.Equal(TypeKind.Interface, @interface.TypeKind);
var interfaceProperty1 = (PropertySymbol)@interface.GetMembers("Property1").Single();
var interfaceProperty2 = (PropertySymbol)@interface.GetMembers("Property2").Single();
var interfaceProperty3 = (PropertySymbol)@interface.GetMembers("Property3").Single();
var interfaceProperty4 = (PropertySymbol)@interface.GetMembers("Property4").Single();
var interfaceProperty5 = (PropertySymbol)@interface.GetMembers("Property5").Single();
Assert.NotNull(interfaceProperty1.GetMethod);
Assert.NotNull(interfaceProperty1.SetMethod);
Assert.NotNull(interfaceProperty2.GetMethod);
Assert.NotNull(interfaceProperty2.SetMethod);
Assert.NotNull(interfaceProperty3.GetMethod);
Assert.NotNull(interfaceProperty3.SetMethod);
Assert.NotNull(interfaceProperty4.GetMethod);
Assert.Null(interfaceProperty4.SetMethod);
Assert.Null(interfaceProperty5.GetMethod);
Assert.NotNull(interfaceProperty5.SetMethod);
var @class = (NamedTypeSymbol)globalNamespace.GetTypeMembers("Class").Single();
Assert.Equal(TypeKind.Class, @class.TypeKind);
var classProperty1 = (PropertySymbol)@class.GetMembers("Property1").Single();
var classProperty2 = (PropertySymbol)@class.GetMembers("Property2").Single();
Assert.NotNull(classProperty1.GetMethod);
Assert.NotNull(classProperty1.SetMethod);
Assert.NotNull(classProperty2.GetMethod);
Assert.NotNull(classProperty2.SetMethod);
var implementedByProperty1 = ImmutableArray.Create<PropertySymbol>(interfaceProperty1, interfaceProperty4, interfaceProperty5);
Assert.True(implementedByProperty1.SetEquals(classProperty1.ExplicitInterfaceImplementations, ReferenceEqualityComparer.Instance));
Assert.Equal(0, classProperty2.ExplicitInterfaceImplementations.Length);
var implementedByGetter1 = ImmutableArray.Create<MethodSymbol>(interfaceProperty1.GetMethod, interfaceProperty2.GetMethod, interfaceProperty4.GetMethod);
Assert.True(implementedByGetter1.SetEquals(classProperty1.GetMethod.ExplicitInterfaceImplementations, ReferenceEqualityComparer.Instance));
var implementedBySetter1 = ImmutableArray.Create<MethodSymbol>(interfaceProperty1.SetMethod, interfaceProperty3.SetMethod, interfaceProperty5.SetMethod);
Assert.True(implementedBySetter1.SetEquals(classProperty1.SetMethod.ExplicitInterfaceImplementations, ReferenceEqualityComparer.Instance));
var implementedByGetter2 = ImmutableArray.Create<MethodSymbol>(interfaceProperty3.GetMethod);
Assert.True(implementedByGetter2.SetEquals(classProperty2.GetMethod.ExplicitInterfaceImplementations, ReferenceEqualityComparer.Instance));
var implementedBySetter2 = ImmutableArray.Create<MethodSymbol>(interfaceProperty2.SetMethod);
Assert.True(implementedBySetter2.SetEquals(classProperty2.SetMethod.ExplicitInterfaceImplementations, ReferenceEqualityComparer.Instance));
Assert.Same(classProperty1, @class.FindImplementationForInterfaceMember(interfaceProperty1));
Assert.Same(classProperty1, @class.FindImplementationForInterfaceMember(interfaceProperty4));
Assert.Same(classProperty1, @class.FindImplementationForInterfaceMember(interfaceProperty5));
Assert.Null(@class.FindImplementationForInterfaceMember(interfaceProperty2));
Assert.Null(@class.FindImplementationForInterfaceMember(interfaceProperty3));
}
[WorkItem(543263, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543263")]
[Fact]
public void TestMixedAccessorModifiers()
{
var assembly = MetadataTestHelpers.GetSymbolForReference(TestReferences.SymbolsTests.Properties);
var globalNamespace = assembly.GlobalNamespace;
var type = globalNamespace.GetMember<NamedTypeSymbol>("AccessorModifierMismatch");
const VirtualnessModifiers @none = VirtualnessModifiers.None;
const VirtualnessModifiers @abstract = VirtualnessModifiers.Abstract;
const VirtualnessModifiers @virtual = VirtualnessModifiers.Virtual;
const VirtualnessModifiers @override = VirtualnessModifiers.Override;
const VirtualnessModifiers @sealed = VirtualnessModifiers.Sealed;
VirtualnessModifiers[] modList = new[]
{
@none,
@abstract,
@virtual,
@override,
@sealed,
};
int length = 1 + modList.Cast<int>().Max();
VirtualnessModifiers[,] expected = new VirtualnessModifiers[length, length];
expected[(int)@none, (int)@none] = @none;
expected[(int)@none, (int)@abstract] = @abstract;
expected[(int)@none, (int)@virtual] = @virtual;
expected[(int)@none, (int)@override] = @override;
expected[(int)@none, (int)@sealed] = @override; //not both sealed
expected[(int)@abstract, (int)@none] = @abstract;
expected[(int)@abstract, (int)@abstract] = @abstract;
expected[(int)@abstract, (int)@virtual] = @abstract;
expected[(int)@abstract, (int)@override] = @abstract | @override;
expected[(int)@abstract, (int)@sealed] = @abstract | @override; //not both sealed
expected[(int)@virtual, (int)@none] = @virtual;
expected[(int)@virtual, (int)@abstract] = @abstract;
expected[(int)@virtual, (int)@virtual] = @virtual;
expected[(int)@virtual, (int)@override] = @override;
expected[(int)@virtual, (int)@sealed] = @override; //not both sealed
expected[(int)@override, (int)@none] = @override;
expected[(int)@override, (int)@abstract] = @override | @abstract;
expected[(int)@override, (int)@virtual] = @override;
expected[(int)@override, (int)@override] = @override;
expected[(int)@override, (int)@sealed] = @override; //not both sealed
expected[(int)@sealed, (int)@none] = @override; //not both sealed
expected[(int)@sealed, (int)@abstract] = @abstract | @override; //not both sealed
expected[(int)@sealed, (int)@virtual] = @override; //not both sealed
expected[(int)@sealed, (int)@override] = @override; //not both sealed
expected[(int)@sealed, (int)@sealed] = @sealed;
// Table should be symmetrical.
for (int i = 0; i < length; i++)
{
for (int j = 0; j < length; j++)
{
Assert.Equal(expected[i, j], expected[j, i]);
}
}
foreach (var mod1 in modList)
{
foreach (var mod2 in modList)
{
var property = type.GetMember<PropertySymbol>(mod1.ToString() + mod2.ToString());
var getter = property.GetMethod;
var setter = property.SetMethod;
Assert.Equal(mod1, GetVirtualnessModifiers(getter));
Assert.Equal(mod2, GetVirtualnessModifiers(setter));
Assert.Equal(expected[(int)mod1, (int)mod2], GetVirtualnessModifiers(property));
}
}
}
[Flags]
private enum VirtualnessModifiers
{
None = 0,
Abstract = 1,
Virtual = 2,
Override = 4,
Sealed = 8, //actually indicates sealed override
}
private static VirtualnessModifiers GetVirtualnessModifiers(Symbol symbol)
{
VirtualnessModifiers mods = VirtualnessModifiers.None;
if (symbol.IsAbstract) mods |= VirtualnessModifiers.Abstract;
if (symbol.IsVirtual) mods |= VirtualnessModifiers.Virtual;
if (symbol.IsSealed) mods |= VirtualnessModifiers.Sealed;
else if (symbol.IsOverride) mods |= VirtualnessModifiers.Override;
return mods;
}
}
}
|