File: Editing\DeclarationModifiers.cs
Web Access
Project: src\src\Workspaces\Core\Portable\Microsoft.CodeAnalysis.Workspaces.csproj (Microsoft.CodeAnalysis.Workspaces)
// 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;
using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis.Shared.Extensions;
 
#if CODE_STYLE
namespace Microsoft.CodeAnalysis.Internal.Editing;
#else
namespace Microsoft.CodeAnalysis.Editing;
#endif
 
public readonly record struct DeclarationModifiers
{
    private readonly Modifiers _modifiers;
 
    private DeclarationModifiers(Modifiers modifiers)
        => _modifiers = modifiers;
 
    internal DeclarationModifiers(
        bool isStatic = false,
        bool isAbstract = false,
        bool isNew = false,
        bool isUnsafe = false,
        bool isReadOnly = false,
        bool isVirtual = false,
        bool isOverride = false,
        bool isSealed = false,
        bool isConst = false,
        bool isWithEvents = false,
        bool isPartial = false,
        bool isAsync = false,
        bool isWriteOnly = false,
        bool isRef = false,
        bool isVolatile = false,
        bool isExtern = false,
        bool isRequired = false,
        bool isFile = false)
        : this(
              (isStatic ? Modifiers.Static : Modifiers.None) |
              (isAbstract ? Modifiers.Abstract : Modifiers.None) |
              (isNew ? Modifiers.New : Modifiers.None) |
              (isUnsafe ? Modifiers.Unsafe : Modifiers.None) |
              (isReadOnly ? Modifiers.ReadOnly : Modifiers.None) |
              (isVirtual ? Modifiers.Virtual : Modifiers.None) |
              (isOverride ? Modifiers.Override : Modifiers.None) |
              (isSealed ? Modifiers.Sealed : Modifiers.None) |
              (isConst ? Modifiers.Const : Modifiers.None) |
              (isWithEvents ? Modifiers.WithEvents : Modifiers.None) |
              (isPartial ? Modifiers.Partial : Modifiers.None) |
              (isAsync ? Modifiers.Async : Modifiers.None) |
              (isWriteOnly ? Modifiers.WriteOnly : Modifiers.None) |
              (isRef ? Modifiers.Ref : Modifiers.None) |
              (isVolatile ? Modifiers.Volatile : Modifiers.None) |
              (isExtern ? Modifiers.Extern : Modifiers.None) |
              (isRequired ? Modifiers.Required : Modifiers.None) |
              (isFile ? Modifiers.File : Modifiers.None))
    {
    }
 
    public static DeclarationModifiers From(ISymbol symbol)
    {
        if (symbol is INamedTypeSymbol or
             IFieldSymbol or
             IPropertySymbol or
             IMethodSymbol or
             IEventSymbol)
        {
            var field = symbol as IFieldSymbol;
            var property = symbol as IPropertySymbol;
            var method = symbol as IMethodSymbol;
            var type = symbol as INamedTypeSymbol;
            var isConst = field?.IsConst == true;
 
            return new DeclarationModifiers(
                isStatic: symbol.IsStatic && !isConst,
                isAbstract: symbol.IsAbstract,
                isReadOnly: field?.IsReadOnly == true || property?.IsReadOnly == true || type?.IsReadOnly == true || method?.IsReadOnly == true,
                isVirtual: symbol.IsVirtual,
                isOverride: symbol.IsOverride,
                isSealed: symbol.IsSealed,
                isConst: isConst,
                isUnsafe: symbol.RequiresUnsafeModifier(),
                isRef: field?.RefKind is RefKind.Ref or RefKind.RefReadOnly || type?.IsRefLikeType == true,
                isVolatile: field?.IsVolatile == true,
                isExtern: symbol.IsExtern,
                isAsync: method?.IsAsync == true,
                isRequired: symbol.IsRequired(),
                isFile: type?.IsFileLocal == true);
        }
 
        // Only named types, members of named types, and local functions have modifiers.
        // Everything else has none.
        return DeclarationModifiers.None;
    }
 
    public bool IsStatic => (_modifiers & Modifiers.Static) != 0;
 
    public bool IsAbstract => (_modifiers & Modifiers.Abstract) != 0;
 
    public bool IsNew => (_modifiers & Modifiers.New) != 0;
 
    public bool IsUnsafe => (_modifiers & Modifiers.Unsafe) != 0;
 
    public bool IsReadOnly => (_modifiers & Modifiers.ReadOnly) != 0;
 
    public bool IsVirtual => (_modifiers & Modifiers.Virtual) != 0;
 
    public bool IsOverride => (_modifiers & Modifiers.Override) != 0;
 
    public bool IsSealed => (_modifiers & Modifiers.Sealed) != 0;
 
    public bool IsConst => (_modifiers & Modifiers.Const) != 0;
 
    public bool IsWithEvents => (_modifiers & Modifiers.WithEvents) != 0;
 
    public bool IsPartial => (_modifiers & Modifiers.Partial) != 0;
 
    public bool IsAsync => (_modifiers & Modifiers.Async) != 0;
 
    public bool IsWriteOnly => (_modifiers & Modifiers.WriteOnly) != 0;
 
    public bool IsRef => (_modifiers & Modifiers.Ref) != 0;
 
    public bool IsVolatile => (_modifiers & Modifiers.Volatile) != 0;
 
    public bool IsExtern => (_modifiers & Modifiers.Extern) != 0;
 
    public bool IsRequired => (_modifiers & Modifiers.Required) != 0;
 
    public bool IsFile => (_modifiers & Modifiers.File) != 0;
 
    public DeclarationModifiers WithIsStatic(bool isStatic)
        => new(SetFlag(_modifiers, Modifiers.Static, isStatic));
 
    public DeclarationModifiers WithIsAbstract(bool isAbstract)
        => new(SetFlag(_modifiers, Modifiers.Abstract, isAbstract));
 
    public DeclarationModifiers WithIsNew(bool isNew)
        => new(SetFlag(_modifiers, Modifiers.New, isNew));
 
    public DeclarationModifiers WithIsUnsafe(bool isUnsafe)
        => new(SetFlag(_modifiers, Modifiers.Unsafe, isUnsafe));
 
    public DeclarationModifiers WithIsReadOnly(bool isReadOnly)
        => new(SetFlag(_modifiers, Modifiers.ReadOnly, isReadOnly));
 
    public DeclarationModifiers WithIsVirtual(bool isVirtual)
        => new(SetFlag(_modifiers, Modifiers.Virtual, isVirtual));
 
    public DeclarationModifiers WithIsOverride(bool isOverride)
        => new(SetFlag(_modifiers, Modifiers.Override, isOverride));
 
    public DeclarationModifiers WithIsSealed(bool isSealed)
        => new(SetFlag(_modifiers, Modifiers.Sealed, isSealed));
 
    public DeclarationModifiers WithIsConst(bool isConst)
        => new(SetFlag(_modifiers, Modifiers.Const, isConst));
 
    public DeclarationModifiers WithWithEvents(bool withEvents)
        => new(SetFlag(_modifiers, Modifiers.WithEvents, withEvents));
 
    public DeclarationModifiers WithPartial(bool isPartial)
        => new(SetFlag(_modifiers, Modifiers.Partial, isPartial));
 
    [SuppressMessage("Style", "VSTHRD200:Use \"Async\" suffix for async methods", Justification = "Public API.")]
    public DeclarationModifiers WithAsync(bool isAsync)
        => new(SetFlag(_modifiers, Modifiers.Async, isAsync));
 
    public DeclarationModifiers WithIsWriteOnly(bool isWriteOnly)
        => new(SetFlag(_modifiers, Modifiers.WriteOnly, isWriteOnly));
 
    public DeclarationModifiers WithIsRef(bool isRef)
        => new(SetFlag(_modifiers, Modifiers.Ref, isRef));
 
    public DeclarationModifiers WithIsVolatile(bool isVolatile)
        => new(SetFlag(_modifiers, Modifiers.Volatile, isVolatile));
 
    public DeclarationModifiers WithIsExtern(bool isExtern)
        => new(SetFlag(_modifiers, Modifiers.Extern, isExtern));
 
    public DeclarationModifiers WithIsRequired(bool isRequired)
        => new(SetFlag(_modifiers, Modifiers.Required, isRequired));
 
    public DeclarationModifiers WithIsFile(bool isFile)
        => new(SetFlag(_modifiers, Modifiers.File, isFile));
 
    private static Modifiers SetFlag(Modifiers existing, Modifiers modifier, bool isSet)
        => isSet ? (existing | modifier) : (existing & ~modifier);
 
    [Flags]
    private enum Modifiers
    {
#pragma warning disable format
        None        = 0,
        Static      = 1 << 0,
        Abstract    = 1 << 1,
        New         = 1 << 2,
        Unsafe      = 1 << 3,
        ReadOnly    = 1 << 4,
        Virtual     = 1 << 5,
        Override    = 1 << 6,
        Sealed      = 1 << 7,
        Const       = 1 << 8,
        WithEvents  = 1 << 9,
        Partial     = 1 << 10,
        Async       = 1 << 11,
        WriteOnly   = 1 << 12,
        Ref         = 1 << 13,
        Volatile    = 1 << 14,
        Extern      = 1 << 15,
        Required    = 1 << 16,
        File        = 1 << 17,
#pragma warning restore format
    }
 
    public static DeclarationModifiers None => default;
 
    public static DeclarationModifiers Static => new(Modifiers.Static);
    public static DeclarationModifiers Abstract => new(Modifiers.Abstract);
    public static DeclarationModifiers New => new(Modifiers.New);
    public static DeclarationModifiers Unsafe => new(Modifiers.Unsafe);
    public static DeclarationModifiers ReadOnly => new(Modifiers.ReadOnly);
    public static DeclarationModifiers Virtual => new(Modifiers.Virtual);
    public static DeclarationModifiers Override => new(Modifiers.Override);
    public static DeclarationModifiers Sealed => new(Modifiers.Sealed);
    public static DeclarationModifiers Const => new(Modifiers.Const);
    public static DeclarationModifiers WithEvents => new(Modifiers.WithEvents);
    public static DeclarationModifiers Partial => new(Modifiers.Partial);
    public static DeclarationModifiers Async => new(Modifiers.Async);
    public static DeclarationModifiers WriteOnly => new(Modifiers.WriteOnly);
    public static DeclarationModifiers Ref => new(Modifiers.Ref);
    public static DeclarationModifiers Volatile => new(Modifiers.Volatile);
    public static DeclarationModifiers Extern => new(Modifiers.Extern);
    public static DeclarationModifiers Required => new(Modifiers.Required);
    public static DeclarationModifiers File => new(Modifiers.File);
 
    public static DeclarationModifiers operator |(DeclarationModifiers left, DeclarationModifiers right)
        => new(left._modifiers | right._modifiers);
 
    public static DeclarationModifiers operator &(DeclarationModifiers left, DeclarationModifiers right)
        => new(left._modifiers & right._modifiers);
 
    public static DeclarationModifiers operator +(DeclarationModifiers left, DeclarationModifiers right)
        => new(left._modifiers | right._modifiers);
 
    public static DeclarationModifiers operator -(DeclarationModifiers left, DeclarationModifiers right)
        => new(left._modifiers & ~right._modifiers);
 
    public override string ToString()
        => _modifiers.ToString();
 
    public static bool TryParse(string value, out DeclarationModifiers modifiers)
    {
        if (Enum.TryParse(value, out Modifiers mods))
        {
            modifiers = new DeclarationModifiers(mods);
            return true;
        }
        else
        {
            modifiers = default;
            return false;
        }
    }
}