910e62b5创建于 1月15日历史提交
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef UI_BASE_METADATA_METADATA_MACROS_INTERNAL_H_
#define UI_BASE_METADATA_METADATA_MACROS_INTERNAL_H_

#include <string>
#include <string_view>
#include <utility>

#include "ui/base/metadata/metadata_types.h"
#include "ui/base/metadata/property_metadata.h"

// Internal Metadata Generation Helpers ---------------------------------------

#define METADATA_CLASS_NAME_INTERNAL(class_name) class_name##_MetaData

// TODO(kylixrd@): Remove kViewClassName[] from macros once all references to it
// have been eradicated and IsViewClass<T> is being used instead.

// Metadata Accessors ---------------------------------------------------------
#define METADATA_ACCESSORS_INTERNAL(class_name)        \
  using kMetadataTag = class_name;                     \
  [[maybe_unused]] static const char kViewClassName[]; \
  static ui::metadata::ClassMetaData* MetaData();      \
  /* Don't hide non-const base class version. */       \
  using MetaDataProvider::GetClassMetaData;            \
  const ui::metadata::ClassMetaData* GetClassMetaData() const override;

#define METADATA_ACCESSORS_INTERNAL_TEMPLATE(class_name)                       \
  using kMetadataTag = class_name;                                             \
  [[maybe_unused]] static const char kViewClassName[];                         \
  static ui::metadata::ClassMetaData* MetaData() {                             \
    if (!METADATA_CLASS_NAME_INTERNAL(class_name)::meta_data_) {               \
      METADATA_CLASS_NAME_INTERNAL(class_name)::meta_data_ =                   \
          ui::metadata::MakeAndRegisterClassInfo<METADATA_CLASS_NAME_INTERNAL( \
              class_name)>();                                                  \
    }                                                                          \
    return METADATA_CLASS_NAME_INTERNAL(class_name)::meta_data_;               \
  }                                                                            \
  /* Don't hide non-const base class version. */                               \
  using ui::metadata::MetaDataProvider::GetClassMetaData;                      \
  const ui::metadata::ClassMetaData* GetClassMetaData() const override {       \
    return MetaData();                                                         \
  }

// A version of METADATA_ACCESSORS_INTERNAL for View, the root of the metadata
// hierarchy; here GetClassName() is not declared as an override.
//
// This also introduces the ReinterpretToBaseClass(), which should exist at the
// root of the hierarchy on which the metadata will be attached. This will take
// the given void*, which should be some instance of a subclass of this base
// class, and return a properly typed class_name*. The body of this function
// does a reinterpret_cast<> of the void* to obtain a class_name*. Doing a
// direct static_cast<> from the void* may result in an incorrect
// pointer-to-instance, which may cause a crash. Using this intermediate step of
// reinterpret_cast<> provides more information to the compiler in order to
// obtain the proper result from the static_cast<>. See |AsClass(void* obj)|
// in property_metadata.h for additional info.
#define METADATA_ACCESSORS_INTERNAL_BASE(class_name)   \
  using kMetadataTag = class_name;                     \
  [[maybe_unused]] static const char kViewClassName[]; \
  std::string_view GetClassName() const;               \
  static ui::metadata::ClassMetaData* MetaData();      \
  class_name* ReinterpretToBaseClass(void* obj);       \
  /* Don't hide non-const base class version. */       \
  using MetaDataProvider::GetClassMetaData;            \
  const ui::metadata::ClassMetaData* GetClassMetaData() const override;

// Metadata Class -------------------------------------------------------------
#define METADATA_CLASS_INTERNAL(class_name, file, line)              \
  class METADATA_CLASS_NAME_INTERNAL(class_name)                     \
      : public ui::metadata::ClassMetaData {                         \
   public:                                                           \
    using TheClass = class_name;                                     \
    explicit METADATA_CLASS_NAME_INTERNAL(class_name)()              \
        : ClassMetaData(file, line) {                                \
      BuildMetaData();                                               \
    }                                                                \
    METADATA_CLASS_NAME_INTERNAL(class_name)                         \
    (const METADATA_CLASS_NAME_INTERNAL(class_name) &) = delete;     \
    METADATA_CLASS_NAME_INTERNAL(class_name) & operator=(            \
        const METADATA_CLASS_NAME_INTERNAL(class_name) &) = delete;  \
                                                                     \
   private:                                                          \
    friend class class_name;                                         \
    void BuildMetaData();                                            \
    [[maybe_unused]] static ui::metadata::ClassMetaData* meta_data_; \
  }

#define METADATA_CLASS_INTERNAL_TEMPLATE(class_name, file, line)     \
  class METADATA_CLASS_NAME_INTERNAL(class_name)                     \
      : public ui::metadata::ClassMetaData {                         \
   public:                                                           \
    using TheClass = class_name;                                     \
    explicit METADATA_CLASS_NAME_INTERNAL(class_name)()              \
        : ClassMetaData(file, line) {                                \
      BuildMetaData();                                               \
    }                                                                \
    METADATA_CLASS_NAME_INTERNAL(class_name)                         \
    (const METADATA_CLASS_NAME_INTERNAL(class_name) &) = delete;     \
    METADATA_CLASS_NAME_INTERNAL(class_name) & operator=(            \
        const METADATA_CLASS_NAME_INTERNAL(class_name) &) = delete;  \
                                                                     \
   private:                                                          \
    friend class class_name;                                         \
    void BuildMetaData();                                            \
    [[maybe_unused]] static ui::metadata::ClassMetaData* meta_data_; \
  }

#define METADATA_PROPERTY_TYPE_INTERNAL(property_type, property_name, ...) \
  ui::metadata::ObjectPropertyMetaData<                                    \
      TheClass, property_type, decltype(&TheClass::Set##property_name),    \
      &TheClass::Set##property_name,                                       \
      decltype(std::declval<TheClass>().Get##property_name()),             \
      &TheClass::Get##property_name, ##__VA_ARGS__>

#define METADATA_READONLY_PROPERTY_TYPE_INTERNAL(property_type, property_name, \
                                                 ...)                          \
  ui::metadata::ObjectPropertyReadOnlyMetaData<                                \
      TheClass, property_type,                                                 \
      decltype(std::declval<TheClass>().Get##property_name()),                 \
      &TheClass::Get##property_name, ##__VA_ARGS__>

#define METADATA_CLASS_PROPERTY_TYPE_INTERNAL(property_type, property_key, \
                                              ...)                         \
  ui::metadata::ClassPropertyMetaData<TheClass, decltype(property_key),    \
                                      property_type, ##__VA_ARGS__>

#define BEGIN_METADATA_INTERNAL(qualified_class_name, metadata_class_name,    \
                                parent_class_name)                            \
  ui::metadata::ClassMetaData*                                                \
      qualified_class_name::metadata_class_name::meta_data_ = nullptr;        \
                                                                              \
  ui::metadata::ClassMetaData* qualified_class_name::MetaData() {             \
    static_assert(std::is_base_of_v<parent_class_name, qualified_class_name>, \
                  "class not child of parent");                               \
    if (!qualified_class_name::metadata_class_name::meta_data_) {             \
      qualified_class_name::metadata_class_name::meta_data_ =                 \
          ui::metadata::MakeAndRegisterClassInfo<                             \
              qualified_class_name::metadata_class_name>();                   \
    }                                                                         \
    return qualified_class_name::metadata_class_name::meta_data_;             \
  }                                                                           \
                                                                              \
  const ui::metadata::ClassMetaData* qualified_class_name::GetClassMetaData() \
      const {                                                                 \
    return MetaData();                                                        \
  }                                                                           \
                                                                              \
  const char qualified_class_name::kViewClassName[] = #qualified_class_name;  \
                                                                              \
  void qualified_class_name::metadata_class_name::BuildMetaData() {           \
    SetTypeName(#qualified_class_name);

#define BEGIN_TEMPLATE_METADATA_INTERNAL(qualified_class_name,               \
                                         metadata_class_name)                \
  template <>                                                                \
  ui::metadata::ClassMetaData*                                               \
      qualified_class_name::metadata_class_name::meta_data_ = nullptr;       \
                                                                             \
  template <>                                                                \
  const char qualified_class_name::kViewClassName[] = #qualified_class_name; \
                                                                             \
  template <>                                                                \
  void qualified_class_name::metadata_class_name::BuildMetaData() {          \
    SetTypeName(#qualified_class_name);                                      \
    SetParentClassMetaData(kAncestorClass::MetaData());

#define BEGIN_METADATA_INTERNAL_BASE(qualified_class_name,                   \
                                     metadata_class_name, parent_class_name) \
  std::string_view qualified_class_name::GetClassName() const {              \
    return GetClassMetaData()->type_name();                                  \
  }                                                                          \
                                                                             \
  BEGIN_METADATA_INTERNAL(qualified_class_name, metadata_class_name,         \
                          parent_class_name)

// See the comment above on the METADATA_ACCESSORS_INTERNAL_BASE macro for more
// information. NOTE: This function should not be modified to access |this|,
// directly or indirectly. It should only do what is necessary to convert |obj|
// to a properly typed pointer.
#define METADATA_REINTERPRET_BASE_CLASS_INTERNAL(qualified_class_name, \
                                                 metadata_class_name)  \
  qualified_class_name* qualified_class_name::ReinterpretToBaseClass(  \
      void* obj) {                                                     \
    return reinterpret_cast<qualified_class_name*>(obj);               \
  }

#define METADATA_PARENT_CLASS_INTERNAL(parent_class_name) \
  SetParentClassMetaData(parent_class_name::MetaData());

#define DECLARE_TEMPLATE_METADATA_INTERNAL(qualified_class_name, \
                                           metadata_class_name)  \
  template <>                                                    \
  ui::metadata::ClassMetaData*                                   \
      qualified_class_name::metadata_class_name::meta_data_

#endif  // UI_BASE_METADATA_METADATA_MACROS_INTERNAL_H_