Browse Source

Fix #858: parse local type arguments in reflection names.

pull/870/head
Daniel Grunwald 8 years ago
parent
commit
7e38d9c5aa
  1. 39
      ICSharpCode.Decompiler.Tests/CustomAttributes/S_CustomAttributes.cs
  2. 56
      ICSharpCode.Decompiler/TypeSystem/ReflectionHelper.cs

39
ICSharpCode.Decompiler.Tests/CustomAttributes/S_CustomAttributes.cs

@ -17,8 +17,9 @@ @@ -17,8 +17,9 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
namespace aa
namespace CustomAttributes
{
public static class CustomAttributes
{
@ -45,21 +46,47 @@ namespace aa @@ -45,21 +46,47 @@ namespace aa
[My(null)]
MaxUInt64 = 18446744073709551615uL
}
[AttributeUsage(AttributeTargets.Class)]
[AttributeUsage(AttributeTargets.Field)]
public class TypesAttribute : Attribute
{
public TypesAttribute(Type type)
{
}
}
[Types(typeof(int))]
private class Class1
private class SomeType<T>
{
}
[Types(null)]
private class Class2
private class SomeType<K, V>
{
}
private struct DataType
{
private int i;
}
[Types(typeof(int))]
private static int typeattr_int;
[Types(null)]
private static int typeattr_null;
[Types(typeof(List<int>))]
private static int typeattr_list_of_int;
[Types(typeof(List<>))]
private static int typeattr_list_unbound;
[Types(typeof(SomeType<DataType>))]
private static int typeattr_sometype_of_datatype;
[Types(typeof(SomeType<DataType, DataType>))]
private static int typeattr_sometype_of_datatype2;
[Types(typeof(SomeType<DataType, int>))]
private static int typeattr_sometype_of_datatype_and_int;
[Types(typeof(SomeType<DataType[], int>))]
private static int typeattr_sometype_of_datatype_array_and_int;
[Types(typeof(SomeType<SomeType<DataType>, int>))]
private static int typeattr_sometype_of_nested_sometype;
[Types(typeof(SomeType<int, DataType>))]
private static int typeattr_sometype_of_int_and_datatype;
[Types(typeof(int[]))]
private static int typeattr_array_of_int;
[Types(typeof(int[,,,][,]))]
private static int typeattr_multidim_array_of_int;
[My(EnumWithFlag.Item1 | EnumWithFlag.Item2)]
private static int field;

56
ICSharpCode.Decompiler/TypeSystem/ReflectionHelper.cs

@ -234,7 +234,11 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -234,7 +234,11 @@ namespace ICSharpCode.Decompiler.TypeSystem
}
}
static ITypeReference ParseReflectionName(string reflectionTypeName, ref int pos)
/// <summary>
/// Parses the reflection name starting at pos.
/// If local is true, only parses local type names, not assembly qualified type names.
/// </summary>
static ITypeReference ParseReflectionName(string reflectionTypeName, ref int pos, bool local=false)
{
if (pos == reflectionTypeName.Length)
throw new ReflectionNameParseException(pos, "Unexpected end");
@ -256,9 +260,8 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -256,9 +260,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
}
} else {
// not a type parameter reference: read the actual type name
int tpc;
string typeName = ReadTypeName(reflectionTypeName, ref pos, out tpc);
string assemblyName = SkipAheadAndReadAssemblyName(reflectionTypeName, pos);
string typeName = ReadTypeName(reflectionTypeName, ref pos, out int tpc);
string assemblyName = local ? null : SkipAheadAndReadAssemblyName(reflectionTypeName, pos);
reference = CreateGetClassTypeReference(assemblyName, typeName, tpc);
}
// read type suffixes
@ -279,29 +282,30 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -279,29 +282,30 @@ namespace ICSharpCode.Decompiler.TypeSystem
// this might be an array or a generic type
if (pos == reflectionTypeName.Length)
throw new ReflectionNameParseException(pos, "Unexpected end");
if (reflectionTypeName[pos] == '[') {
if (reflectionTypeName[pos] != ']' && reflectionTypeName[pos] != ',') {
// it's a generic type
List<ITypeReference> typeArguments = new List<ITypeReference>();
pos++;
typeArguments.Add(ParseReflectionName(reflectionTypeName, ref pos));
if (pos < reflectionTypeName.Length && reflectionTypeName[pos] == ']')
pos++;
else
throw new ReflectionNameParseException(pos, "Expected end of type argument");
while (pos < reflectionTypeName.Length && reflectionTypeName[pos] == ',') {
pos++;
if (pos < reflectionTypeName.Length && reflectionTypeName[pos] == '[')
pos++;
else
throw new ReflectionNameParseException(pos, "Expected another type argument");
typeArguments.Add(ParseReflectionName(reflectionTypeName, ref pos));
if (pos < reflectionTypeName.Length && reflectionTypeName[pos] == ']')
bool first = true;
while (first || pos < reflectionTypeName.Length && reflectionTypeName[pos] == ',') {
if (first) {
first = false;
} else {
pos++; // skip ','
}
if (pos < reflectionTypeName.Length && reflectionTypeName[pos] == '[') {
// non-local type names are enclosed in another set of []
pos++;
else
throw new ReflectionNameParseException(pos, "Expected end of type argument");
typeArguments.Add(ParseReflectionName(reflectionTypeName, ref pos));
if (pos < reflectionTypeName.Length && reflectionTypeName[pos] == ']')
pos++;
else
throw new ReflectionNameParseException(pos, "Expected end of type argument");
} else {
// local type names occur directly in the outer []
typeArguments.Add(ParseReflectionName(reflectionTypeName, ref pos, local: true));
}
}
if (pos < reflectionTypeName.Length && reflectionTypeName[pos] == ']') {
@ -325,14 +329,14 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -325,14 +329,14 @@ namespace ICSharpCode.Decompiler.TypeSystem
}
}
break;
case ',':
case ',' when !local:
// assembly qualified name, ignore everything up to the end/next ']'
while (pos < reflectionTypeName.Length && reflectionTypeName[pos] != ']')
pos++;
break;
default:
pos--; // reset pos to the character we couldn't read
if (reflectionTypeName[pos] == ']')
if (reflectionTypeName[pos] == ']' || reflectionTypeName[pos] == ',')
return reference; // return from a nested generic
else
throw new ReflectionNameParseException(pos, "Unexpected character: '" + reflectionTypeName[pos] + "'");

Loading…
Cancel
Save