/// <summary> /// Decodes a type name. A type name is a string which is terminated by the end of the string or one of the /// delimiters '+', ',', '[', ']'. '+' separates nested classes. '[' and ']' /// enclosed generic type arguments. ',' separates types. /// </summary> public AssemblyQualifiedTypeName DecodeTypeName(bool isTypeArgument = false, bool isTypeArgumentWithAssemblyName = false) { Debug.Assert(!isTypeArgumentWithAssemblyName || isTypeArgument); string topLevelType = null; List <string> nestedTypesBuilder = null; AssemblyQualifiedTypeName[] typeArguments = null; int pointerCount = 0; List <int> arrayRanksBuilder = null; string assemblyName = null; bool decodingTopLevelType = true; bool isGenericTypeName = false; var pooledStrBuilder = PooledStringBuilder.GetInstance(); StringBuilder typeNameBuilder = pooledStrBuilder.Builder; while (!EndOfInput) { int i = _input.IndexOfAny(s_typeNameDelimiters, _offset); if (i >= 0) { char c = _input[i]; // Found name, which could be a generic name with arity. // Generic type parameter count, if any, are handled in DecodeGenericName. string decodedString = DecodeGenericName(i); Debug.Assert(decodedString != null); // Type name is generic if the decoded name of the top level type OR any of the outer types of a nested type had the '`' character. isGenericTypeName = isGenericTypeName || decodedString.IndexOf(GenericTypeNameManglingChar) >= 0; typeNameBuilder.Append(decodedString); switch (c) { case '*': if (arrayRanksBuilder != null) { // Error case, array shape must be specified at the end of the type name. // Process as a regular character and continue. typeNameBuilder.Append(c); } else { pointerCount++; } Advance(); break; case '+': if (arrayRanksBuilder != null || pointerCount > 0) { // Error case, array shape must be specified at the end of the type name. // Process as a regular character and continue. typeNameBuilder.Append(c); } else { // Type followed by nested type. Handle nested class separator and collect the nested types. HandleDecodedTypeName(typeNameBuilder.ToString(), decodingTopLevelType, ref topLevelType, ref nestedTypesBuilder); typeNameBuilder.Clear(); decodingTopLevelType = false; } Advance(); break; case '[': // Is type followed by generic type arguments? if (isGenericTypeName && typeArguments == null) { Advance(); if (arrayRanksBuilder != null || pointerCount > 0) { // Error case, array shape must be specified at the end of the type name. // Process as a regular character and continue. typeNameBuilder.Append(c); } else { // Decode type arguments. typeArguments = DecodeTypeArguments(); } } else { // Decode array shape. DecodeArrayShape(typeNameBuilder, ref arrayRanksBuilder); } break; case ']': if (isTypeArgument) { // End of type arguments. This occurs when the last type argument is a type in the // current assembly. goto ExitDecodeTypeName; } else { // Error case, process as a regular character and continue. typeNameBuilder.Append(c); Advance(); break; } case ',': // A comma may separate a type name from its assembly name or a type argument from // another type argument. // If processing non-type argument or a type argument with assembly name, // process the characters after the comma as an assembly name. if (!isTypeArgument || isTypeArgumentWithAssemblyName) { Advance(); if (!EndOfInput && Char.IsWhiteSpace(Current)) { Advance(); } assemblyName = DecodeAssemblyName(isTypeArgumentWithAssemblyName); } goto ExitDecodeTypeName; default: throw ExceptionUtilities.UnexpectedValue(c); } } else { typeNameBuilder.Append(DecodeGenericName(_input.Length)); goto ExitDecodeTypeName; } } ExitDecodeTypeName: HandleDecodedTypeName(typeNameBuilder.ToString(), decodingTopLevelType, ref topLevelType, ref nestedTypesBuilder); pooledStrBuilder.Free(); return(new AssemblyQualifiedTypeName( topLevelType, nestedTypesBuilder?.ToArray(), typeArguments, pointerCount, arrayRanksBuilder?.ToArray(), assemblyName)); }
internal static string GetSerializedTypeName(this ITypeReference typeReference, EmitContext context, ref bool isAssemblyQualified) { var pooled = PooledStringBuilder.GetInstance(); StringBuilder sb = pooled.Builder; IArrayTypeReference arrType = typeReference as IArrayTypeReference; if (arrType != null) { typeReference = arrType.GetElementType(context); bool isAssemQual = false; AppendSerializedTypeName(sb, typeReference, ref isAssemQual, context); if (arrType.IsSZArray) { sb.Append("[]"); } else { sb.Append('['); if (arrType.Rank == 1) { sb.Append('*'); } sb.Append(',', (int)arrType.Rank - 1); sb.Append(']'); } goto done; } IPointerTypeReference pointer = typeReference as IPointerTypeReference; if (pointer != null) { typeReference = pointer.GetTargetType(context); bool isAssemQual = false; AppendSerializedTypeName(sb, typeReference, ref isAssemQual, context); sb.Append('*'); goto done; } INamespaceTypeReference namespaceType = typeReference.AsNamespaceTypeReference; if (namespaceType != null) { var name = namespaceType.NamespaceName; if (name.Length != 0) { sb.Append(name); sb.Append('.'); } sb.Append(GetMangledAndEscapedName(namespaceType)); goto done; } if (typeReference.IsTypeSpecification()) { ITypeReference uninstantiatedTypeReference = typeReference.GetUninstantiatedGenericType(context); List <ITypeReference> consolidatedTypeArguments = new List <ITypeReference>(); typeReference.GetConsolidatedTypeArguments(consolidatedTypeArguments, context); bool uninstantiatedTypeIsAssemblyQualified = false; sb.Append(GetSerializedTypeName(uninstantiatedTypeReference, context, ref uninstantiatedTypeIsAssemblyQualified)); sb.Append('['); bool first = true; foreach (ITypeReference argument in consolidatedTypeArguments) { if (first) { first = false; } else { sb.Append(','); } bool isAssemQual = true; AppendSerializedTypeName(sb, argument, ref isAssemQual, context); } sb.Append(']'); goto done; } INestedTypeReference nestedType = typeReference.AsNestedTypeReference; if (nestedType != null) { bool nestedTypeIsAssemblyQualified = false; sb.Append(GetSerializedTypeName(nestedType.GetContainingType(context), context, ref nestedTypeIsAssemblyQualified)); sb.Append('+'); sb.Append(GetMangledAndEscapedName(nestedType)); goto done; } // TODO: error done: if (isAssemblyQualified) { AppendAssemblyQualifierIfNecessary(sb, UnwrapTypeReference(typeReference, context), out isAssemblyQualified, context); } return(pooled.ToStringAndFree()); }