Пример #1
0
        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();
                    }
                }
            }
        }
        private static void AddAttributes(
            ImmutableArray <SymbolDisplayPart> .Builder builder,
            ImmutableArray <AttributeData> attributes,
            Func <INamedTypeSymbol, bool> predicate = null,
            INamespaceSymbol containingNamespace    = null,
            bool splitAttributes           = true,
            bool includeAttributeArguments = false,
            bool isAssemblyAttribute       = false,
            bool addNewLine = true)
        {
            using (IEnumerator <AttributeData> en = attributes
                                                    .Where(f => predicate(f.AttributeClass))
                                                    .OrderBy(f => ToDisplayString(f.AttributeClass, containingNamespace)).GetEnumerator())
            {
                if (en.MoveNext())
                {
                    builder.AddPunctuation("[");

                    if (isAssemblyAttribute)
                    {
                        builder.AddKeyword("assembly");
                        builder.AddPunctuation(":");
                        builder.AddSpace();
                    }

                    while (true)
                    {
                        builder.AddDisplayParts(en.Current.AttributeClass, containingNamespace);

                        if (includeAttributeArguments)
                        {
                            AddAttributeArguments(en.Current);
                        }

                        if (en.MoveNext())
                        {
                            if (splitAttributes)
                            {
                                builder.AddPunctuation("]");

                                if (addNewLine)
                                {
                                    builder.AddLineBreak();
                                }
                                else
                                {
                                    builder.AddSpace();
                                }

                                builder.AddPunctuation("[");

                                if (isAssemblyAttribute)
                                {
                                    builder.AddKeyword("assembly");
                                    builder.AddPunctuation(":");
                                    builder.AddSpace();
                                }
                            }
                            else
                            {
                                builder.AddPunctuation(",");
                                builder.AddSpace();
                            }
                        }
                        else
                        {
                            break;
                        }
                    }

                    builder.AddPunctuation("]");

                    if (addNewLine)
                    {
                        builder.AddLineBreak();
                    }
                }
            }

            void AddAttributeArguments(AttributeData attributeData)
            {
                bool hasConstructorArgument = false;
                bool hasNamedArgument       = false;

                AppendConstructorArguments();
                AppendNamedArguments();

                if (hasConstructorArgument || hasNamedArgument)
                {
                    builder.AddPunctuation(")");
                }

                void AppendConstructorArguments()
                {
                    ImmutableArray <TypedConstant> .Enumerator en = attributeData.ConstructorArguments.GetEnumerator();

                    if (en.MoveNext())
                    {
                        hasConstructorArgument = true;
                        builder.AddPunctuation("(");

                        while (true)
                        {
                            AddConstantValue(en.Current);

                            if (en.MoveNext())
                            {
                                builder.AddPunctuation(",");
                                builder.AddSpace();
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                }

                void AppendNamedArguments()
                {
                    ImmutableArray <KeyValuePair <string, TypedConstant> > .Enumerator en = attributeData.NamedArguments.GetEnumerator();

                    if (en.MoveNext())
                    {
                        hasNamedArgument = true;

                        if (hasConstructorArgument)
                        {
                            builder.AddPunctuation(",");
                            builder.AddSpace();
                        }
                        else
                        {
                            builder.AddPunctuation("(");
                        }

                        while (true)
                        {
                            builder.Add(new SymbolDisplayPart(SymbolDisplayPartKind.PropertyName, null, en.Current.Key));
                            builder.AddSpace();
                            builder.AddPunctuation("=");
                            builder.AddSpace();
                            AddConstantValue(en.Current.Value);

                            if (en.MoveNext())
                            {
                                builder.AddPunctuation(",");
                                builder.AddSpace();
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                }
            }

            void AddConstantValue(TypedConstant typedConstant)
            {
                switch (typedConstant.Kind)
                {
                case TypedConstantKind.Primitive:
                {
                    builder.Add(new SymbolDisplayPart(
                                    GetSymbolDisplayPart(typedConstant.Type.SpecialType),
                                    null,
                                    SymbolDisplay.FormatPrimitive(typedConstant.Value, quoteStrings: true, useHexadecimalNumbers: false)));

                    break;
                }

                case TypedConstantKind.Enum:
                {
                    OneOrMany <EnumFieldInfo> oneOrMany = EnumUtility.GetConstituentFields(typedConstant.Value, (INamedTypeSymbol)typedConstant.Type);

                    OneOrMany <EnumFieldInfo> .Enumerator en = oneOrMany.GetEnumerator();

                    if (en.MoveNext())
                    {
                        while (true)
                        {
                            AddDisplayParts(builder, en.Current.Symbol, containingNamespace);

                            if (en.MoveNext())
                            {
                                builder.AddSpace();
                                builder.AddPunctuation("|");
                                builder.AddSpace();
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                    else
                    {
                        builder.AddPunctuation("(");
                        AddDisplayParts(builder, (INamedTypeSymbol)typedConstant.Type, containingNamespace);
                        builder.AddPunctuation(")");
                        builder.Add(new SymbolDisplayPart(SymbolDisplayPartKind.NumericLiteral, null, typedConstant.Value.ToString()));
                    }

                    break;
                }

                case TypedConstantKind.Type:
                {
                    builder.AddKeyword("typeof");
                    builder.AddPunctuation("(");
                    AddDisplayParts(builder, (ISymbol)typedConstant.Value, containingNamespace);
                    builder.AddPunctuation(")");

                    break;
                }

                case TypedConstantKind.Array:
                {
                    var arrayType = (IArrayTypeSymbol)typedConstant.Type;

                    builder.AddKeyword("new");
                    builder.AddSpace();
                    AddDisplayParts(builder, arrayType.ElementType, containingNamespace);

                    builder.AddPunctuation("[");
                    builder.AddPunctuation("]");
                    builder.AddSpace();
                    builder.AddPunctuation("{");
                    builder.AddSpace();

                    ImmutableArray <TypedConstant> .Enumerator en = typedConstant.Values.GetEnumerator();

                    if (en.MoveNext())
                    {
                        while (true)
                        {
                            AddConstantValue(en.Current);

                            if (en.MoveNext())
                            {
                                builder.AddPunctuation(",");
                                builder.AddSpace();
                            }
                            else
                            {
                                break;
                            }
                        }
                    }

                    builder.AddSpace();
                    builder.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();
                    }
                }
            }
        }
Пример #3
0
        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);
            }
        }
        public static ImmutableArray <SymbolDisplayPart> GetDisplayParts(
            ISymbol symbol,
            SymbolDisplayFormat format,
            SymbolDisplayTypeDeclarationOptions typeDeclarationOptions = SymbolDisplayTypeDeclarationOptions.None,
            Func <INamedTypeSymbol, bool> isVisibleAttribute           = null,
            bool formatBaseList            = false,
            bool formatConstraints         = false,
            bool formatParameters          = false,
            bool splitAttributes           = true,
            bool includeAttributeArguments = false,
            bool omitIEnumerable           = false,
            bool useNameOnlyIfPossible     = false)
        {
            ImmutableArray <SymbolDisplayPart> parts;

            if (symbol is INamedTypeSymbol typeSymbol)
            {
                parts = typeSymbol.ToDisplayParts(format, typeDeclarationOptions);
            }
            else
            {
                parts      = symbol.ToDisplayParts(format);
                typeSymbol = null;
            }

            ImmutableArray <AttributeData> attributes = ImmutableArray <AttributeData> .Empty;
            bool hasAttributes = false;

            if (isVisibleAttribute != null)
            {
                attributes = symbol.GetAttributes();

                hasAttributes = attributes.Any(f => isVisibleAttribute(f.AttributeClass));
            }

            int baseListCount         = 0;
            INamedTypeSymbol baseType = null;
            ImmutableArray <INamedTypeSymbol> interfaces = default;

            if (typeSymbol != null)
            {
                if (typeSymbol.TypeKind.Is(TypeKind.Class, TypeKind.Interface))
                {
                    baseType = typeSymbol.BaseType;

                    if (baseType?.SpecialType == SpecialType.System_Object)
                    {
                        baseType = null;
                    }
                }

                interfaces = typeSymbol.Interfaces;

                if (omitIEnumerable &&
                    interfaces.Any(f => f.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IEnumerable_T))
                {
                    interfaces = interfaces.RemoveAll(f => f.SpecialType == SpecialType.System_Collections_IEnumerable);
                }

                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 (!hasAttributes &&
                baseListCount == 0 &&
                constraintCount == 0 &&
                (!formatParameters || symbol.GetParameters().Length <= 1))
            {
                return(parts);
            }

            INamespaceSymbol containingNamespace = (useNameOnlyIfPossible) ? symbol.ContainingNamespace : null;

            ImmutableArray <SymbolDisplayPart> .Builder builder = ImmutableArray.CreateBuilder <SymbolDisplayPart>(parts.Length);

            AddAttributes(builder, attributes, isVisibleAttribute, containingNamespace, splitAttributes: splitAttributes, includeAttributeArguments: includeAttributeArguments);

            if (baseListCount > 0)
            {
                if (whereIndex != -1)
                {
                    builder.AddRange(parts, whereIndex);
                }
                else
                {
                    builder.AddRange(parts);
                    builder.AddSpace();
                }

                builder.AddPunctuation(":");
                builder.AddSpace();

                if (baseType != null)
                {
                    builder.AddDisplayParts(baseType, containingNamespace);

                    if (interfaces.Any())
                    {
                        builder.AddPunctuation(",");

                        if (formatBaseList)
                        {
                            builder.AddLineBreak();
                            builder.AddIndentation();
                        }
                        else
                        {
                            builder.AddSpace();
                        }
                    }
                }

                interfaces = interfaces.Sort((x, y) =>
                {
                    INamespaceSymbol n1 = x.ContainingNamespace;
                    INamespaceSymbol n2 = y.ContainingNamespace;

                    if (!MetadataNameEqualityComparer <INamespaceSymbol> .Instance.Equals(n1, n2))
                    {
                        return(string.CompareOrdinal(
                                   n1.ToDisplayString(SymbolDisplayFormats.TypeNameAndContainingTypesAndNamespaces),
                                   n2.ToDisplayString(SymbolDisplayFormats.TypeNameAndContainingTypesAndNamespaces)));
                    }

                    return(string.CompareOrdinal(
                               ToDisplayString(x, containingNamespace),
                               ToDisplayString(y, containingNamespace)));
                });

                ImmutableArray <INamedTypeSymbol> .Enumerator en = interfaces.GetEnumerator();

                if (en.MoveNext())
                {
                    while (true)
                    {
                        builder.AddDisplayParts(en.Current, containingNamespace);

                        if (en.MoveNext())
                        {
                            builder.AddPunctuation(",");

                            if (formatBaseList)
                            {
                                builder.AddLineBreak();
                                builder.AddIndentation();
                            }
                            else
                            {
                                builder.AddSpace();
                            }
                        }
                        else
                        {
                            break;
                        }
                    }
                }

                if (whereIndex != -1)
                {
                    if (!formatConstraints ||
                        (baseListCount == 1 && constraintCount == 1))
                    {
                        builder.AddSpace();
                    }
                }
            }
            else if (whereIndex != -1)
            {
                builder.AddRange(parts, whereIndex);
            }
            else
            {
                builder.AddRange(parts);
            }

            if (whereIndex != -1)
            {
                for (int i = whereIndex; i < parts.Length; i++)
                {
                    if (parts[i].IsKeyword("where"))
                    {
                        if (formatConstraints &&
                            (baseListCount > 1 || constraintCount > 1))
                        {
                            builder.AddLineBreak();
                            builder.AddIndentation();
                        }

                        builder.Add(parts[i]);
                    }
                    else if (parts[i].IsTypeName() &&
                             parts[i].Symbol is INamedTypeSymbol namedTypeSymbol)
                    {
                        builder.AddDisplayParts(namedTypeSymbol, containingNamespace);
                    }
                    else
                    {
                        builder.Add(parts[i]);
                    }
                }
            }

            if (formatParameters)
            {
                ImmutableArray <IParameterSymbol> parameters = symbol.GetParameters();

                if (parameters.Length > 1)
                {
                    FormatParameters(symbol, builder, DeclarationListOptions.DefaultValues.IndentChars);
                }
            }

            return(builder.ToImmutableArray());
        }