| File: Symbols\Source\SourceLabelSymbol.cs | Web Access |
| Project: src\roslyn\src\Compilers\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj (Microsoft.CodeAnalysis.CSharp) |
// 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.Collections.Immutable; using System.Diagnostics; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.CSharp.Symbols { internal sealed class SourceLabelSymbol : LabelSymbol { private readonly MethodSymbol _containingMethod; private readonly SyntaxNodeOrToken _identifierNodeOrToken; /// <summary> /// Switch case labels have a constant expression associated with them. /// </summary> private readonly ConstantValue? _switchCaseLabelConstant; // PERF: Often we do not need this, so we make this lazy private string? _lazyName; public SourceLabelSymbol( MethodSymbol containingMethod, SyntaxNodeOrToken identifierNodeOrToken, ConstantValue? switchCaseLabelConstant = null) { Debug.Assert(identifierNodeOrToken.IsToken || identifierNodeOrToken.IsNode); _containingMethod = containingMethod; _identifierNodeOrToken = identifierNodeOrToken; _switchCaseLabelConstant = switchCaseLabelConstant; } public override string Name { get { return _lazyName ?? (_lazyName = MakeLabelName()); } } private string MakeLabelName() { var node = _identifierNodeOrToken.AsNode(); if (node != null) { if (node.Kind() == SyntaxKind.DefaultSwitchLabel) { return ((DefaultSwitchLabelSyntax)node).Keyword.ToString(); } return node.ToString(); } var tk = _identifierNodeOrToken.AsToken(); if (tk.Kind() != SyntaxKind.None) { return tk.ValueText; } return _switchCaseLabelConstant?.ToString() ?? ""; } public SourceLabelSymbol( MethodSymbol containingMethod, ConstantValue switchCaseLabelConstant) { _containingMethod = containingMethod; _identifierNodeOrToken = default(SyntaxToken); _switchCaseLabelConstant = switchCaseLabelConstant; } public override ImmutableArray<Location> Locations { get { return _identifierNodeOrToken.IsToken && _identifierNodeOrToken.Parent == null ? ImmutableArray<Location>.Empty : ImmutableArray.Create<Location>(_identifierNodeOrToken.GetLocation()!); } } public override ImmutableArray<SyntaxReference> DeclaringSyntaxReferences { get { CSharpSyntaxNode? node = null; if (_identifierNodeOrToken.IsToken) { if (_identifierNodeOrToken.Parent != null) node = _identifierNodeOrToken.Parent.FirstAncestorOrSelf<LabeledStatementSyntax>(); } else { node = _identifierNodeOrToken.AsNode()!.FirstAncestorOrSelf<SwitchLabelSyntax>(); } return node == null ? ImmutableArray<SyntaxReference>.Empty : ImmutableArray.Create<SyntaxReference>(node.GetReference()); } } public override MethodSymbol ContainingMethod { get { return _containingMethod; } } public override Symbol ContainingSymbol { get { return _containingMethod; } } // Get the identifier node or token that defined this label symbol. This is useful for robustly // checking if a label symbol actually matches a particular definition, even in the presence // of duplicates. internal override SyntaxNodeOrToken IdentifierNodeOrToken { get { return _identifierNodeOrToken; } } /// <summary> /// If the label is a switch case label, returns the associated constant value with /// case expression, otherwise returns null. /// </summary> public ConstantValue? SwitchCaseLabelConstant { get { return _switchCaseLabelConstant; } } public override bool Equals(Symbol? obj, TypeCompareKind compareKind) { if (obj == (object)this) { return true; } var symbol = obj as SourceLabelSymbol; return (object?)symbol != null && symbol._identifierNodeOrToken.Kind() != SyntaxKind.None && symbol._identifierNodeOrToken.Equals(_identifierNodeOrToken) && symbol._containingMethod.Equals(_containingMethod, compareKind); } public override int GetHashCode() { return _identifierNodeOrToken.GetHashCode(); } } }