public static void BuildNamedTypeDisplayName(this INamedTypeSymbol namedType, Context cx, ITrapBuilder tb) { if (namedType.IsTupleType) { tb.Append("("); tb.BuildList(",", namedType.TupleElements.Select(f => f.Type), (t, tb0) => t.BuildDisplayName(cx, tb0) ); tb.Append(")"); return; } if (namedType.IsAnonymousType) { namedType.BuildAnonymousName(cx, tb, (cx0, tb0, sub) => sub.BuildDisplayName(cx0, tb0), false); } tb.Append(namedType.Name); if (namedType.IsGenericType && namedType.TypeKind != TypeKind.Error && namedType.TypeArguments.Any()) { tb.Append("<"); tb.BuildList(",", namedType.TypeArguments, (p, tb0) => { if (IsReallyBound(namedType)) { p.BuildDisplayName(cx, tb0); } }); tb.Append(">"); } }
public void AppendTo(ITrapBuilder tb) { tb.Append("@\""); foreach (var fragment in TrapBuilder.Fragments) { tb.Append(fragment); } tb.Append("\""); }
/// <summary> /// Constructs an array suffix string for this array type symbol. /// </summary> /// <param name="tb">The trap builder used to store the result.</param> public static void BuildArraySuffix(this IArrayTypeSymbol array, ITrapBuilder tb) { tb.Append("["); for (int i = 0; i < array.Rank - 1; i++) { tb.Append(","); } tb.Append("]"); }
/// <summary> /// Constructs a unique string for this type symbol. /// /// The supplied action <paramref name="subTermAction"/> is applied to the /// syntactic sub terms of this type (if any). /// </summary> /// <param name="cx">The extraction context.</param> /// <param name="tb">The trap builder used to store the result.</param> /// <param name="subTermAction">The action to apply to syntactic sub terms of this type.</param> public static void BuildTypeId(this ITypeSymbol type, Context cx, ITrapBuilder tb, Action <Context, ITrapBuilder, ITypeSymbol> subTermAction) { if (type.SpecialType != SpecialType.None) { /* * Use the keyword ("int" etc) for the built-in types. * This makes the IDs shorter and means that all built-in types map to * the same entities (even when using multiple versions of mscorlib). */ tb.Append(type.ToDisplayString()); return; } using (cx.StackGuard) { switch (type.TypeKind) { case TypeKind.Array: var array = (IArrayTypeSymbol)type; subTermAction(cx, tb, array.ElementType); array.BuildArraySuffix(tb); return; case TypeKind.Class: case TypeKind.Interface: case TypeKind.Struct: case TypeKind.Enum: case TypeKind.Delegate: case TypeKind.Error: var named = (INamedTypeSymbol)type; named.BuildNamedTypeId(cx, tb, subTermAction); return; case TypeKind.Pointer: var ptr = (IPointerTypeSymbol)type; subTermAction(cx, tb, ptr.PointedAtType); tb.Append("*"); return; case TypeKind.TypeParameter: var tp = (ITypeParameterSymbol)type; tb.Append(tp.Name); return; case TypeKind.Dynamic: tb.Append("dynamic"); return; default: throw new InternalError(type, $"Unhandled type kind '{type.TypeKind}'"); } } }
public void EmitToTrapBuilder(ITrapBuilder tb) { label.AppendTo(tb); tb.Append("="); id.AppendTo(tb); tb.AppendLine(); }
/// <summary> /// Constructs a display name string for this type symbol. /// </summary> /// <param name="tb">The trap builder used to store the result.</param> public static void BuildDisplayName(this ITypeSymbol type, Context cx, ITrapBuilder tb) { using (cx.StackGuard) { switch (type.TypeKind) { case TypeKind.Array: var array = (IArrayTypeSymbol)type; var elementType = array.ElementType; if (elementType.MetadataName.IndexOf("`") >= 0) { tb.Append(elementType.Name); return; } elementType.BuildDisplayName(cx, tb); array.BuildArraySuffix(tb); return; case TypeKind.Class: case TypeKind.Interface: case TypeKind.Struct: case TypeKind.Enum: case TypeKind.Delegate: case TypeKind.Error: var named = (INamedTypeSymbol)type; named.BuildNamedTypeDisplayName(cx, tb); return; case TypeKind.Pointer: var ptr = (IPointerTypeSymbol)type; ptr.PointedAtType.BuildDisplayName(cx, tb); tb.Append("*"); return; case TypeKind.TypeParameter: tb.Append(type.Name); return; case TypeKind.Dynamic: tb.Append("dynamic"); return; default: throw new InternalError(type, $"Unhandled type kind '{type.TypeKind}'"); } } }
/// <summary> /// Constructs a unique string for this label. /// </summary> /// <param name="tb">The trap builder used to store the result.</param> public void AppendTo(ITrapBuilder tb) { if (!Valid) { throw new NullReferenceException("Attempt to use an invalid label"); } tb.Append("#").Append(Value); }
static void BuildAnonymousName(this ITypeSymbol type, Context cx, ITrapBuilder tb, Action <Context, ITrapBuilder, ITypeSymbol> subTermAction, bool includeParamName) { var buildParam = includeParamName ? (prop, tb0) => { tb0.Append(prop.Name).Append(" "); subTermAction(cx, tb0, prop.Type); } : (Action <IPropertySymbol, ITrapBuilder>)((prop, tb0) => subTermAction(cx, tb0, prop.Type)); int memberCount = type.GetMembers().OfType <IPropertySymbol>().Count(); int hackTypeNumber = memberCount == 1 ? 1 : 0; tb.Append("<>__AnonType"); tb.Append(hackTypeNumber); tb.Append("<"); tb.BuildList(",", type.GetMembers().OfType <IPropertySymbol>(), buildParam); tb.Append(">"); }
/// <summary> /// Adds an appropriate label ID to the trap builder <paramref name="tb"/> /// for the type <paramref name="type"/> belonging to the signature of method /// <paramref name="method"/>. /// /// For methods without type parameters this will always add the key of the /// corresponding type. /// /// For methods with type parameters, this will add the key of the /// corresponding type if the type does *not* contain one of the method /// type parameters, otherwise it will add a textual representation of /// the type. This distinction is required because type parameter IDs /// refer to their declaring methods. /// /// Example: /// /// <code> /// int Count<T>(IEnumerable<T> items) /// </code> /// /// The label definitions for <code>Count</code> (<code>#4</code>) and <code>T</code> /// (<code>#5</code>) will look like: /// /// <code> /// #1=<label for System.Int32> /// #2=<label for type containing Count> /// #3=<label for IEnumerable`1> /// #4=@"{#1} {#2}.Count`2(#3<T>);method" /// #5=@"{#4}T;typeparameter" /// </code> /// /// Note how <code>int</code> is referenced in the label definition <code>#3</code> for /// <code>Count</code>, while <code>T[]</code> is represented textually in order /// to make the reference to <code>#3</code> in the label definition <code>#4</code> for /// <code>T</code> valid. /// </summary> protected static void AddSignatureTypeToId(Context cx, ITrapBuilder tb, IMethodSymbol method, ITypeSymbol type) { if (type.ContainsTypeParameters(cx, method)) { type.BuildTypeId(cx, tb, (cx0, tb0, type0) => AddSignatureTypeToId(cx, tb0, method, type0)); } else { tb.Append(Type.Create(cx, type)); } }
static void BuildNamespace(this INamespaceSymbol ns, Context cx, ITrapBuilder tb) { // Only include the assembly information in each type ID // for normal extractions. This is because standalone extractions // lack assembly information or may be ambiguous. bool prependAssemblyToTypeId = !cx.Extractor.Standalone && ns.ContainingAssembly != null; if (prependAssemblyToTypeId) { // Note that we exclude the revision number as this has // been observed to be unstable. var assembly = ns.ContainingAssembly.Identity; tb.Append(assembly.Name).Append("_"). Append(assembly.Version.Major).Append("."). Append(assembly.Version.Minor).Append("."). Append(assembly.Version.Build).Append("::"); } tb.Append(Namespace.Create(cx, ns)).Append("."); }
static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, ITrapBuilder tb, Action <Context, ITrapBuilder, ITypeSymbol> subTermAction) { if (named.IsTupleType) { tb.Append("("); tb.BuildList(",", named.TupleElements, (f, tb0) => { tb.Append(f.Name).Append(":"); subTermAction(cx, tb0, f.Type); } ); tb.Append(")"); return; } if (named.ContainingType != null) { subTermAction(cx, tb, named.ContainingType); tb.Append("."); } else if (named.ContainingNamespace != null) { named.ContainingNamespace.BuildNamespace(cx, tb); } if (named.IsAnonymousType) { named.BuildAnonymousName(cx, tb, subTermAction, true); } else if (named.TypeParameters.IsEmpty) { tb.Append(named.Name); } else if (IsReallyUnbound(named)) { tb.Append(named.Name).Append("`").Append(named.TypeParameters.Length); } else { subTermAction(cx, tb, named.ConstructedFrom); tb.Append("<"); // Encode the nullability of the type arguments in the label. // Type arguments with different nullability can result in // a constructed type with different nullability of its members and methods, // so we need to create a distinct database entity for it. tb.BuildList(",", named.GetAnnotatedTypeArguments(), (ta, tb0) => { subTermAction(cx, tb0, ta.Symbol); tb.Append((int)ta.Nullability); }); tb.Append(">"); } }
static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, ITrapBuilder tb, Action <Context, ITrapBuilder, ITypeSymbol> subTermAction) { if (named.IsTupleType) { tb.Append("("); tb.BuildList(",", named.TupleElements, (f, tb0) => { tb.Append(f.Name).Append(":"); subTermAction(cx, tb0, f.Type); } ); tb.Append(")"); return; } if (named.ContainingType != null) { subTermAction(cx, tb, named.ContainingType); tb.Append("."); } else if (named.ContainingNamespace != null) { named.ContainingNamespace.BuildNamespace(cx, tb); } if (named.IsAnonymousType) { named.BuildAnonymousName(cx, tb, subTermAction, true); } else if (named.TypeParameters.IsEmpty) { tb.Append(named.Name); } else if (IsReallyUnbound(named)) { tb.Append(named.Name).Append("`").Append(named.TypeParameters.Length); } else { subTermAction(cx, tb, named.ConstructedFrom); tb.Append("<"); tb.BuildList(",", named.TypeArguments, (ta, tb0) => subTermAction(cx, tb0, ta)); tb.Append(">"); } }
/// <summary> /// Builds a trap builder using a separator and an action for each item in the list. /// </summary> /// <typeparam name="T">The type of the items.</typeparam> /// <param name="tb">The trap builder to append to.</param> /// <param name="separator">The separator string (e.g. ",")</param> /// <param name="items">The list of items.</param> /// <param name="action">The action on each item.</param> /// <returns>The original trap builder (fluent interface).</returns> public static ITrapBuilder BuildList <T>(this ITrapBuilder tb, string separator, IEnumerable <T> items, Action <T, ITrapBuilder> action) { bool first = true; foreach (var item in items) { if (first) { first = false; } else { tb.Append(separator); } action(item, tb); } return(tb); }
/// <summary> /// Factored out to share logic between `Method` and `UserOperator`. /// </summary> protected static void BuildMethodId(Method m, ITrapBuilder tb) { tb.Append(m.ContainingType); AddExplicitInterfaceQualifierToId(m.Context, tb, m.symbol.ExplicitInterfaceImplementations); tb.Append(".").Append(m.symbol.Name); if (m.symbol.IsGenericMethod) { if (Equals(m.symbol, m.symbol.OriginalDefinition)) { tb.Append("`").Append(m.symbol.TypeParameters.Length); } else { tb.Append("<"); // Encode the nullability of the type arguments in the label. // Type arguments with different nullability can result in // a constructed method with different nullability of its parameters and return type, // so we need to create a distinct database entity for it. tb.BuildList(",", m.symbol.GetAnnotatedTypeArguments(), (ta, tb0) => { AddSignatureTypeToId(m.Context, tb0, m.symbol, ta.Symbol); tb.Append((int)ta.Nullability); }); tb.Append(">"); } } AddParametersToId(m.Context, tb, m.symbol); switch (m.symbol.MethodKind) { case MethodKind.PropertyGet: tb.Append(";getter"); break; case MethodKind.PropertySet: tb.Append(";setter"); break; case MethodKind.EventAdd: tb.Append(";adder"); break; case MethodKind.EventRaise: tb.Append(";raiser"); break; case MethodKind.EventRemove: tb.Append(";remover"); break; default: tb.Append(";method"); break; } }
public void AppendTo(ITrapBuilder tb) { tb.Append("*"); }
private static void WriteString(ITrapBuilder tb, string s) => tb.Append(EncodeString(s));
public void EmitToTrapBuilder(ITrapBuilder tb) { tb.Append(".push "); Key.AppendTo(tb); tb.AppendLine(); }
public void AppendTo(ITrapBuilder tb) { tb.Append("@\""); BuildParts(tb); tb.Append("\""); }
/// <summary> /// Factored out to share logic between `Method` and `UserOperator`. /// </summary> protected static void BuildMethodId(Method m, ITrapBuilder tb) { tb.Append(m.ContainingType); AddExplicitInterfaceQualifierToId(m.Context, tb, m.symbol.ExplicitInterfaceImplementations); tb.Append(".").Append(m.symbol.Name); if (m.symbol.IsGenericMethod) { if (Equals(m.symbol, m.symbol.OriginalDefinition)) { tb.Append("`").Append(m.symbol.TypeParameters.Length); } else { tb.Append("<"); tb.BuildList(",", m.symbol.TypeArguments, (ta, tb0) => AddSignatureTypeToId(m.Context, tb0, m.symbol, ta)); tb.Append(">"); } } AddParametersToId(m.Context, tb, m.symbol); switch (m.symbol.MethodKind) { case MethodKind.PropertyGet: tb.Append(";getter"); break; case MethodKind.PropertySet: tb.Append(";setter"); break; case MethodKind.EventAdd: tb.Append(";adder"); break; case MethodKind.EventRaise: tb.Append(";raiser"); break; case MethodKind.EventRemove: tb.Append(";remover"); break; default: tb.Append(";method"); break; } }
public void EmitToTrapBuilder(ITrapBuilder tb) { tb.Append(Content); }
protected static void AddParametersToId(Context cx, ITrapBuilder tb, IMethodSymbol method) { tb.Append("("); tb.AppendList(",", AddParameterPartsToId(cx, tb, method)); tb.Append(")"); }
public override void BuildParts(ITrapBuilder tb) { tb.Append(value); }
/// <summary> /// Constructs a unique string for this tuple. /// </summary> /// <param name="tb">The trap builder used to store the result.</param> public void EmitToTrapBuilder(ITrapBuilder tb) { tb.Append(Name).Append("("); int column = 0; foreach (var a in Args) { if (column > 0) { tb.Append(", "); } switch (a) { case Label l: l.AppendTo(tb); break; case IEntity e: e.Label.AppendTo(tb); break; case string s: tb.Append("\""); if (NeedsTruncation(s)) { // Slow path int remaining = maxStringBytes; WriteTruncatedString(tb, s, ref remaining); } else { // Fast path WriteString(tb, s); } tb.Append("\""); break; case System.Enum _: tb.Append((int)a); break; case int i: tb.Append(i); break; case float f: tb.Append(f.ToString("0.#####e0")); // Trap importer won't accept ints break; case string[] array: tb.Append("\""); if (NeedsTruncation(array)) { // Slow path int remaining = maxStringBytes; foreach (var element in array) { WriteTruncatedString(tb, element, ref remaining); } } else { // Fast path foreach (var element in array) { WriteString(tb, element); } } tb.Append("\""); break; case null: throw new InternalError($"Attempt to write a null argument tuple {Name} at column {column}"); default: throw new InternalError($"Attempt to write an invalid argument type {a.GetType()} in tuple {Name} at column {column}"); } ++column; } tb.Append(")"); tb.AppendLine(); }
public void EmitToTrapBuilder(ITrapBuilder tb) { tb.Append(".pop"); tb.AppendLine(); }
/// <summary> /// Constructs a unique string for this tuple. /// </summary> /// <param name="tb">The trap builder used to store the result.</param> public void EmitToTrapBuilder(ITrapBuilder tb) { tb.Append(Name).Append("("); int column = 0; foreach (var a in Args) { if (column > 0) { tb.Append(", "); } if (a is Label) { ((Label)a).AppendTo(tb); } else if (a is IEntity) { ((IEntity)a).Label.AppendTo(tb); } else if (a is string) { tb.Append("\""); tb.Append(((string)a).Replace("\"", "\"\"")); tb.Append("\""); } else if (a is System.Enum) { tb.Append((int)a); } else if (a is int) { tb.Append((int)a); } else if (a == null) { throw new InternalError("Attempt to write a null argument tuple {0} at column {1}", Name, column); } else { var array = a as string[]; if (array != null) { tb.Append("\""); foreach (var element in array) { tb.Append(element.Replace("\"", "\"\"")); } tb.Append("\""); } else { throw new InternalError("Attempt to write an invalid argument type {0} in tuple {1} at column {2}", a.GetType(), Name, column); } } ++column; } tb.Append(")"); tb.AppendLine(); }