private static bool AppendQualifiedSymbolName(StringBuilder builder, ISymbol symbol, TypeSyntax type) { switch (symbol.Kind) { case SymbolKind.ArrayType: var arraySymbol = (IArrayTypeSymbol)symbol; AppendQualifiedSymbolName(builder, arraySymbol.ElementType, GetElementSyntax(type)); builder .Append("[") .Append(',', arraySymbol.Rank - 1) .Append("]"); AppendNullableSuffixIfNeeded(builder, type); return(true); case SymbolKind.Namespace: var namespaceSymbol = (INamespaceSymbol)symbol; if (namespaceSymbol.IsGlobalNamespace) { return(false); } builder.Append(namespaceSymbol.ToDisplayString()); return(true); case SymbolKind.NamedType: var namedTypeSymbol = (INamedTypeSymbol)symbol; if (SpecialTypeHelper.TryGetPredefinedType(namedTypeSymbol.SpecialType, out var specialTypeSyntax) && (type?.IsKind(SyntaxKind.PredefinedType) == true || (type is NullableTypeSyntax nullable && nullable.ElementType.IsKind(SyntaxKind.PredefinedType)))) { // This handles these cases: int, int?, object, object? // But not these cases: System.Int32, System.Int32?, System.Object, System.Object? builder.Append(specialTypeSyntax.ToFullString()); AppendNullableSuffixIfNeeded(builder, type); return(true); } else if (namedTypeSymbol.IsTupleType()) { return(AppendTupleType(builder, namedTypeSymbol, type)); } else if (namedTypeSymbol.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T && type?.IsKind(SyntaxKind.NullableType) == true) { // This handles the case '(int, int)?' but not 'System.Nullable<(int, int)>' AppendQualifiedSymbolName(builder, namedTypeSymbol.TypeArguments[0], GetElementSyntax(type)); builder.Append("?"); return(true); } else { return(AppendNamedType(builder, namedTypeSymbol, type)); }
/// <summary> /// Generates the qualified name for the given symbol. /// </summary> /// <param name="symbol">The symbol to use.</param> /// <returns>The generated qualified name.</returns> public static string ToQualifiedString(this ISymbol symbol) { var builder = ObjectPools.StringBuilderPool.Allocate(); if (symbol is INamedTypeSymbol namedTypeSymbol) { if (SpecialTypeHelper.TryGetPredefinedType(namedTypeSymbol.SpecialType, out PredefinedTypeSyntax specialTypeSyntax)) { return(specialTypeSyntax.ToFullString()); } if (namedTypeSymbol.IsTupleType()) { namedTypeSymbol = namedTypeSymbol.TupleUnderlyingType(); } AppendQualifiedSymbolName(builder, namedTypeSymbol); if (namedTypeSymbol.IsGenericType) { builder.Append(GenericTypeParametersOpen); foreach (var typeArgument in namedTypeSymbol.TypeArguments) { if (typeArgument is INamedTypeSymbol namedTypeArgument && typeArgument.IsTupleType()) { builder.Append(namedTypeArgument.TupleUnderlyingType().ToQualifiedString()); } else { builder.Append(typeArgument.ToQualifiedString()); } builder.Append(GenericSeparator); } builder.Remove(builder.Length - GenericSeparator.Length, GenericSeparator.Length); builder.Append(GenericTypeParametersClose); }
private static bool AppendQualifiedSymbolName(StringBuilder builder, ISymbol symbol, TypeSyntax type) { switch (symbol.Kind) { case SymbolKind.ArrayType: var arraySymbol = (IArrayTypeSymbol)symbol; AppendQualifiedSymbolName(builder, arraySymbol.ElementType, (type as ArrayTypeSyntax)?.ElementType); builder .Append("[") .Append(',', arraySymbol.Rank - 1) .Append("]"); return(true); case SymbolKind.Namespace: var namespaceSymbol = (INamespaceSymbol)symbol; if (namespaceSymbol.IsGlobalNamespace) { return(false); } builder.Append(namespaceSymbol.ToDisplayString()); return(true); case SymbolKind.NamedType: var namedTypeSymbol = (INamedTypeSymbol)symbol; if (SpecialTypeHelper.TryGetPredefinedType(namedTypeSymbol.SpecialType, out var specialTypeSyntax)) { builder.Append(specialTypeSyntax.ToFullString()); return(true); } else if (namedTypeSymbol.IsTupleType()) { if (TupleTypeSyntaxWrapper.IsInstance(type)) { var tupleType = (TupleTypeSyntaxWrapper)type; builder.Append(TupleTypeOpen); var elements = namedTypeSymbol.TupleElements(); for (int i = 0; i < elements.Length; i++) { var field = elements[i]; var fieldType = tupleType.Elements.Count > i ? tupleType.Elements[i] : default; if (i > 0) { builder.Append(TupleElementSeparator); } AppendQualifiedSymbolName(builder, field.Type, fieldType.Type); if (field != field.CorrespondingTupleField()) { builder.Append(" ").Append(field.Name); } } builder.Append(TupleTypeClose); return(true); } else { return(AppendQualifiedSymbolName(builder, namedTypeSymbol.TupleUnderlyingType(), type)); } } else if (namedTypeSymbol.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T) { AppendQualifiedSymbolName(builder, namedTypeSymbol.TypeArguments[0], (type as NullableTypeSyntax)?.ElementType); builder.Append("?"); return(true); } else { if (AppendQualifiedSymbolName(builder, symbol.ContainingSymbol, (type as QualifiedNameSyntax)?.Left)) { builder.Append("."); } builder.Append(symbol.Name); if (namedTypeSymbol.IsGenericType && !namedTypeSymbol.TypeArguments.IsEmpty) { builder.Append(GenericTypeParametersOpen); var arguments = namedTypeSymbol.TypeArguments; var argumentTypes = type is QualifiedNameSyntax qualifiedName ? (qualifiedName.Right as GenericNameSyntax)?.TypeArgumentList : (type as GenericNameSyntax)?.TypeArgumentList; for (int i = 0; i < arguments.Length; i++) { var argument = arguments[i]; var argumentType = argumentTypes != null && argumentTypes.Arguments.Count > i ? argumentTypes.Arguments[i] : null; if (i > 0) { builder.Append(GenericSeparator); } if (!argumentType.IsKind(SyntaxKind.OmittedTypeArgument)) { AppendQualifiedSymbolName(builder, argument, argumentType); } } builder.Append(GenericTypeParametersClose); } return(true); } default: if (symbol != null) { builder.Append(symbol.Name); return(true); } return(false); } }