/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/VisualStudio/CSharp/Impl/ObjectBrowser/DescriptionBuilder.cs
536 строк
16 KB
Cyrus Najmabadi
Update src/VisualStudio/CSharp/Impl/ObjectBrowser/DescriptionBuilder.cs
18 дек 2024, 01:49
Не верифицирован
18 дек 2024, 01:49
ef6467e
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable using System.Collections.Immutable; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectBrowser; using Microsoft.VisualStudio.Shell.Interop; namespace Microsoft.VisualStudio.LanguageServices.CSharp.ObjectBrowser; internal sealed class DescriptionBuilder( IVsObjectBrowserDescription3 description, ObjectBrowserLibraryManager libraryManager, ObjectListItem listItem, Project project) : AbstractDescriptionBuilder(description, libraryManager, listItem, project) { protected override void BuildNamespaceDeclaration(INamespaceSymbol namespaceSymbol, _VSOBJDESCOPTIONS options) { AddText("namespace "); AddName(namespaceSymbol.ToDisplayString()); } protected override async Task BuildDelegateDeclarationAsync( INamedTypeSymbol typeSymbol, _VSOBJDESCOPTIONS options, CancellationToken cancellationToken) { Debug.Assert(typeSymbol.TypeKind == TypeKind.Delegate); BuildTypeModifiers(typeSymbol); AddText("delegate "); var delegateInvokeMethod = typeSymbol.DelegateInvokeMethod; await AddTypeLinkAsync(delegateInvokeMethod.ReturnType, LinkFlags.None, cancellationToken).ConfigureAwait(true); AddText(" "); var typeQualificationStyle = (options & _VSOBJDESCOPTIONS.ODO_USEFULLNAME) != 0 ? SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces : SymbolDisplayTypeQualificationStyle.NameOnly; var typeNameFormat = new SymbolDisplayFormat( typeQualificationStyle: typeQualificationStyle, genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeVariance); AddName(typeSymbol.ToDisplayString(typeNameFormat)); AddText("("); await BuildParameterListAsync(delegateInvokeMethod.Parameters, cancellationToken).ConfigureAwait(true); AddText(")"); if (typeSymbol.IsGenericType) await BuildGenericConstraintsAsync(typeSymbol, cancellationToken).ConfigureAwait(true); } protected override async Task BuildTypeDeclarationAsync( INamedTypeSymbol typeSymbol, _VSOBJDESCOPTIONS options, CancellationToken cancellationToken) { BuildTypeModifiers(typeSymbol); switch (typeSymbol.TypeKind) { case TypeKind.Enum: AddText("enum "); break; case TypeKind.Struct: AddText("struct "); break; case TypeKind.Interface: AddText("interface "); break; case TypeKind.Class: AddText("class "); break; default: Debug.Fail("Invalid type kind encountered: " + typeSymbol.TypeKind.ToString()); break; } var typeNameFormat = new SymbolDisplayFormat( genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeVariance); AddName(typeSymbol.ToDisplayString(typeNameFormat)); if (typeSymbol.TypeKind == TypeKind.Enum) { var underlyingType = typeSymbol.EnumUnderlyingType; if (underlyingType != null) { if (underlyingType.SpecialType != SpecialType.System_Int32) { AddText(" : "); await AddTypeLinkAsync(underlyingType, LinkFlags.None, cancellationToken).ConfigureAwait(true); } } } else { var baseType = typeSymbol.BaseType; if (baseType != null) { if (baseType.SpecialType is not SpecialType.System_Object and not SpecialType.System_Delegate and not SpecialType.System_MulticastDelegate and not SpecialType.System_Enum and not SpecialType.System_ValueType) { AddText(" : "); await AddTypeLinkAsync(baseType, LinkFlags.None, cancellationToken).ConfigureAwait(true); } } } if (typeSymbol.IsGenericType) await BuildGenericConstraintsAsync(typeSymbol, cancellationToken).ConfigureAwait(true); } private void BuildAccessibility(ISymbol symbol) { switch (symbol.DeclaredAccessibility) { case Accessibility.Public: AddText("public "); break; case Accessibility.Private: AddText("private "); break; case Accessibility.Protected: AddText("protected "); break; case Accessibility.Internal: AddText("internal "); break; case Accessibility.ProtectedOrInternal: AddText("protected internal "); break; case Accessibility.ProtectedAndInternal: AddText("private protected "); break; default: AddText("internal "); break; } } private void BuildTypeModifiers(INamedTypeSymbol typeSymbol) { BuildAccessibility(typeSymbol); if (typeSymbol.IsStatic) { AddText("static "); } if (typeSymbol.IsAbstract && typeSymbol.TypeKind != TypeKind.Interface) { AddText("abstract "); } if (typeSymbol.IsSealed && typeSymbol.TypeKind != TypeKind.Struct && typeSymbol.TypeKind != TypeKind.Enum && typeSymbol.TypeKind != TypeKind.Delegate) { AddText("sealed "); } } protected override async Task BuildMethodDeclarationAsync( IMethodSymbol methodSymbol, _VSOBJDESCOPTIONS options, CancellationToken cancellationToken) { BuildMemberModifiers(methodSymbol); if (methodSymbol.MethodKind is not MethodKind.Constructor and not MethodKind.Destructor and not MethodKind.StaticConstructor and not MethodKind.Conversion) { await AddTypeLinkAsync(methodSymbol.ReturnType, LinkFlags.None, cancellationToken).ConfigureAwait(true); AddText(" "); } if (methodSymbol.MethodKind == MethodKind.Conversion) { switch (methodSymbol.Name) { case WellKnownMemberNames.ImplicitConversionName: AddName("implicit operator "); break; case WellKnownMemberNames.ExplicitConversionName: AddName("explicit operator "); break; } await AddTypeLinkAsync(methodSymbol.ReturnType, LinkFlags.None, cancellationToken).ConfigureAwait(true); } else { var methodNameFormat = new SymbolDisplayFormat( genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeVariance); AddName(methodSymbol.ToDisplayString(methodNameFormat)); } AddText("("); if (methodSymbol.IsExtensionMethod) { AddText("this "); } await BuildParameterListAsync(methodSymbol.Parameters, cancellationToken).ConfigureAwait(true); AddText(")"); if (methodSymbol.IsGenericMethod) await BuildGenericConstraintsAsync(methodSymbol, cancellationToken).ConfigureAwait(true); } private void BuildMemberModifiers(ISymbol memberSymbol) { if (memberSymbol.ContainingType != null && memberSymbol.ContainingType.TypeKind == TypeKind.Interface) { return; } var methodSymbol = memberSymbol as IMethodSymbol; var fieldSymbol = memberSymbol as IFieldSymbol; if (methodSymbol != null && methodSymbol.MethodKind == MethodKind.Destructor) { return; } if (fieldSymbol != null && fieldSymbol.ContainingType.TypeKind == TypeKind.Enum) { return; } // TODO: 'new' modifier isn't exposed on symbols. Do we need it? // Note: we don't display the access modifier for static constructors if (methodSymbol == null || methodSymbol.MethodKind != MethodKind.StaticConstructor) { BuildAccessibility(memberSymbol); } if (memberSymbol.RequiresUnsafeModifier()) { AddText("unsafe "); } // Note: we don't display 'static' for constant fields if (memberSymbol.IsStatic && (fieldSymbol == null || !fieldSymbol.IsConst)) { AddText("static "); } if (memberSymbol.IsExtern) { AddText("extern "); } if (fieldSymbol != null && fieldSymbol.IsReadOnly) { AddText("readonly "); } if (fieldSymbol != null && fieldSymbol.IsConst) { AddText("const "); } if (fieldSymbol != null && fieldSymbol.IsVolatile) { AddText("volatile "); } if (memberSymbol.IsAbstract) { AddText("abstract "); } else if (memberSymbol.IsOverride) { if (memberSymbol.IsSealed) { AddText("sealed "); } AddText("override "); } else if (memberSymbol.IsVirtual) { AddText("virtual "); } } private async Task BuildGenericConstraintsAsync(INamedTypeSymbol typeSymbol, CancellationToken cancellationToken) { foreach (var typeParameterSymbol in typeSymbol.TypeParameters) await BuildConstraintsAsync(typeParameterSymbol, cancellationToken).ConfigureAwait(true); } private async Task BuildGenericConstraintsAsync(IMethodSymbol methodSymbol, CancellationToken cancellationToken) { foreach (var typeParameterSymbol in methodSymbol.TypeParameters) await BuildConstraintsAsync(typeParameterSymbol, cancellationToken).ConfigureAwait(true); } private async Task BuildConstraintsAsync(ITypeParameterSymbol typeParameterSymbol, CancellationToken cancellationToken) { if (typeParameterSymbol.ConstraintTypes.Length == 0 && !typeParameterSymbol.HasConstructorConstraint && !typeParameterSymbol.HasReferenceTypeConstraint && !typeParameterSymbol.HasValueTypeConstraint && !typeParameterSymbol.AllowsRefLikeType) { return; } AddLineBreak(); AddText("\t"); AddText("where "); AddName(typeParameterSymbol.Name); AddText(" : "); var isFirst = true; if (typeParameterSymbol.HasReferenceTypeConstraint) { if (!isFirst) { AddComma(); } AddText("class"); isFirst = false; } if (typeParameterSymbol.HasValueTypeConstraint) { if (!isFirst) { AddComma(); } AddText("struct"); isFirst = false; } foreach (var constraintType in typeParameterSymbol.ConstraintTypes) { if (!isFirst) { AddComma(); } await AddTypeLinkAsync(constraintType, LinkFlags.None, cancellationToken).ConfigureAwait(true); isFirst = false; } if (typeParameterSymbol.HasConstructorConstraint) { if (!isFirst) { AddComma(); } AddText("new()"); isFirst = false; } if (typeParameterSymbol.AllowsRefLikeType) { if (!isFirst) { AddComma(); } AddText("allows ref struct"); } } private async Task BuildParameterListAsync( ImmutableArray<IParameterSymbol> parameters, CancellationToken cancellationToken) { var count = parameters.Length; if (count == 0) { return; } for (var i = 0; i < count; i++) { if (i > 0) { AddComma(); } var current = parameters[i]; if (current.IsOptional) { AddText("["); } if (current.RefKind == RefKind.Ref) { AddText("ref "); } else if (current.RefKind == RefKind.Out) { AddText("out "); } if (current.IsParams) { AddText("params "); } await AddTypeLinkAsync(current.Type, LinkFlags.None, cancellationToken).ConfigureAwait(true); AddText(" "); AddParam(current.Name); if (current.HasExplicitDefaultValue) { AddText(" = "); if (current.ExplicitDefaultValue == null) { AddText("null"); } else { AddText(current.ExplicitDefaultValue.ToString()); } } if (current.IsOptional) { AddText("]"); } } } protected override async Task BuildFieldDeclarationAsync( IFieldSymbol fieldSymbol, _VSOBJDESCOPTIONS options, CancellationToken cancellationToken) { BuildMemberModifiers(fieldSymbol); if (fieldSymbol.ContainingType.TypeKind != TypeKind.Enum) { await AddTypeLinkAsync(fieldSymbol.Type, LinkFlags.None, cancellationToken).ConfigureAwait(true); AddText(" "); } AddName(fieldSymbol.Name); } protected override async Task BuildPropertyDeclarationAsync( IPropertySymbol propertySymbol, _VSOBJDESCOPTIONS options, CancellationToken cancellationToken) { BuildMemberModifiers(propertySymbol); await AddTypeLinkAsync(propertySymbol.Type, LinkFlags.None, cancellationToken).ConfigureAwait(true); AddText(" "); if (propertySymbol.IsIndexer) { AddName("this"); AddText("["); await BuildParameterListAsync(propertySymbol.Parameters, cancellationToken).ConfigureAwait(true); AddText("]"); } else { AddName(propertySymbol.Name); } AddText(" { "); if (propertySymbol.GetMethod != null) { if (propertySymbol.GetMethod.DeclaredAccessibility != propertySymbol.DeclaredAccessibility) { BuildAccessibility(propertySymbol.GetMethod); } AddText("get; "); } if (propertySymbol.SetMethod != null) { if (propertySymbol.SetMethod.DeclaredAccessibility != propertySymbol.DeclaredAccessibility) { BuildAccessibility(propertySymbol.SetMethod); } AddText("set; "); } AddText("}"); } protected override async Task BuildEventDeclarationAsync( IEventSymbol eventSymbol, _VSOBJDESCOPTIONS options, CancellationToken cancellationToken) { BuildMemberModifiers(eventSymbol); AddText("event "); await AddTypeLinkAsync(eventSymbol.Type, LinkFlags.None, cancellationToken).ConfigureAwait(true); AddText(" "); AddName(eventSymbol.Name); } }