static bool ParseTypeArguments(string id, ref int index, IGenericParameterProvider?typeParameterContext, List <string> typeArguments) { index++; // skip over { while (true) { var type = ParseTypeSymbol(id, ref index, typeParameterContext); if (type == null) { // if a type argument cannot be identified, argument list is no good return(false); } // add first one typeArguments.Add(type); if (PeekNextChar(id, index) == ',') { index++; continue; } break; } // note: this doesn't require closing } if (PeekNextChar(id, index) == '}') { index++; } return(true); }
static void ParseNamedTypeSymbol(string id, ref int index, IGenericParameterProvider?typeParameterContext, List <string> results) { Debug.Assert(results.Count == 0); var nameBuilder = new StringBuilder(); // loop for dotted names while (true) { var name = ParseName(id, ref index); if (String.IsNullOrEmpty(name)) { return; } nameBuilder.Append(name); List <string>?typeArguments = null; int arity = 0; // type arguments if (PeekNextChar(id, index) == '{') { typeArguments = new List <string> (); if (!ParseTypeArguments(id, ref index, typeParameterContext, typeArguments)) { continue; } arity = typeArguments.Count; } if (arity != 0) { Debug.Assert(typeArguments != null && typeArguments.Count != 0); nameBuilder.Append('{'); bool needsComma = false; foreach (var typeArg in typeArguments) { if (needsComma) { nameBuilder.Append(','); } nameBuilder.Append(typeArg); needsComma = true; } nameBuilder.Append('}'); } if (PeekNextChar(id, index) != '.') { break; } index++; nameBuilder.Append('.'); } results.Add(nameBuilder.ToString()); }
static string?ParseTypeSymbol(string id, ref int index, IGenericParameterProvider?typeParameterContext) { var results = new List <string> (); ParseTypeSymbol(id, ref index, typeParameterContext, results); if (results.Count == 1) { return(results[0]); } Debug.Assert(results.Count == 0); return(null); }
private TypeReference?ResolveImpl(ModuleDefinition module, IGenericParameterProvider?context, TypeReference typeRef) { if (typeRef.IsGenericInstance) { throw new WeavingException($"Type is already a generic instance: {typeRef.FullName}"); } if (typeRef.IsByReference || typeRef.IsPointer || typeRef.IsArray) { throw new WeavingException("Cannot make a generic instance of a ByRef, pointer or array type"); } var typeDef = typeRef.ResolveRequiredType(); if (!typeDef.HasGenericParameters) { throw new WeavingException($"Not a generic type definition: {typeRef.FullName}"); } if (typeDef.GenericParameters.Count != _genericArgs.Length) { throw new WeavingException($"Incorrect number of generic arguments supplied for type {typeRef.FullName} - expected {typeRef.GenericParameters.Count}, but got {_genericArgs.Length}"); } var genericType = new GenericInstanceType(typeRef); foreach (var argTypeBuilder in _genericArgs) { TypeReference?argTypeRef; if (context != null) { argTypeRef = argTypeBuilder.TryBuild(context); if (argTypeRef == null) { return(null); } } else { argTypeRef = argTypeBuilder.Build(); } genericType.GenericArguments.Add(argTypeRef); } return(module.ImportReference(genericType)); }
static void ParseTypeParameterSymbol(string id, ref int index, IGenericParameterProvider?typeParameterContext, List <string> results) { // skip the first ` Debug.Assert(PeekNextChar(id, index) == '`'); index++; Debug.Assert( typeParameterContext == null || (typeParameterContext is MethodDefinition && typeParameterContext.GenericParameterType == GenericParameterType.Method) || (typeParameterContext is TypeDefinition && typeParameterContext.GenericParameterType == GenericParameterType.Type) ); if (PeekNextChar(id, index) == '`') { // `` means this is a method type parameter index++; var methodTypeParameterIndex = ReadNextInteger(id, ref index); if (typeParameterContext is MethodDefinition methodContext) { var count = methodContext.HasGenericParameters ? methodContext.GenericParameters.Count : 0; if (count > 0 && methodTypeParameterIndex < count) { results.Add("``" + methodTypeParameterIndex); } } } else { // regular type parameter var typeParameterIndex = ReadNextInteger(id, ref index); var typeContext = typeParameterContext is MethodDefinition methodContext ? methodContext.DeclaringType : typeParameterContext as TypeDefinition; if (typeParameterIndex >= 0 || typeParameterIndex < typeContext?.GenericParameters.Count) { // No need to look at declaring types like Roslyn, because type parameters are redeclared. results.Add("`" + typeParameterIndex); } } }
static void ParseTypeSymbol(string id, ref int index, IGenericParameterProvider?typeParameterContext, List <string> results) { // Note: Roslyn has a special case that deviates from the language spec, which // allows context expressions embedded in a type reference => <context-definition>:<type-parameter> // We do not support this special format. Debug.Assert(results.Count == 0); if (PeekNextChar(id, index) == '`') { ParseTypeParameterSymbol(id, ref index, typeParameterContext, results); } else { ParseNamedTypeSymbol(id, ref index, typeParameterContext, results); } // apply any array or pointer constructions to results var startIndex = index; var endIndex = index; for (int i = 0; i < results.Count; i++) { index = startIndex; var typeReference = results[i]; while (true) { if (PeekNextChar(id, index) == '[') { var boundsStartIndex = index; var bounds = ParseArrayBounds(id, ref index); var boundsEndIndex = index; Debug.Assert(bounds > 0); // Instead of constructing a representation of the array bounds, we // use the original input to represent the bounds, and later match it // against the generated strings for types in signatures. // This ensures that we will only resolve members with supported array bounds. typeReference += id.Substring(boundsStartIndex, boundsEndIndex - boundsStartIndex); continue; } if (PeekNextChar(id, index) == '*') { index++; typeReference += '*'; continue; } break; } if (PeekNextChar(id, index) == '@') { index++; typeReference += '@'; } results[i] = typeReference; endIndex = index; } index = endIndex; }