/// <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"); } ITypeReference reference; if (reflectionTypeName[pos] == '`') { // type parameter reference pos++; if (pos == reflectionTypeName.Length) { throw new ReflectionNameParseException(pos, "Unexpected end"); } if (reflectionTypeName[pos] == '`') { // method type parameter reference pos++; int index = ReadTypeParameterCount(reflectionTypeName, ref pos); reference = TypeParameterReference.Create(SymbolKind.Method, index); } else { // class type parameter reference int index = ReadTypeParameterCount(reflectionTypeName, ref pos); reference = TypeParameterReference.Create(SymbolKind.TypeDefinition, index); } } else { // not a type parameter reference: read the actual type name string typeName = ReadTypeName(reflectionTypeName, ref pos, out int tpc); string assemblyName = local ? null : SkipAheadAndReadAssemblyName(reflectionTypeName, pos); reference = CreateGetClassTypeReference(assemblyName, typeName, tpc); } // read type suffixes while (pos < reflectionTypeName.Length) { switch (reflectionTypeName[pos++]) { case '+': int tpc; string typeName = ReadTypeName(reflectionTypeName, ref pos, out tpc); reference = new NestedTypeReference(reference, typeName, tpc); break; case '*': reference = new PointerTypeReference(reference); break; case '&': reference = new ByReferenceTypeReference(reference); break; case '[': // this might be an array or a generic type if (pos == reflectionTypeName.Length) { throw new ReflectionNameParseException(pos, "Unexpected end"); } if (reflectionTypeName[pos] != ']' && reflectionTypeName[pos] != ',') { // it's a generic type List <ITypeReference> typeArguments = new List <ITypeReference>(); 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++; 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] == ']') { pos++; reference = new ParameterizedTypeReference(reference, typeArguments); } else { throw new ReflectionNameParseException(pos, "Expected end of generic type"); } } else { // it's an array int dimensions = 1; while (pos < reflectionTypeName.Length && reflectionTypeName[pos] == ',') { dimensions++; pos++; } if (pos < reflectionTypeName.Length && reflectionTypeName[pos] == ']') { pos++; // end of array reference = new ArrayTypeReference(reference, dimensions); } else { throw new ReflectionNameParseException(pos, "Invalid array modifier"); } } break; 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] == ']' || reflectionTypeName[pos] == ',') { return(reference); // return from a nested generic } else { throw new ReflectionNameParseException(pos, "Unexpected character: '" + reflectionTypeName[pos] + "'"); } } } return(reference); }
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) { ArrayTypeReference o = other as ArrayTypeReference; return(o != null && elementType == o.elementType && dimensions == o.dimensions); }