public static ImmutableArray <SymbolDisplayPart> GetAttributesParts( ISymbol symbol, SymbolDisplayFormat format, SymbolDisplayAdditionalOptions additionalOptions, Func <ISymbol, AttributeData, bool> shouldDisplayAttribute, bool includeTrailingNewLine = false, bool?formatAttributes = null) { IEnumerable <AttributeData> attributes = GetAttributes(symbol, shouldDisplayAttribute); if (!attributes.Any()) { return(ImmutableArray <SymbolDisplayPart> .Empty); } ImmutableArray <SymbolDisplayPart> .Builder parts = ImmutableArray.CreateBuilder <SymbolDisplayPart>(); AddAttributes( parts: parts, attributes: attributes, format: format, additionalOptions: additionalOptions, includeTrailingNewLine: includeTrailingNewLine, formatAttributes: formatAttributes); return(parts.ToImmutableArray()); }
private static void AddAccessorAttributes( ImmutableArray <SymbolDisplayPart> .Builder parts, IMethodSymbol methodSymbol, SymbolDisplayFormat format, SymbolDisplayAdditionalOptions additionalOptions, Func <ISymbol, AttributeData, bool> shouldDisplayAttribute) { ImmutableArray <SymbolDisplayPart> attributeParts = GetAttributesParts( methodSymbol, format: format, additionalOptions: additionalOptions, shouldDisplayAttribute: shouldDisplayAttribute, formatAttributes: false); if (attributeParts.Any()) { string keyword = GetKeyword(); SymbolDisplayPart part = parts.FirstOrDefault(f => f.IsKeyword(keyword)); Debug.Assert(part.Kind == SymbolDisplayPartKind.Keyword); if (part.Kind == SymbolDisplayPartKind.Keyword) { int index = parts.IndexOf(part); parts.Insert(index, SymbolDisplayPartFactory.Space()); parts.InsertRange(index, attributeParts); } } string GetKeyword() { switch (methodSymbol.MethodKind) { case MethodKind.EventAdd: return("add"); case MethodKind.EventRemove: return("remove"); case MethodKind.PropertyGet: return("get"); case MethodKind.PropertySet: return("set"); default: throw new InvalidOperationException(); } } }
private static void AddEventAccessorAttributes( ImmutableArray <SymbolDisplayPart> .Builder parts, IEnumerable <AttributeData> addAttributes, IEnumerable <AttributeData> removeAttributes, SymbolDisplayFormat format, SymbolDisplayAdditionalOptions additionalOptions) { parts.AddSpace(); parts.AddPunctuation("{"); parts.AddSpace(); AddAccessorAttributes(addAttributes); parts.AddKeyword("add"); parts.AddPunctuation(";"); parts.AddSpace(); AddAccessorAttributes(removeAttributes); parts.AddKeyword("remove"); parts.AddPunctuation(";"); parts.AddSpace(); parts.AddPunctuation("}"); void AddAccessorAttributes(IEnumerable <AttributeData> attributes) { AddAttributes( parts: parts, attributes: attributes, format: format, additionalOptions: additionalOptions, includeTrailingNewLine: false, formatAttributes: false); parts.AddSpace(); } }
private static void AddParameterAttributes( ImmutableArray <SymbolDisplayPart> .Builder parts, ISymbol symbol, ImmutableArray <IParameterSymbol> parameters, SymbolDisplayFormat format, SymbolDisplayAdditionalOptions additionalOptions, Func <ISymbol, AttributeData, bool> shouldDisplayAttribute) { int i = FindParameterListStart(symbol, parts); if (i == -1) { return; } i++; int parameterIndex = 0; AddParameterAttributes(); int parenthesesDepth = 1; int bracesDepth = 0; int bracketsDepth = 0; int angleBracketsDepth = 0; while (i < parts.Count) { SymbolDisplayPart part = parts[i]; if (part.Kind == SymbolDisplayPartKind.Punctuation) { switch (part.ToString()) { case ",": { if (((angleBracketsDepth == 0 && parenthesesDepth == 1 && bracesDepth == 0 && bracketsDepth == 0) || (angleBracketsDepth == 0 && parenthesesDepth == 0 && bracesDepth == 0 && bracketsDepth == 1)) && i < parts.Count - 1) { SymbolDisplayPart nextPart = parts[i + 1]; if (nextPart.Kind == SymbolDisplayPartKind.Space) { i += 2; parameterIndex++; AddParameterAttributes(); continue; } } break; } case "(": { parenthesesDepth++; break; } case ")": { Debug.Assert(parenthesesDepth >= 0); parenthesesDepth--; if (parenthesesDepth == 0 && symbol.IsKind(SymbolKind.Method, SymbolKind.NamedType)) { return; } break; } case "[": { bracketsDepth++; break; } case "]": { Debug.Assert(bracketsDepth >= 0); bracketsDepth--; if (bracketsDepth == 0 && symbol.Kind == SymbolKind.Property) { return; } break; } case "{": { bracesDepth++; break; } case "}": { Debug.Assert(bracesDepth >= 0); bracesDepth--; break; } case "<": { angleBracketsDepth++; break; } case ">": { Debug.Assert(angleBracketsDepth >= 0); angleBracketsDepth--; break; } } } i++; } void AddParameterAttributes() { IParameterSymbol parameter = parameters[parameterIndex]; ImmutableArray <SymbolDisplayPart> attributeParts = GetAttributesParts( parameter, format, additionalOptions, shouldDisplayAttribute: shouldDisplayAttribute); if (attributeParts.Any()) { parts.Insert(i, SymbolDisplayPartFactory.Space()); parts.InsertRange(i, attributeParts); i += attributeParts.Length + 1; } } }
private static void AddAttribute( ImmutableArray <SymbolDisplayPart> .Builder parts, AttributeData attribute, SymbolDisplayFormat format, SymbolDisplayAdditionalOptions additionalOptions) { parts.AddDisplayParts(attribute.AttributeClass, format, additionalOptions, removeAttributeSuffix: true); if (additionalOptions.HasOption(SymbolDisplayAdditionalOptions.IncludeAttributeArguments)) { AddAttributeArguments(); } void AddAttributeArguments() { bool hasConstructorArgument = false; bool hasNamedArgument = false; AppendConstructorArguments(); AppendNamedArguments(); if (hasConstructorArgument || hasNamedArgument) { parts.AddPunctuation(")"); } void AppendConstructorArguments() { ImmutableArray <TypedConstant> .Enumerator en = attribute.ConstructorArguments.GetEnumerator(); if (en.MoveNext()) { hasConstructorArgument = true; parts.AddPunctuation("("); while (true) { AddConstantValue(en.Current); if (en.MoveNext()) { parts.AddPunctuation(","); parts.AddSpace(); } else { break; } } } } void AppendNamedArguments() { ImmutableArray <KeyValuePair <string, TypedConstant> > .Enumerator en = attribute.NamedArguments.GetEnumerator(); if (en.MoveNext()) { hasNamedArgument = true; if (hasConstructorArgument) { parts.AddPunctuation(","); parts.AddSpace(); } else { parts.AddPunctuation("("); } while (true) { parts.Add(new SymbolDisplayPart(SymbolDisplayPartKind.PropertyName, null, en.Current.Key)); parts.AddSpace(); parts.AddPunctuation("="); parts.AddSpace(); AddConstantValue(en.Current.Value); if (en.MoveNext()) { parts.AddPunctuation(","); parts.AddSpace(); } else { break; } } } } } void AddConstantValue(TypedConstant typedConstant) { switch (typedConstant.Kind) { case TypedConstantKind.Primitive: { parts.Add(new SymbolDisplayPart( GetSymbolDisplayPart(typedConstant.Type.SpecialType), null, SymbolDisplay.FormatPrimitive(typedConstant.Value, quoteStrings: true, useHexadecimalNumbers: false))); break; } case TypedConstantKind.Enum: { OneOrMany <EnumFieldSymbolInfo> oneOrMany = EnumUtility.GetConstituentFields(typedConstant.Value, (INamedTypeSymbol)typedConstant.Type); OneOrMany <EnumFieldSymbolInfo> .Enumerator en = oneOrMany.GetEnumerator(); if (en.MoveNext()) { while (true) { AddDisplayParts(parts, en.Current.Symbol, format, additionalOptions); if (en.MoveNext()) { parts.AddSpace(); parts.AddPunctuation("|"); parts.AddSpace(); } else { break; } } } else { parts.AddPunctuation("("); AddDisplayParts(parts, (INamedTypeSymbol)typedConstant.Type, format, additionalOptions); parts.AddPunctuation(")"); parts.Add(new SymbolDisplayPart(SymbolDisplayPartKind.NumericLiteral, null, typedConstant.Value.ToString())); } break; } case TypedConstantKind.Type: { parts.AddKeyword("typeof"); parts.AddPunctuation("("); AddDisplayParts(parts, (ISymbol)typedConstant.Value, format, additionalOptions); parts.AddPunctuation(")"); break; } case TypedConstantKind.Array: { var arrayType = (IArrayTypeSymbol)typedConstant.Type; parts.AddKeyword("new"); parts.AddSpace(); AddDisplayParts(parts, arrayType.ElementType, format, additionalOptions); parts.AddPunctuation("["); parts.AddPunctuation("]"); parts.AddSpace(); parts.AddPunctuation("{"); parts.AddSpace(); ImmutableArray <TypedConstant> .Enumerator en = typedConstant.Values.GetEnumerator(); if (en.MoveNext()) { while (true) { AddConstantValue(en.Current); if (en.MoveNext()) { parts.AddPunctuation(","); parts.AddSpace(); } else { break; } } } parts.AddSpace(); parts.AddPunctuation("}"); break; } default: { throw new InvalidOperationException(); } } SymbolDisplayPartKind GetSymbolDisplayPart(SpecialType specialType) { switch (specialType) { case SpecialType.System_Boolean: return(SymbolDisplayPartKind.Keyword); case SpecialType.System_SByte: case SpecialType.System_Byte: case SpecialType.System_Int16: case SpecialType.System_UInt16: case SpecialType.System_Int32: case SpecialType.System_UInt32: case SpecialType.System_Int64: case SpecialType.System_UInt64: case SpecialType.System_Single: case SpecialType.System_Double: return(SymbolDisplayPartKind.NumericLiteral); case SpecialType.System_Char: case SpecialType.System_String: return(SymbolDisplayPartKind.StringLiteral); default: throw new InvalidOperationException(); } } } }
private static void AddAttributes( ImmutableArray <SymbolDisplayPart> .Builder parts, IEnumerable <AttributeData> attributes, SymbolDisplayFormat format, SymbolDisplayAdditionalOptions additionalOptions, bool includeTrailingNewLine = true, bool?formatAttributes = null) { IComparer <INamedTypeSymbol> comparer = (additionalOptions.HasOption(SymbolDisplayAdditionalOptions.OmitContainingNamespace)) ? SymbolDefinitionComparer.SystemFirstOmitContainingNamespace.TypeComparer : SymbolDefinitionComparer.SystemFirst.TypeComparer; attributes = attributes.OrderBy(f => f.AttributeClass, comparer); using (IEnumerator <AttributeData> en = attributes.GetEnumerator()) { if (en.MoveNext()) { parts.AddPunctuation("["); while (true) { AddAttribute(parts, en.Current, format, additionalOptions); if (en.MoveNext()) { if (formatAttributes ?? additionalOptions.HasOption(SymbolDisplayAdditionalOptions.FormatAttributes)) { parts.AddPunctuation("]"); if (includeTrailingNewLine) { parts.AddLineBreak(); } else { parts.AddSpace(); } parts.AddPunctuation("["); } else { parts.AddPunctuation(","); parts.AddSpace(); } } else { break; } } parts.AddPunctuation("]"); if (includeTrailingNewLine) { parts.AddLineBreak(); } } } }
public static ImmutableArray <SymbolDisplayPart> GetDisplayParts( ISymbol symbol, SymbolDisplayFormat format, SymbolDisplayTypeDeclarationOptions typeDeclarationOptions = SymbolDisplayTypeDeclarationOptions.None, SymbolDisplayAdditionalOptions additionalOptions = SymbolDisplayAdditionalOptions.None, Func <ISymbol, AttributeData, bool> shouldDisplayAttribute = null) { ImmutableArray <SymbolDisplayPart> parts; if (symbol is INamedTypeSymbol typeSymbol) { parts = typeSymbol.ToDisplayParts(format, typeDeclarationOptions); } else { parts = symbol.ToDisplayParts(format); typeSymbol = null; } IEnumerable <AttributeData> attributes = (additionalOptions.HasOption(SymbolDisplayAdditionalOptions.IncludeAttributes)) ? GetAttributes(symbol, shouldDisplayAttribute) : ImmutableArray <AttributeData> .Empty; ImmutableArray <SymbolDisplayPart> .Builder builder = default; INamedTypeSymbol baseType = null; ImmutableArray <INamedTypeSymbol> interfaces = ImmutableArray <INamedTypeSymbol> .Empty; if (typeSymbol != null && (typeDeclarationOptions & SymbolDisplayTypeDeclarationOptions.BaseList) != 0) { if ((typeDeclarationOptions & SymbolDisplayTypeDeclarationOptions.BaseType) != 0 && typeSymbol.TypeKind.Is(TypeKind.Class, TypeKind.Interface)) { baseType = typeSymbol.BaseType; if (baseType?.SpecialType == SpecialType.System_Object) { baseType = null; } } if ((typeDeclarationOptions & SymbolDisplayTypeDeclarationOptions.Interfaces) != 0) { interfaces = typeSymbol.Interfaces; if (additionalOptions.HasOption(SymbolDisplayAdditionalOptions.OmitIEnumerable) && interfaces.Any(f => f.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IEnumerable_T)) { interfaces = interfaces.RemoveAll(f => f.SpecialType == SpecialType.System_Collections_IEnumerable); } } } int baseListCount = interfaces.Length; if (baseType != null) { baseListCount++; } int constraintCount = 0; int whereIndex = -1; for (int i = 0; i < parts.Length; i++) { if (parts[i].IsKeyword("where")) { if (whereIndex == -1) { whereIndex = i; } constraintCount++; } } if (baseListCount > 0) { InitializeBuilder(); if (whereIndex != -1) { builder.AddRange(parts, whereIndex); } else { builder.AddRange(parts); builder.AddSpace(); } builder.AddPunctuation(":"); builder.AddSpace(); if (baseType != null) { builder.AddDisplayParts(baseType, format, additionalOptions); if (interfaces.Any()) { builder.AddPunctuation(","); if (additionalOptions.HasOption(SymbolDisplayAdditionalOptions.FormatBaseList)) { builder.AddLineBreak(); builder.AddIndentation(); } else { builder.AddSpace(); } } } IComparer <INamedTypeSymbol> comparer = (additionalOptions.HasOption(SymbolDisplayAdditionalOptions.OmitContainingNamespace)) ? SymbolDefinitionComparer.SystemFirstOmitContainingNamespace.TypeComparer : SymbolDefinitionComparer.SystemFirst.TypeComparer; interfaces = interfaces.Sort(comparer); ImmutableArray <INamedTypeSymbol> .Enumerator en = interfaces.GetEnumerator(); if (en.MoveNext()) { while (true) { builder.AddDisplayParts(en.Current, format, additionalOptions); if (en.MoveNext()) { builder.AddPunctuation(","); if (additionalOptions.HasOption(SymbolDisplayAdditionalOptions.FormatBaseList)) { builder.AddLineBreak(); builder.AddIndentation(); } else { builder.AddSpace(); } } else { break; } } } if (whereIndex != -1) { if (!additionalOptions.HasOption(SymbolDisplayAdditionalOptions.FormatConstraints) || (baseListCount == 1 && constraintCount == 1)) { builder.AddSpace(); } } } if (whereIndex != -1) { InitializeBuilder(); if (baseListCount == 0) { builder.AddRange(parts, whereIndex); } for (int i = whereIndex; i < parts.Length; i++) { if (parts[i].IsKeyword("where") && additionalOptions.HasOption(SymbolDisplayAdditionalOptions.FormatConstraints) && (baseListCount > 1 || constraintCount > 1)) { builder.AddLineBreak(); builder.AddIndentation(); } builder.Add(parts[i]); } } if (builder == null && attributes.Any()) { builder = ImmutableArray.CreateBuilder <SymbolDisplayPart>(parts.Length); AddAttributes(builder, attributes, format, additionalOptions, includeTrailingNewLine: true); builder.AddRange(parts); } bool hasEventAccessorList = false; if (additionalOptions.HasOption(SymbolDisplayAdditionalOptions.IncludeAccessorAttributes)) { if (symbol.Kind == SymbolKind.Property) { var propertySymbol = (IPropertySymbol)symbol; IMethodSymbol getMethod = propertySymbol.GetMethod; if (getMethod != null) { builder = builder ?? parts.ToBuilder(); AddAccessorAttributes(builder, getMethod, format, additionalOptions, shouldDisplayAttribute: shouldDisplayAttribute); } IMethodSymbol setMethod = propertySymbol.SetMethod; if (setMethod != null) { builder = builder ?? parts.ToBuilder(); AddAccessorAttributes(builder, setMethod, format, additionalOptions, shouldDisplayAttribute: shouldDisplayAttribute); } } else if (symbol.Kind == SymbolKind.Event) { var eventSymbol = (IEventSymbol)symbol; IEnumerable <AttributeData> addAttributes = GetAttributes(eventSymbol.AddMethod, shouldDisplayAttribute); IEnumerable <AttributeData> removeAttributes = GetAttributes(eventSymbol.RemoveMethod, shouldDisplayAttribute); if (addAttributes.Any() || removeAttributes.Any()) { hasEventAccessorList = true; builder = builder ?? parts.ToBuilder(); AddEventAccessorAttributes(builder, addAttributes, removeAttributes, format, additionalOptions); } } } ImmutableArray <IParameterSymbol> parameters = symbol.GetParameters(); if (additionalOptions.HasOption(SymbolDisplayAdditionalOptions.IncludeParameterAttributes) && parameters.Any(f => GetAttributes(f, shouldDisplayAttribute).Any())) { builder = builder ?? parts.ToBuilder(); AddParameterAttributes(builder, symbol, parameters, format, additionalOptions, shouldDisplayAttribute); } if (additionalOptions.HasOption(SymbolDisplayAdditionalOptions.FormatParameters) && parameters.Length > 1) { builder = builder ?? parts.ToBuilder(); FormatParameters(symbol, builder, DefinitionListFormat.Default.IndentChars); } if (ShouldAddTrailingSemicolon()) { if (builder == null) { parts = parts.Add(new SymbolDisplayPart(SymbolDisplayPartKind.Punctuation, null, ";")); } else { builder.AddPunctuation(";"); } } return(builder?.ToImmutableArray() ?? parts); void InitializeBuilder() { if (builder == null) { builder = ImmutableArray.CreateBuilder <SymbolDisplayPart>(parts.Length); if (attributes.Any()) { AddAttributes(builder, attributes, format, additionalOptions, includeTrailingNewLine: true); } } } bool ShouldAddTrailingSemicolon() { if (additionalOptions.HasOption(SymbolDisplayAdditionalOptions.IncludeTrailingSemicolon)) { if (typeSymbol?.TypeKind == TypeKind.Delegate) { return(true); } switch (symbol.Kind) { case SymbolKind.Event: return(!hasEventAccessorList); case SymbolKind.Field: return(symbol.ContainingType?.TypeKind != TypeKind.Enum); case SymbolKind.Method: return(true); } } return(false); } }
private static bool HasOption(this SymbolDisplayAdditionalOptions options, SymbolDisplayAdditionalOptions option) { return((options & option) == option); }
private static void AddDisplayParts( this ImmutableArray <SymbolDisplayPart> .Builder parts, ISymbol symbol, SymbolDisplayFormat format, SymbolDisplayAdditionalOptions additionalOptions, bool removeAttributeSuffix = false) { SymbolDisplayFormat format2; if (additionalOptions.HasOption(SymbolDisplayAdditionalOptions.OmitContainingNamespace)) { format2 = TypeSymbolDisplayFormats.Name_ContainingTypes_SpecialTypes; } else if (format.GlobalNamespaceStyle == SymbolDisplayGlobalNamespaceStyle.Included) { format2 = TypeSymbolDisplayFormats.Name_ContainingTypes_Namespaces_GlobalNamespace_SpecialTypes; } else { format2 = TypeSymbolDisplayFormats.Name_ContainingTypes_Namespaces_SpecialTypes; } parts.AddRange(symbol.ToDisplayParts(format2)); if (!(symbol is INamedTypeSymbol typeSymbol)) { return; } if (removeAttributeSuffix) { SymbolDisplayPart last = parts.Last(); if (last.Kind == SymbolDisplayPartKind.ClassName) { const string attributeSuffix = "Attribute"; string text = last.ToString(); if (text.EndsWith(attributeSuffix, StringComparison.Ordinal)) { parts[parts.Count - 1] = last.WithText(text.Remove(text.Length - attributeSuffix.Length)); } } } ImmutableArray <ITypeSymbol> typeArguments = typeSymbol.TypeArguments; ImmutableArray <ITypeSymbol> .Enumerator en = typeArguments.GetEnumerator(); if (en.MoveNext()) { parts.AddPunctuation("<"); while (true) { if (en.Current.Kind == SymbolKind.NamedType) { parts.AddDisplayParts((INamedTypeSymbol)en.Current, format, additionalOptions); } else { Debug.Assert(en.Current.Kind == SymbolKind.TypeParameter, en.Current.Kind.ToString()); parts.Add(new SymbolDisplayPart(SymbolDisplayPartKind.TypeParameterName, en.Current, en.Current.Name)); } if (en.MoveNext()) { parts.AddPunctuation(","); parts.AddSpace(); } else { break; } } parts.AddPunctuation(">"); } }