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. 52
      ICSharpCode.Decompiler/TypeSystem/ReflectionHelper.cs

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

@ -17,8 +17,9 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections.Generic;
namespace aa namespace CustomAttributes
{ {
public static class CustomAttributes public static class CustomAttributes
{ {
@ -45,21 +46,47 @@ namespace aa
[My(null)] [My(null)]
MaxUInt64 = 18446744073709551615uL MaxUInt64 = 18446744073709551615uL
} }
[AttributeUsage(AttributeTargets.Class)] [AttributeUsage(AttributeTargets.Field)]
public class TypesAttribute : Attribute public class TypesAttribute : Attribute
{ {
public TypesAttribute(Type type) public TypesAttribute(Type type)
{ {
} }
} }
[Types(typeof(int))] private class SomeType<T>
private class Class1
{ {
} }
[Types(null)] private class SomeType<K, V>
private class Class2 {
}
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)] [My(EnumWithFlag.Item1 | EnumWithFlag.Item2)]
private static int field; private static int field;

52
ICSharpCode.Decompiler/TypeSystem/ReflectionHelper.cs

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

Loading…
Cancel
Save