/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.cs
471 строка
17 KB
Rekkonnect
Merge branch 'main' into fix-66009
25 авг 2024, 18:44
25 авг 2024, 18:44
2a72040
Код
Авторство
О чём код?
// 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. using System; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.SymbolDisplay; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp { internal partial class SymbolDisplayVisitor : AbstractSymbolDisplayVisitor { private static readonly ObjectPool<SymbolDisplayVisitor> s_visitorPool = new ObjectPool<SymbolDisplayVisitor>(pool => new SymbolDisplayVisitor(pool), 128); private readonly ObjectPool<SymbolDisplayVisitor> _pool; private bool _escapeKeywordIdentifiers; private IDictionary<INamespaceOrTypeSymbol, IAliasSymbol>? _lazyAliasMap; private SymbolDisplayVisitor(ObjectPool<SymbolDisplayVisitor> pool) { _pool = pool; } public static SymbolDisplayVisitor GetInstance( ArrayBuilder<SymbolDisplayPart> builder, SymbolDisplayFormat format, SemanticModel? semanticModelOpt, int positionOpt) { var instance = s_visitorPool.Allocate(); instance.Initialize(builder, format, isFirstSymbolVisited: true, semanticModelOpt, positionOpt, inNamespaceOrType: false); return instance; } private static SymbolDisplayVisitor GetInstance( ArrayBuilder<SymbolDisplayPart> builder, SymbolDisplayFormat format, SemanticModel? semanticModelOpt, int positionOpt, bool escapeKeywordIdentifiers, IDictionary<INamespaceOrTypeSymbol, IAliasSymbol>? aliasMap, bool isFirstSymbolVisited, bool inNamespaceOrType = false) { var instance = s_visitorPool.Allocate(); instance.Initialize(builder, format, isFirstSymbolVisited, semanticModelOpt, positionOpt, inNamespaceOrType); instance._escapeKeywordIdentifiers = escapeKeywordIdentifiers; instance._lazyAliasMap = aliasMap; return instance; } protected new void Initialize(ArrayBuilder<SymbolDisplayPart> builder, SymbolDisplayFormat format, bool isFirstSymbolVisited, SemanticModel? semanticModelOpt, int positionOpt, bool inNamespaceOrType) { base.Initialize(builder, format, isFirstSymbolVisited, semanticModelOpt, positionOpt, inNamespaceOrType); _escapeKeywordIdentifiers = format.MiscellaneousOptions.IncludesOption(SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers); } public override void Free() { base.Free(); _escapeKeywordIdentifiers = false; _lazyAliasMap = null; _pool.Free(this); } protected override AbstractSymbolDisplayVisitor MakeNotFirstVisitor(bool inNamespaceOrType = false) { return GetInstance( this.Builder, this.Format, this.SemanticModelOpt, this.PositionOpt, _escapeKeywordIdentifiers, _lazyAliasMap, isFirstSymbolVisited: false, inNamespaceOrType: inNamespaceOrType); } protected override void FreeNotFirstVisitor(AbstractSymbolDisplayVisitor visitor) { Debug.Assert(visitor != this); visitor.Free(); } internal SymbolDisplayPart CreatePart(SymbolDisplayPartKind kind, ISymbol? symbol, string text) { if (text == null) { return new SymbolDisplayPart(kind, symbol, "?"); } if (!_escapeKeywordIdentifiers) { return new SymbolDisplayPart(kind, symbol, text); } if (IsEscapable(kind)) { text = EscapeIdentifier(text, symbol?.Kind is SymbolKind.NamedType or SymbolKind.Alias); } return new SymbolDisplayPart(kind, symbol, text); } private static bool IsEscapable(SymbolDisplayPartKind kind) { switch (kind) { case SymbolDisplayPartKind.AliasName: case SymbolDisplayPartKind.ClassName: case SymbolDisplayPartKind.RecordClassName: case SymbolDisplayPartKind.StructName: case SymbolDisplayPartKind.RecordStructName: case SymbolDisplayPartKind.InterfaceName: case SymbolDisplayPartKind.EnumName: case SymbolDisplayPartKind.DelegateName: case SymbolDisplayPartKind.TypeParameterName: case SymbolDisplayPartKind.MethodName: case SymbolDisplayPartKind.PropertyName: case SymbolDisplayPartKind.FieldName: case SymbolDisplayPartKind.LocalName: case SymbolDisplayPartKind.NamespaceName: case SymbolDisplayPartKind.ParameterName: return true; default: return false; } } private static string EscapeIdentifier(string identifier, bool isNamedTypeOrAliasName) { SyntaxKind kind = SyntaxFacts.GetKeywordKind(identifier); if (kind is SyntaxKind.None && isNamedTypeOrAliasName && StringComparer.Ordinal.Equals(identifier, "record")) { kind = SyntaxKind.RecordKeyword; } return kind == SyntaxKind.None ? identifier : $"@{identifier}"; } public override void VisitAssembly(IAssemblySymbol symbol) { var text = Format.TypeQualificationStyle == SymbolDisplayTypeQualificationStyle.NameOnly ? symbol.Identity.Name : symbol.Identity.GetDisplayName(); Builder.Add(CreatePart(SymbolDisplayPartKind.AssemblyName, symbol, text)); } public override void VisitModule(IModuleSymbol symbol) { Builder.Add(CreatePart(SymbolDisplayPartKind.ModuleName, symbol, symbol.Name)); } public override void VisitNamespace(INamespaceSymbol symbol) { if (this.IsMinimizing) { if (TryAddAlias(symbol, Builder)) { return; } MinimallyQualify(symbol); return; } if (IsFirstSymbolVisited && Format.KindOptions.IncludesOption(SymbolDisplayKindOptions.IncludeNamespaceKeyword)) { AddKeyword(SyntaxKind.NamespaceKeyword); AddSpace(); } if (Format.TypeQualificationStyle == SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces) { var containingNamespace = symbol.ContainingNamespace; if (ShouldVisitNamespace(containingNamespace)) { containingNamespace.Accept(this.NotFirstVisitor); AddPunctuation(containingNamespace.IsGlobalNamespace ? SyntaxKind.ColonColonToken : SyntaxKind.DotToken); } } if (symbol.IsGlobalNamespace) { AddGlobalNamespace(symbol); } else { Builder.Add(CreatePart(SymbolDisplayPartKind.NamespaceName, symbol, symbol.Name)); } } private void AddGlobalNamespace(INamespaceSymbol globalNamespace) { // Formerly, localized via MessageID.IDS_GlobalNamespace. const string standaloneGlobalNamespaceString = "<global namespace>"; switch (Format.GlobalNamespaceStyle) { case SymbolDisplayGlobalNamespaceStyle.Omitted: break; case SymbolDisplayGlobalNamespaceStyle.Included: if (this.IsFirstSymbolVisited) { Builder.Add(CreatePart( SymbolDisplayPartKind.Text, globalNamespace, standaloneGlobalNamespaceString)); } else { Builder.Add(CreatePart(SymbolDisplayPartKind.Keyword, globalNamespace, SyntaxFacts.GetText(SyntaxKind.GlobalKeyword))); } break; case SymbolDisplayGlobalNamespaceStyle.OmittedAsContaining: Debug.Assert(this.IsFirstSymbolVisited, "Don't call with IsFirstSymbolVisited = false if OmittedAsContaining"); Builder.Add(CreatePart( SymbolDisplayPartKind.Text, globalNamespace, standaloneGlobalNamespaceString)); break; default: throw ExceptionUtilities.UnexpectedValue(Format.GlobalNamespaceStyle); } } public override void VisitLocal(ILocalSymbol symbol) { if (Format.LocalOptions.IncludesOption(SymbolDisplayLocalOptions.IncludeModifiers)) { if (symbol.IsRef) { if (symbol.ScopedKind == ScopedKind.ScopedRef) { AddKeyword(SyntaxKind.ScopedKeyword); AddSpace(); } AddKeyword(SyntaxKind.RefKeyword); AddSpace(); if (symbol.RefKind == RefKind.RefReadOnly) { AddKeyword(SyntaxKind.ReadOnlyKeyword); AddSpace(); } } else if (symbol.ScopedKind == ScopedKind.ScopedValue) { AddKeyword(SyntaxKind.ScopedKeyword); AddSpace(); } } if (Format.LocalOptions.IncludesOption(SymbolDisplayLocalOptions.IncludeType)) { symbol.Type.Accept(this.NotFirstVisitor); AddSpace(); } if (symbol.IsConst) { Builder.Add(CreatePart(SymbolDisplayPartKind.ConstantName, symbol, symbol.Name)); } else { Builder.Add(CreatePart(SymbolDisplayPartKind.LocalName, symbol, symbol.Name)); } if (Format.LocalOptions.IncludesOption(SymbolDisplayLocalOptions.IncludeConstantValue) && symbol.IsConst && symbol.HasConstantValue && CanAddConstant(symbol.Type, symbol.ConstantValue)) { AddSpace(); AddPunctuation(SyntaxKind.EqualsToken); AddSpace(); AddConstantValue(symbol.Type, symbol.ConstantValue); } } public override void VisitDiscard(IDiscardSymbol symbol) { if (Format.LocalOptions.IncludesOption(SymbolDisplayLocalOptions.IncludeType)) { symbol.Type.Accept(this.NotFirstVisitor); AddSpace(); } Builder.Add(CreatePart(SymbolDisplayPartKind.Punctuation, symbol, "_")); } public override void VisitRangeVariable(IRangeVariableSymbol symbol) { if (Format.LocalOptions.IncludesOption(SymbolDisplayLocalOptions.IncludeType)) { ITypeSymbol? type = GetRangeVariableType(symbol); if (type != null && type.TypeKind != TypeKind.Error) { type.Accept(this); } else { Builder.Add(CreatePart(SymbolDisplayPartKind.ErrorTypeName, type, "?")); } AddSpace(); } Builder.Add(CreatePart(SymbolDisplayPartKind.RangeVariableName, symbol, symbol.Name)); } public override void VisitLabel(ILabelSymbol symbol) { Builder.Add(CreatePart(SymbolDisplayPartKind.LabelName, symbol, symbol.Name)); } public override void VisitAlias(IAliasSymbol symbol) { Builder.Add(CreatePart(SymbolDisplayPartKind.AliasName, symbol, symbol.Name)); if (Format.LocalOptions.IncludesOption(SymbolDisplayLocalOptions.IncludeType)) { // ??? AddPunctuation(SyntaxKind.EqualsToken); symbol.Target.Accept(this); } } internal override void VisitPreprocessing(IPreprocessingSymbol symbol) { // Currently using 'Text' part kind as there is no kind specific to preprocessing symbols. var part = new SymbolDisplayPart(SymbolDisplayPartKind.Text, symbol, symbol.Name); Builder.Add(part); } protected override void AddSpace() { Builder.Add(CreatePart(SymbolDisplayPartKind.Space, null, " ")); } private void AddPunctuation(SyntaxKind punctuationKind) { Builder.Add(CreatePart(SymbolDisplayPartKind.Punctuation, null, SyntaxFacts.GetText(punctuationKind))); } private void AddKeyword(SyntaxKind keywordKind) { Builder.Add(CreatePart(SymbolDisplayPartKind.Keyword, null, SyntaxFacts.GetText(keywordKind))); } private void AddAccessibilityIfNeeded(ISymbol symbol) { INamedTypeSymbol containingType = symbol.ContainingType; // this method is only called for members and they should have a containingType or a containing symbol should be a TypeSymbol. Debug.Assert((object)containingType != null || (symbol.ContainingSymbol is ITypeSymbol)); if (Format.MemberOptions.IncludesOption(SymbolDisplayMemberOptions.IncludeAccessibility) && (containingType == null || (containingType.TypeKind != TypeKind.Interface && !IsEnumMember(symbol) & !IsLocalFunction(symbol)))) { AddAccessibility(symbol); } } private static bool IsLocalFunction(ISymbol symbol) { if (symbol.Kind != SymbolKind.Method) { return false; } return ((IMethodSymbol)symbol).MethodKind == MethodKind.LocalFunction; } private void AddAccessibility(ISymbol symbol) { switch (symbol.DeclaredAccessibility) { case Accessibility.Private: AddKeyword(SyntaxKind.PrivateKeyword); break; case Accessibility.Internal: AddKeyword(SyntaxKind.InternalKeyword); break; case Accessibility.ProtectedAndInternal: AddKeyword(SyntaxKind.PrivateKeyword); AddSpace(); AddKeyword(SyntaxKind.ProtectedKeyword); break; case Accessibility.Protected: AddKeyword(SyntaxKind.ProtectedKeyword); break; case Accessibility.ProtectedOrInternal: AddKeyword(SyntaxKind.ProtectedKeyword); AddSpace(); AddKeyword(SyntaxKind.InternalKeyword); break; case Accessibility.Public: AddKeyword(SyntaxKind.PublicKeyword); break; default: throw ExceptionUtilities.UnexpectedValue(symbol.DeclaredAccessibility); } AddSpace(); } private bool ShouldVisitNamespace(ISymbol containingSymbol) { var namespaceSymbol = containingSymbol as INamespaceSymbol; if (namespaceSymbol == null) { return false; } if (Format.TypeQualificationStyle != SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces) { return false; } return !namespaceSymbol.IsGlobalNamespace || Format.GlobalNamespaceStyle == SymbolDisplayGlobalNamespaceStyle.Included; } private bool IncludeNamedType([NotNullWhen(true)] INamedTypeSymbol? namedType) { if (namedType is null) { return false; } if (namedType.IsScriptClass && !Format.CompilerInternalOptions.IncludesOption(SymbolDisplayCompilerInternalOptions.IncludeScriptType)) { return false; } if (namedType == SemanticModelOpt?.Compilation.ScriptGlobalsType) { return false; } return true; } private static bool IsEnumMember(ISymbol symbol) { return symbol != null && symbol.Kind == SymbolKind.Field && symbol.ContainingType != null && symbol.ContainingType.TypeKind == TypeKind.Enum && symbol.Name != WellKnownMemberNames.EnumBackingFieldName; } } }