keyword_modifier_set.h 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #ifndef CARBON_TOOLCHAIN_CHECK_KEYWORD_MODIFIER_SET_H_
  5. #define CARBON_TOOLCHAIN_CHECK_KEYWORD_MODIFIER_SET_H_
  6. #include <optional>
  7. #include "llvm/ADT/BitmaskEnum.h"
  8. #include "toolchain/sem_ir/name_scope.h"
  9. namespace Carbon::Check {
  10. LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
  11. // The order of modifiers. Each of these corresponds to a group on
  12. // KeywordModifierSet, and can be used as an array index.
  13. enum class ModifierOrder : int8_t { Access, Extern, Extend, Decl, Last = Decl };
  14. // Represents a set of keyword modifiers, using a separate bit per modifier.
  15. class KeywordModifierSet {
  16. public:
  17. // Provide values as an enum. This doesn't expose these as KeywordModifierSet
  18. // instances just due to the duplication of declarations that would cause.
  19. //
  20. // We expect this to grow, so are using a bigger size than needed.
  21. // NOLINTNEXTLINE(performance-enum-size)
  22. enum RawEnumType : uint32_t {
  23. // At most one of these access modifiers allowed for a given declaration,
  24. // and if present it must be first:
  25. Private = 1 << 0,
  26. Protected = 1 << 1,
  27. // Extern is standalone.
  28. Extern = 1 << 2,
  29. // Extend can be combined with Final, but no others in the group below.
  30. Extend = 1 << 3,
  31. // At most one of these declaration modifiers allowed for a given
  32. // declaration:
  33. Abstract = 1 << 4,
  34. Base = 1 << 5,
  35. Default = 1 << 6,
  36. Export = 1 << 7,
  37. Final = 1 << 8,
  38. Impl = 1 << 9,
  39. Virtual = 1 << 10,
  40. Returned = 1 << 11,
  41. // Sets of modifiers:
  42. Access = Private | Protected,
  43. Class = Abstract | Base,
  44. Method = Abstract | Impl | Virtual,
  45. ImplDecl = Extend | Final,
  46. Interface = Default | Final,
  47. Decl = Class | Method | Impl | Interface | Export | Returned,
  48. None = 0,
  49. LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/Returned)
  50. };
  51. // Default construct to empty.
  52. explicit KeywordModifierSet() : set_(None) {}
  53. // Support implicit conversion so that the difference with the member enum is
  54. // opaque.
  55. // NOLINTNEXTLINE(google-explicit-constructor)
  56. constexpr KeywordModifierSet(RawEnumType set) : set_(set) {}
  57. // Adds entries to the set.
  58. auto Add(KeywordModifierSet set) -> void { set_ |= set.set_; }
  59. // Removes entries from the set.
  60. auto Remove(KeywordModifierSet set) -> void { set_ &= ~set.set_; }
  61. // Returns true if there's a non-empty set intersection.
  62. constexpr auto HasAnyOf(KeywordModifierSet other) const -> bool {
  63. return set_ & other.set_;
  64. }
  65. // Return a builder that returns the new enumeration type once a series of
  66. // mapping `Case`s and a final `Default` are provided. For example:
  67. // ```
  68. // auto e = set.ToEnum<SomeEnum>()
  69. // .Case(KeywordModifierSet::A, SomeEnum::A)
  70. // .Case(KeywordModifierSet::B, SomeEnum::B)
  71. // .Default(SomeEnum::DefaultValue);
  72. // ```
  73. template <typename T>
  74. auto ToEnum() const -> auto {
  75. class Converter {
  76. public:
  77. explicit Converter(const KeywordModifierSet& set) : set_(set) {}
  78. auto Case(RawEnumType raw_enumerator, T result) -> Converter& {
  79. if (set_.HasAnyOf(raw_enumerator)) {
  80. result_ = result;
  81. }
  82. return *this;
  83. }
  84. auto Default(T default_value) -> T {
  85. if (result_) {
  86. return *result_;
  87. }
  88. return default_value;
  89. }
  90. private:
  91. const KeywordModifierSet& set_;
  92. std::optional<T> result_;
  93. };
  94. return Converter(*this);
  95. }
  96. // Returns the access kind from modifiers.
  97. auto GetAccessKind() const -> SemIR::AccessKind {
  98. if (HasAnyOf(KeywordModifierSet::Protected)) {
  99. return SemIR::AccessKind::Protected;
  100. }
  101. if (HasAnyOf(KeywordModifierSet::Private)) {
  102. return SemIR::AccessKind::Private;
  103. }
  104. return SemIR::AccessKind::Public;
  105. }
  106. // Returns true if empty.
  107. constexpr auto empty() const -> bool { return !set_; }
  108. // Returns the set intersection.
  109. constexpr auto operator&(KeywordModifierSet other) const
  110. -> KeywordModifierSet {
  111. return set_ & other.set_;
  112. }
  113. // Returns the set inverse.
  114. auto operator~() const -> KeywordModifierSet { return ~set_; }
  115. private:
  116. RawEnumType set_;
  117. };
  118. static_assert(!KeywordModifierSet(KeywordModifierSet::Access)
  119. .HasAnyOf(KeywordModifierSet::Extern) &&
  120. !KeywordModifierSet(KeywordModifierSet::Access |
  121. KeywordModifierSet::Extern |
  122. KeywordModifierSet::Extend)
  123. .HasAnyOf(KeywordModifierSet::Decl),
  124. "Order-related sets must not overlap");
  125. static_assert(~KeywordModifierSet::None ==
  126. (KeywordModifierSet::Access | KeywordModifierSet::Extern |
  127. KeywordModifierSet::Extend | KeywordModifierSet::Decl),
  128. "Modifier missing from all modifier sets");
  129. } // namespace Carbon::Check
  130. #endif // CARBON_TOOLCHAIN_CHECK_KEYWORD_MODIFIER_SET_H_