提交 207a7706 编写于 作者: A AlekseyTs

Support multi-dimensional arrays of rank 1 for System.Type arguments of attributes.

Fixes #4958.
上级 fb2fcec0
......@@ -1567,5 +1567,131 @@ Overriden 15
Overriden 16
");
}
[ClrOnlyFact(ClrOnlyReason.Ilasm)]
[WorkItem(4958, "https://github.com/dotnet/roslyn/issues/4958")]
public void ArraysOfRank1_InAttributes()
{
var ilSource = @"
.class public auto ansi beforefieldinit Program
extends [mscorlib]System.Object
{
.method public hidebysig instance void
Test1() cil managed
{
.custom instance void TestAttribute::.ctor(class [mscorlib] System.Type) = {type(class 'System.Int32[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')}
// Code size 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method Program::Test1
.method public hidebysig instance void
Test2() cil managed
{
.custom instance void TestAttribute::.ctor(class [mscorlib] System.Type) = {type(class 'System.Int32[*], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')}
// Code size 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method Program::Test2
.method public hidebysig instance void
Test3() cil managed
{
.custom instance void TestAttribute::.ctor(class [mscorlib] System.Type) = {type(class 'System.Int32[*,*], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')}
// Code size 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method Program::Test3
.method public hidebysig instance void
Test4() cil managed
{
.custom instance void TestAttribute::.ctor(class [mscorlib] System.Type) = {type(class 'System.Int32[,*], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')}
// Code size 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method Program::Test4
} // end of class Program
.class public auto ansi beforefieldinit TestAttribute
extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname
instance void .ctor(class [mscorlib]System.Type val) cil managed
{
// Code size 9 (0x9)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Attribute::.ctor()
IL_0006: nop
IL_0007: nop
IL_0008: ret
} // end of method TestAttribute::.ctor
} // end of class TestAttribute
";
var source =
@"
using System;
using System.Linq;
class C
{
static void Main()
{
System.Console.WriteLine(GetTypeFromAttribute(""Test1""));
System.Console.WriteLine(GetTypeFromAttribute(""Test2""));
try
{
GetTypeFromAttribute(""Test3"");
}
catch
{
System.Console.WriteLine(""Throws"");
}
try
{
GetTypeFromAttribute(""Test4"");
}
catch
{
System.Console.WriteLine(""Throws"");
}
}
private static Type GetTypeFromAttribute(string target)
{
return (System.Type)typeof(Program).GetMember(target)[0].GetCustomAttributesData().ElementAt(0).ConstructorArguments[0].Value;
}
}";
var compilation = CreateCompilationWithCustomILSource(source, ilSource, new [] { SystemCoreRef }, options: TestOptions.ReleaseExe);
var p = compilation.GetTypeByMetadataName("Program");
var a1 = (ArrayTypeSymbol)p.GetMember<MethodSymbol>("Test1").GetAttributes().Single().ConstructorArguments.Single().Value;
Assert.Equal("System.Int32[]", a1.ToTestDisplayString());
Assert.Equal(1, a1.Rank);
Assert.True(a1.IsSZArray);
var a2 = (ArrayTypeSymbol)p.GetMember<MethodSymbol>("Test2").GetAttributes().Single().ConstructorArguments.Single().Value;
Assert.Equal("System.Int32[*]", a2.ToTestDisplayString());
Assert.Equal(1, a2.Rank);
Assert.False(a2.IsSZArray);
Assert.True(((TypeSymbol)p.GetMember<MethodSymbol>("Test3").GetAttributes().Single().ConstructorArguments.Single().Value).IsErrorType());
Assert.True(((TypeSymbol)p.GetMember<MethodSymbol>("Test4").GetAttributes().Single().ConstructorArguments.Single().Value).IsErrorType());
CompileAndVerify(compilation, expectedOutput:
@"System.Int32[]
System.Int32[*]
Throws
Throws");
}
}
}
......@@ -44,8 +44,10 @@ public void IsValidMetadataIdentifier()
private enum ArrayKind
{
None,
SzArray,
SingleDimensional,
MultiDimensional,
JaggedSzArray,
Jagged
};
......@@ -172,8 +174,13 @@ private static string[] GenerateTypeNamesToDecode(TypeNameConfig[] typeNameConfi
int[] expectedArrayRanks = null;
switch (typeNameConfig.ArrayKind)
{
case ArrayKind.SingleDimensional:
case ArrayKind.SzArray:
typeNameBuilder.Append("[]");
expectedArrayRanks = new[] { 0 };
break;
case ArrayKind.SingleDimensional:
typeNameBuilder.Append("[*]");
expectedArrayRanks = new[] { 1 };
break;
......@@ -182,8 +189,13 @@ private static string[] GenerateTypeNamesToDecode(TypeNameConfig[] typeNameConfi
expectedArrayRanks = new[] { 2 };
break;
case ArrayKind.Jagged:
case ArrayKind.JaggedSzArray:
typeNameBuilder.Append("[,][]");
expectedArrayRanks = new[] { 2, 0 };
break;
case ArrayKind.Jagged:
typeNameBuilder.Append("[,][*]");
expectedArrayRanks = new[] { 2, 1 };
break;
}
......@@ -281,6 +293,10 @@ public void TestDecodeTypeNameMatrix()
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 });
......@@ -293,7 +309,7 @@ public void TestDecodeArrayTypeName_Valid()
// Single-D Array
DecodeTypeNameAndVerify("W[]",
expectedTopLevelType: "W",
expectedArrayRanks: new[] { 1 });
expectedArrayRanks: new[] { 0 });
// Multi-D Array
DecodeTypeNameAndVerify("W[,]",
......@@ -303,13 +319,13 @@ public void TestDecodeArrayTypeName_Valid()
// Jagged Array
DecodeTypeNameAndVerify("W[][,]",
expectedTopLevelType: "W",
expectedArrayRanks: new[] { 1, 2 });
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[] { 1, 2 });
expectedArrayRanks: new[] { 0, 2 });
// Nested Generic Type Jagged Array with Array type argument
DecodeTypeNameAndVerify("Y`1+F[[System.Int32[], mscorlib]][,,][][,]",
......@@ -320,9 +336,9 @@ public void TestDecodeArrayTypeName_Valid()
nestedTypes: null,
typeArguments: null,
pointerCount: 0,
arrayRanks: new[] { 1 },
arrayRanks: new[] { 0 },
assemblyName: "mscorlib") },
expectedArrayRanks: new[] { 3, 1, 2 });
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][][,]",
......@@ -333,10 +349,10 @@ public void TestDecodeArrayTypeName_Valid()
nestedTypes: null,
typeArguments: null,
pointerCount: 0,
arrayRanks: new[] { 1 },
arrayRanks: new[] { 0 },
assemblyName: "mscorlib"),
new MetadataHelpers.AssemblyQualifiedTypeName("W", null, null, 0, null, null) },
expectedArrayRanks: new[] { 1, 2 });
expectedArrayRanks: new[] { 0, 2 });
}
[WorkItem(546277, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546277")]
......@@ -347,13 +363,13 @@ public void TestDecodeArrayTypeName_Invalid()
DecodeTypeNameAndVerify("X[]+Y",
expectedTopLevelType: "X+Y",
expectedNestedTypes: null,
expectedArrayRanks: new[] { 1 });
expectedArrayRanks: new[] { 0 });
// Error case, array shape before generic type arguments
DecodeTypeNameAndVerify("X[]`1[T]",
expectedTopLevelType: "X`1[T]",
expectedTypeArguments: null,
expectedArrayRanks: new[] { 1 });
expectedArrayRanks: new[] { 0 });
// Error case, invalid array shape
DecodeTypeNameAndVerify("X[T]",
......@@ -396,7 +412,7 @@ public void TestDecodePointerType_Invalid()
expectedTopLevelType: "W*",
expectedTypeArguments: null,
expectedPointerCount: 0,
expectedArrayRanks: new[] { 1 });
expectedArrayRanks: new[] { 0 });
}
[Fact, WorkItem(7396, "https://github.com/dotnet/roslyn/issues/7396")]
......
......@@ -33,6 +33,10 @@ internal struct AssemblyQualifiedTypeName
internal readonly string[] NestedTypes;
internal readonly AssemblyQualifiedTypeName[] TypeArguments;
internal readonly int PointerCount;
/// <summary>
/// Rank equal 0 is used to denote an SzArray, rank equal 1 denotes multi-dimensional array of rank 1.
/// </summary>
internal readonly int[] ArrayRanks;
internal readonly string AssemblyName;
......@@ -400,12 +404,16 @@ private string DecodeAssemblyName(bool isTypeArgumentWithAssemblyName)
return name;
}
/// <summary>
/// Rank equal 0 is used to denote an SzArray, rank equal 1 denotes multi-dimensional array of rank 1.
/// </summary>
private void DecodeArrayShape(StringBuilder typeNameBuilder, ref ArrayBuilder<int> arrayRanksBuilder)
{
Debug.Assert(Current == '[');
int start = _offset;
int rank = 1;
bool isMultiDimensionalIfRankOne = false;
Advance();
while (!EndOfInput)
......@@ -423,10 +431,27 @@ private void DecodeArrayShape(StringBuilder typeNameBuilder, ref ArrayBuilder<in
arrayRanksBuilder = ArrayBuilder<int>.GetInstance();
}
arrayRanksBuilder.Add(rank);
arrayRanksBuilder.Add(rank == 1 && !isMultiDimensionalIfRankOne ? 0 : rank);
Advance();
return;
case '*':
if (rank != 1)
{
goto default;
}
Advance();
if (Current != ']')
{
// Error case, process as regular characters
typeNameBuilder.Append(_input.Substring(start, _offset - start));
return;
}
isMultiDimensionalIfRankOne = true;
break;
default:
// Error case, process as regular characters
Advance();
......
......@@ -203,8 +203,8 @@ internal TypeSymbol GetTypeSymbol(MetadataHelpers.AssemblyQualifiedTypeName full
{
foreach (int rank in fullName.ArrayRanks)
{
Debug.Assert(rank > 0);
container = rank == 1 ?
Debug.Assert(rank >= 0);
container = rank == 0 ?
GetSZArrayTypeSymbol(container, default(ImmutableArray<ModifierInfo<TypeSymbol>>)) :
GetMDArrayTypeSymbol(rank, container, default(ImmutableArray<ModifierInfo<TypeSymbol>>), ImmutableArray<int>.Empty, default(ImmutableArray<int>));
}
......
......@@ -2594,5 +2594,128 @@ Overriden 16
]]>)
End Sub
<ClrOnlyFact(ClrOnlyReason.Ilasm)>
<WorkItem(4958, "https://github.com/dotnet/roslyn/issues/4958")>
Public Sub ArraysOfRank1_InAttributes()
Dim ilSource = "
.class public auto ansi beforefieldinit Program
extends [mscorlib]System.Object
{
.method public hidebysig instance void
Test1() cil managed
{
.custom instance void TestAttribute::.ctor(class [mscorlib] System.Type) = {type(class 'System.Int32[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')}
// Code size 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method Program::Test1
.method public hidebysig instance void
Test2() cil managed
{
.custom instance void TestAttribute::.ctor(class [mscorlib] System.Type) = {type(class 'System.Int32[*], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')}
// Code size 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method Program::Test2
.method public hidebysig instance void
Test3() cil managed
{
.custom instance void TestAttribute::.ctor(class [mscorlib] System.Type) = {type(class 'System.Int32[*,*], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')}
// Code size 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method Program::Test3
.method public hidebysig instance void
Test4() cil managed
{
.custom instance void TestAttribute::.ctor(class [mscorlib] System.Type) = {type(class 'System.Int32[,*], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')}
// Code size 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method Program::Test4
} // end of class Program
.class public auto ansi beforefieldinit TestAttribute
extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname
instance void .ctor(class [mscorlib]System.Type val) cil managed
{
// Code size 9 (0x9)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Attribute::.ctor()
IL_0006: nop
IL_0007: nop
IL_0008: ret
} // end of method TestAttribute::.ctor
} // end of class TestAttribute
"
Dim source =
<compilation>
<file name="a.vb">
imports System
imports System.Linq
class C
Shared Sub Main()
System.Console.WriteLine(GetTypeFromAttribute("Test1"))
System.Console.WriteLine(GetTypeFromAttribute("Test2"))
Try
GetTypeFromAttribute("Test3")
Catch
System.Console.WriteLine("Throws")
End Try
Try
GetTypeFromAttribute("Test4")
Catch
System.Console.WriteLine("Throws")
End Try
End Sub
Private Shared Function GetTypeFromAttribute(target As String) As Type
Return DirectCast(GetType(Program).GetMember(target)(0).GetCustomAttributesData().ElementAt(0).ConstructorArguments(0).Value, System.Type)
End Function
End Class
</file>
</compilation>
Dim compilation = CreateCompilationWithCustomILSource(source, ilSource, includeVbRuntime:=True,
additionalReferences:={SystemCoreRef}, options:=TestOptions.ReleaseExe)
Dim p = compilation.GetTypeByMetadataName("Program")
Dim a1 = DirectCast(p.GetMember(Of MethodSymbol)("Test1").GetAttributes().Single().ConstructorArguments.Single().Value, ArrayTypeSymbol)
Assert.Equal("System.Int32()", a1.ToTestDisplayString())
Assert.Equal(1, a1.Rank)
Assert.True(a1.IsSZArray)
Dim a2 = DirectCast(p.GetMember(Of MethodSymbol)("Test2").GetAttributes().Single().ConstructorArguments.Single().Value, ArrayTypeSymbol)
Assert.Equal("System.Int32(*)", a2.ToTestDisplayString())
Assert.Equal(1, a2.Rank)
Assert.False(a2.IsSZArray)
Assert.True(DirectCast(p.GetMember(Of MethodSymbol)("Test3").GetAttributes().Single().ConstructorArguments.Single().Value, TypeSymbol).IsErrorType())
Assert.True(DirectCast(p.GetMember(Of MethodSymbol)("Test4").GetAttributes().Single().ConstructorArguments.Single().Value, TypeSymbol).IsErrorType())
CompileAndVerify(compilation, expectedOutput:=
<![CDATA[
System.Int32[]
System.Int32[*]
Throws
Throws]]>)
End Sub
End Class
End Namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册