/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/Core/CodeAnalysisTest/MetadataReferences/MetadataHelpersTests.cs
518 строк
23 KB
Tomáš Matoušek
Add support for FieldRva to EnC delta (#78033)
10 май 2025, 20:30
Не верифицирован
10 май 2025, 20:30
7c62502
Код
Авторство
О чём код?
// 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.Generic; using System.Linq; using System.Reflection.Metadata; using System.Text; using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.UnitTests { public class MetadataHelpersTests { [Fact] public void IsValidMetadataIdentifier() { string lowSurrogate = "\uDC00"; string highSurrogate = "\uD800"; Assert.True(Char.IsLowSurrogate(lowSurrogate, 0)); Assert.True(Char.IsHighSurrogate(highSurrogate, 0)); Assert.True(Char.IsSurrogatePair(highSurrogate + lowSurrogate, 0)); Assert.False(MetadataHelpers.IsValidMetadataIdentifier(null)); Assert.False(MetadataHelpers.IsValidMetadataIdentifier("")); Assert.True(MetadataHelpers.IsValidMetadataIdentifier("x")); Assert.False(MetadataHelpers.IsValidMetadataIdentifier("\0")); Assert.False(MetadataHelpers.IsValidMetadataIdentifier("x\0")); Assert.False(MetadataHelpers.IsValidMetadataIdentifier("\0x")); Assert.False(MetadataHelpers.IsValidMetadataIdentifier("abc\0xyz\0uwq")); Assert.False(MetadataHelpers.IsValidMetadataIdentifier(lowSurrogate)); Assert.False(MetadataHelpers.IsValidMetadataIdentifier(highSurrogate)); Assert.True(MetadataHelpers.IsValidMetadataIdentifier(highSurrogate + lowSurrogate)); Assert.False(MetadataHelpers.IsValidMetadataIdentifier(lowSurrogate + highSurrogate)); Assert.False(MetadataHelpers.IsValidMetadataIdentifier(highSurrogate + "x" + lowSurrogate)); Assert.False(MetadataHelpers.IsValidMetadataIdentifier(lowSurrogate + "x" + highSurrogate)); Assert.False(MetadataHelpers.IsValidMetadataIdentifier(highSurrogate + "xxx")); Assert.False(MetadataHelpers.IsValidMetadataIdentifier(lowSurrogate + "xxx")); Assert.False(MetadataHelpers.IsValidMetadataIdentifier(lowSurrogate + "\0" + highSurrogate)); Assert.False(MetadataHelpers.IsValidMetadataIdentifier(highSurrogate + "\0" + lowSurrogate)); } private enum ArrayKind { None, SzArray, SingleDimensional, MultiDimensional, JaggedSzArray, Jagged }; private readonly struct TypeNameConfig { public readonly int NestingLevel; public readonly TypeNameConfig[] GenericParamsConfig; public readonly int PointerCount; public readonly ArrayKind ArrayKind; public readonly bool AssemblyQualified; public TypeNameConfig(int nestingLevel, TypeNameConfig[] genericParamsConfig, int pointerCount, ArrayKind arrayKind, bool assemblyQualified) { this.NestingLevel = nestingLevel; this.GenericParamsConfig = genericParamsConfig; this.PointerCount = pointerCount; this.ArrayKind = arrayKind; this.AssemblyQualified = assemblyQualified; } } private static TypeNameConfig[] GenerateTypeNameConfigs(int typeParamStackDepth) { var builder = ArrayBuilder<TypeNameConfig>.GetInstance(); for (int nestingLevel = 0; nestingLevel <= 2; nestingLevel++) { for (int pointerCount = 0; pointerCount <= 2; pointerCount++) { foreach (ArrayKind arrayKind in Enum.GetValues(typeof(ArrayKind))) { var genericParamsConfigBuilder = ArrayBuilder<TypeNameConfig[]>.GetInstance(); genericParamsConfigBuilder.Add(null); if (typeParamStackDepth < 2) { genericParamsConfigBuilder.Add(GenerateTypeNameConfigs(typeParamStackDepth + 1)); } foreach (var genericParamsConfig in genericParamsConfigBuilder.ToImmutableAndFree()) { builder.Add(new TypeNameConfig(nestingLevel, genericParamsConfig, pointerCount, arrayKind, assemblyQualified: true)); builder.Add(new TypeNameConfig(nestingLevel, genericParamsConfig, pointerCount, arrayKind, assemblyQualified: false)); } } } } return builder.ToArrayAndFree(); } private static string[] GenerateTypeNamesToDecode(TypeNameConfig[] typeNameConfigs, out MetadataHelpers.AssemblyQualifiedTypeName[] expectedDecodeNames) { var pooledStrBuilder = PooledStringBuilder.GetInstance(); StringBuilder typeNameBuilder = pooledStrBuilder.Builder; var typeNamesToDecode = new string[typeNameConfigs.Length]; expectedDecodeNames = new MetadataHelpers.AssemblyQualifiedTypeName[typeNameConfigs.Length]; for (int index = 0; index < typeNameConfigs.Length; index++) { TypeNameConfig typeNameConfig = typeNameConfigs[index]; string expectedTopLevelTypeName = "X"; typeNameBuilder.Append('X'); string[] expectedNestedTypes = null; if (typeNameConfig.NestingLevel > 0) { expectedNestedTypes = new string[typeNameConfig.NestingLevel]; for (int i = 0; i < typeNameConfig.NestingLevel; i++) { expectedNestedTypes[i] = "Y" + i; typeNameBuilder.Append("+" + expectedNestedTypes[i]); } } MetadataHelpers.AssemblyQualifiedTypeName[] expectedTypeArguments; if (typeNameConfig.GenericParamsConfig == null) { expectedTypeArguments = null; } else { string[] genericParamsToDecode = GenerateTypeNamesToDecode(typeNameConfig.GenericParamsConfig, out expectedTypeArguments); var genericArityStr = "`" + genericParamsToDecode.Length.ToString(); typeNameBuilder.Append(genericArityStr); if (typeNameConfig.NestingLevel == 0) { expectedTopLevelTypeName += genericArityStr; } else { expectedNestedTypes[typeNameConfig.NestingLevel - 1] += genericArityStr; } typeNameBuilder.Append('['); for (int i = 0; i < genericParamsToDecode.Length; i++) { if (i > 0) { typeNameBuilder.Append(", "); } if (typeNameConfig.GenericParamsConfig[i].AssemblyQualified) { typeNameBuilder.Append('['); typeNameBuilder.Append(genericParamsToDecode[i]); typeNameBuilder.Append(']'); } else { typeNameBuilder.Append(genericParamsToDecode[i]); } } typeNameBuilder.Append(']'); } int expectedPointerCount = typeNameConfig.PointerCount; typeNameBuilder.Append('*', expectedPointerCount); int[] expectedArrayRanks = null; switch (typeNameConfig.ArrayKind) { case ArrayKind.SzArray: typeNameBuilder.Append("[]"); expectedArrayRanks = new[] { 0 }; break; case ArrayKind.SingleDimensional: typeNameBuilder.Append("[*]"); expectedArrayRanks = new[] { 1 }; break; case ArrayKind.MultiDimensional: typeNameBuilder.Append("[,]"); expectedArrayRanks = new[] { 2 }; break; case ArrayKind.JaggedSzArray: typeNameBuilder.Append("[,][]"); expectedArrayRanks = new[] { 2, 0 }; break; case ArrayKind.Jagged: typeNameBuilder.Append("[,][*]"); expectedArrayRanks = new[] { 2, 1 }; break; } string expectedAssemblyName; if (typeNameConfig.AssemblyQualified) { expectedAssemblyName = "Assembly, Version=0.0.0.0, Culture=neutral, null"; typeNameBuilder.Append(", " + expectedAssemblyName); } else { expectedAssemblyName = null; } typeNamesToDecode[index] = typeNameBuilder.ToString(); expectedDecodeNames[index] = new MetadataHelpers.AssemblyQualifiedTypeName(expectedTopLevelTypeName, expectedNestedTypes, expectedTypeArguments, expectedPointerCount, expectedArrayRanks, expectedAssemblyName); typeNameBuilder.Clear(); } pooledStrBuilder.Free(); return typeNamesToDecode; } private static void VerifyDecodedTypeName( MetadataHelpers.AssemblyQualifiedTypeName decodedName, string expectedTopLevelType, string expectedAssemblyName, string[] expectedNestedTypes, MetadataHelpers.AssemblyQualifiedTypeName[] expectedTypeArguments, int expectedPointerCount, int[] expectedArrayRanks) { Assert.Equal(expectedTopLevelType, decodedName.TopLevelType); Assert.Equal(expectedAssemblyName, decodedName.AssemblyName); Assert.Equal(expectedNestedTypes, decodedName.NestedTypes); if (decodedName.TypeArguments == null) { Assert.Null(expectedTypeArguments); } else { var decodedTypeArguments = decodedName.TypeArguments; for (int i = 0; i < decodedTypeArguments.Length; i++) { var expectedTypeArgument = expectedTypeArguments[i]; VerifyDecodedTypeName(decodedTypeArguments[i], expectedTypeArgument.TopLevelType, expectedTypeArgument.AssemblyName, expectedTypeArgument.NestedTypes, expectedTypeArgument.TypeArguments, expectedTypeArgument.PointerCount, expectedTypeArgument.ArrayRanks); } } Assert.Equal(expectedPointerCount, decodedName.PointerCount); AssertEx.Equal(expectedArrayRanks, decodedName.ArrayRanks); } private static void DecodeTypeNameAndVerify( string nameToDecode, string expectedTopLevelType, string expectedAssemblyName = null, string[] expectedNestedTypes = null, MetadataHelpers.AssemblyQualifiedTypeName[] expectedTypeArguments = null, int expectedPointerCount = 0, int[] expectedArrayRanks = null) { MetadataHelpers.AssemblyQualifiedTypeName decodedName = MetadataHelpers.DecodeTypeName(nameToDecode); VerifyDecodedTypeName(decodedName, expectedTopLevelType, expectedAssemblyName, expectedNestedTypes, expectedTypeArguments, expectedPointerCount, expectedArrayRanks); } private static void DecodeTypeNamesAndVerify(string[] namesToDecode, MetadataHelpers.AssemblyQualifiedTypeName[] expectedDecodedNames) { Assert.Equal(namesToDecode.Length, expectedDecodedNames.Length); for (int i = 0; i < namesToDecode.Length; i++) { var expectedDecodedName = expectedDecodedNames[i]; DecodeTypeNameAndVerify(namesToDecode[i], expectedDecodedName.TopLevelType, expectedDecodedName.AssemblyName, expectedDecodedName.NestedTypes, expectedDecodedName.TypeArguments, expectedDecodedName.PointerCount, expectedDecodedName.ArrayRanks); } } [WorkItem(546277, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546277")] [Fact] public void TestDecodeTypeNameMatrix() { TypeNameConfig[] configsToTest = GenerateTypeNameConfigs(0); MetadataHelpers.AssemblyQualifiedTypeName[] expectedDecodedNames; string[] namesToDecode = GenerateTypeNamesToDecode(configsToTest, out expectedDecodedNames); DecodeTypeNamesAndVerify(namesToDecode, expectedDecodedNames); } [WorkItem(546277, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546277")] [Fact] public void TestDecodeArrayTypeName_Bug15478() { DecodeTypeNameAndVerify("System.Int32[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", expectedTopLevelType: "System.Int32", expectedAssemblyName: "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", expectedArrayRanks: new[] { 0 }); DecodeTypeNameAndVerify("System.Int32[*], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", expectedTopLevelType: "System.Int32", expectedAssemblyName: "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", expectedArrayRanks: new[] { 1 }); } [WorkItem(546277, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546277")] [Fact] public void TestDecodeArrayTypeName_Valid() { // Single-D Array DecodeTypeNameAndVerify("W[]", expectedTopLevelType: "W", expectedArrayRanks: new[] { 0 }); // Multi-D Array DecodeTypeNameAndVerify("W[,]", expectedTopLevelType: "W", expectedArrayRanks: new[] { 2 }); // Jagged Array DecodeTypeNameAndVerify("W[][,]", expectedTopLevelType: "W", expectedArrayRanks: new[] { 0, 2 }); // Generic Type Jagged Array DecodeTypeNameAndVerify("Y`1[W][][,]", expectedTopLevelType: "Y`1", expectedTypeArguments: new[] { new MetadataHelpers.AssemblyQualifiedTypeName("W", null, null, 0, null, null) }, expectedArrayRanks: new[] { 0, 2 }); // Nested Generic Type Jagged Array with Array type argument DecodeTypeNameAndVerify("Y`1+F[[System.Int32[], mscorlib]][,,][][,]", expectedTopLevelType: "Y`1", expectedNestedTypes: new[] { "F" }, expectedTypeArguments: new[] { new MetadataHelpers.AssemblyQualifiedTypeName( "System.Int32", nestedTypes: null, typeArguments: null, pointerCount: 0, arrayRanks: new[] { 0 }, assemblyName: "mscorlib") }, expectedArrayRanks: new[] { 3, 0, 2 }); // Nested Generic Type Jagged Array with type arguments from nested type and outer type DecodeTypeNameAndVerify("Y`1+Z`1[[System.Int32[], mscorlib], W][][,]", expectedTopLevelType: "Y`1", expectedNestedTypes: new[] { "Z`1" }, expectedTypeArguments: new[] { new MetadataHelpers.AssemblyQualifiedTypeName( "System.Int32", nestedTypes: null, typeArguments: null, pointerCount: 0, arrayRanks: new[] { 0 }, assemblyName: "mscorlib"), new MetadataHelpers.AssemblyQualifiedTypeName("W", null, null, 0, null, null) }, expectedArrayRanks: new[] { 0, 2 }); } [WorkItem(546277, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546277")] [Fact] public void TestDecodeArrayTypeName_Invalid() { // Error case, array shape before nested type DecodeTypeNameAndVerify("X[]+Y", expectedTopLevelType: "X+Y", expectedNestedTypes: null, expectedArrayRanks: new[] { 0 }); // Error case, array shape before generic type arguments DecodeTypeNameAndVerify("X[]`1[T]", expectedTopLevelType: "X`1[T]", expectedTypeArguments: null, expectedArrayRanks: new[] { 0 }); // Error case, invalid array shape DecodeTypeNameAndVerify("X[T]", expectedTopLevelType: "X[T]", expectedTypeArguments: null, expectedArrayRanks: null); DecodeTypeNameAndVerify("X[,", expectedTopLevelType: "X[,", expectedTypeArguments: null, expectedArrayRanks: null); // Incomplete type argument assembly name DecodeTypeNameAndVerify("X`1[[T, Assembly", expectedTopLevelType: "X`1", expectedAssemblyName: null, expectedTypeArguments: new[] { new MetadataHelpers.AssemblyQualifiedTypeName("T", null, null, 0, null, "Assembly") }, expectedArrayRanks: null); } [WorkItem(1140387, "DevDiv")] [Fact] public void TestDecodePointerType_Invalid() { // Error case, star before nested type DecodeTypeNameAndVerify("X*+Y", expectedTopLevelType: "X+Y", expectedNestedTypes: null, expectedPointerCount: 1); // Error case, star before generic type arguments DecodeTypeNameAndVerify("X*`1[T]", expectedTopLevelType: "X`1[T]", expectedTypeArguments: null, expectedPointerCount: 1); // Unsupported case, star after array shape // This is supported in the AQN grammar, but not in C# or VB. DecodeTypeNameAndVerify("W[]*", expectedTopLevelType: "W*", expectedTypeArguments: null, expectedPointerCount: 0, expectedArrayRanks: new[] { 0 }); } [Fact, WorkItem(7396, "https://github.com/dotnet/roslyn/issues/7396")] public void ObfuscatedNamespaceNames_01() { var result = new ArrayBuilder<IGrouping<string, TypeDefinitionHandle>>(); foreach (var namespaceName in new[] { "A.", "A.a", "A..", "A.-" }) { result.Add(new Grouping<string, TypeDefinitionHandle>(namespaceName, new[] { new TypeDefinitionHandle() })); } result.Sort(new PEModule.TypesByNamespaceSortComparer(StringComparer.Ordinal)); // This is equivalent to the result of PEModule.GroupTypesByNamespaceOrThrow IEnumerable<IGrouping<string, TypeDefinitionHandle>> typesByNS = result; // The following code is equivalent to code in PENamespaceSymbol.LoadAllMembers IEnumerable<IGrouping<string, TypeDefinitionHandle>> nestedTypes = null; IEnumerable<KeyValuePair<string, IEnumerable<IGrouping<string, TypeDefinitionHandle>>>> nestedNamespaces = null; MetadataHelpers.GetInfoForImmediateNamespaceMembers( false, "A".Length, typesByNS, StringComparer.Ordinal, out nestedTypes, out nestedNamespaces); // We don't expect duplicate keys in nestedNamespaces at this point. Assert.False(nestedNamespaces.GroupBy(pair => pair.Key).Where(g => g.Count() > 1).Any()); var array = nestedNamespaces.ToArray(); Assert.Equal(3, array.Length); Assert.Equal("", array[0].Key); Assert.Equal(2, array[0].Value.Count()); Assert.Equal("-", array[1].Key); Assert.Equal(1, array[1].Value.Count()); Assert.Equal("a", array[2].Key); Assert.Equal(1, array[2].Value.Count()); } [Fact, WorkItem(7396, "https://github.com/dotnet/roslyn/issues/7396")] public void ObfuscatedNamespaceNames_02() { var result = new ArrayBuilder<IGrouping<string, TypeDefinitionHandle>>(); foreach (var namespaceName in new[] { ".a", ".b" }) { result.Add(new Grouping<string, TypeDefinitionHandle>(namespaceName, new[] { new TypeDefinitionHandle() })); } result.Sort(new PEModule.TypesByNamespaceSortComparer(StringComparer.Ordinal)); // This is equivalent to the result of PEModule.GroupTypesByNamespaceOrThrow IEnumerable<IGrouping<string, TypeDefinitionHandle>> typesByNS = result; // The following code is equivalent to code in PENamespaceSymbol.LoadAllMembers IEnumerable<IGrouping<string, TypeDefinitionHandle>> nestedTypes = null; IEnumerable<KeyValuePair<string, IEnumerable<IGrouping<string, TypeDefinitionHandle>>>> nestedNamespaces = null; MetadataHelpers.GetInfoForImmediateNamespaceMembers( true, // global namespace 0, // global namespace typesByNS, StringComparer.Ordinal, out nestedTypes, out nestedNamespaces); var nestedNS = nestedNamespaces.Single(); Assert.Equal("", nestedNS.Key); Assert.Equal(2, nestedNS.Value.Count()); MetadataHelpers.GetInfoForImmediateNamespaceMembers( false, nestedNS.Key.Length, nestedNS.Value, StringComparer.Ordinal, out nestedTypes, out nestedNamespaces); Assert.Equal(2, nestedNamespaces.Count()); Assert.Equal("a", nestedNamespaces.ElementAt(0).Key); Assert.Equal("b", nestedNamespaces.ElementAt(1).Key); } [Theory] [InlineData("")] [InlineData("abc")] [InlineData("\u1234")] public static void GetUserStringBlobSize(string str) { var builder = new BlobBuilder(); builder.WriteUserString(str); Assert.Equal(builder.Count, MetadataHelpers.GetUserStringBlobSize(str)); } } }