blob: 00e10523a86d1d36347db09c6e105b1fd47f520e [file]
// Protocol Buffers - Google's data interchange format
// Copyright 2025 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
// This file contains the SymbolChecker class which is used to enforce
// visibility rules within a FileDescriptor.
//
// The SymbolChecker is used to validate that a FileDescriptor is compatible
// with the rules of the protobuf symbol visibility specifications. When
// enabled these rules are used to ensure FileDescriptors are narrowly scoped.
#ifndef GOOGLE_PROTOBUF_SYMBOL_CHECKER_H__
#define GOOGLE_PROTOBUF_SYMBOL_CHECKER_H__
#include <string>
#include <vector>
#include "absl/strings/string_view.h"
// Must be included last.
#include "google/protobuf/port_def.inc"
namespace google {
namespace protobuf {
// Forward Declare Mesasge and Descriptor types.
class Message;
class Descriptor;
class DescriptorProto;
class FileDescriptor;
class FileDescriptorProto;
class EnumDescriptor;
class EnumDescriptorProto;
enum SymbolCheckerErrorType {
// A nested message was marked 'export' while using STRICT visibility.
NESTED_MESSAGE_STRICT_VIOLATION,
// A nested enum was marked 'export' while using STRICT visibility.
NESTED_ENUM_STRICT_VIOLATION,
};
// A single error generated from the SymbolChecker methods.
class SymbolCheckerError {
public:
SymbolCheckerError(absl::string_view symbol_name, const Message& descriptor,
SymbolCheckerErrorType type)
: symbol_name_(symbol_name), descriptor_(descriptor), type_(type) {}
absl::string_view symbol_name() const { return symbol_name_; }
const Message* descriptor() const { return &descriptor_; }
SymbolCheckerErrorType type() const { return type_; }
std::string message() const;
private:
absl::string_view symbol_name_;
const Message& descriptor_;
SymbolCheckerErrorType type_;
};
namespace internal {
// Pair for symbol type and its proto.
template <typename DescriptorT, typename DescriptorProtoT>
struct DescriptorAndProto {
const DescriptorT* descriptor;
const DescriptorProtoT* proto;
};
// Internal State used for checking symbol visibility rules.
typedef DescriptorAndProto<Descriptor, DescriptorProto>
MessageDescriptorAndProto;
typedef DescriptorAndProto<EnumDescriptor, EnumDescriptorProto>
EnumDescriptorAndProto;
// Internal State for SymbolChecker kept out of public API.
struct SymbolCheckerState {
std::vector<MessageDescriptorAndProto> nested_messages;
std::vector<EnumDescriptorAndProto> nested_enums;
// Enums that are considered 'namespaced' by IsEnumNamespaceMessage
std::vector<EnumDescriptorAndProto> namespaced_enums;
};
} // namespace internal
// Container for visibility checking state. This class is NOT thread-safe,
// concurrent calls to Initialize will result in undefined behavior.
//
// This should not be considered public API and is intended for internal tooling
// and CLI access only.
class PROTOBUF_EXPORT SymbolChecker {
public:
SymbolChecker(const FileDescriptor* file, const FileDescriptorProto& proto);
SymbolChecker(const SymbolChecker&) = delete;
SymbolChecker& operator=(const SymbolChecker&) = delete;
~SymbolChecker() = default;
// Returns true iff the message is a pure zero field message used only for
// Enum namespacing. AKA it is:
// * top-level
// * visibility local either explicitly or by file default
// * has reserved range of 1 to max.
// Example:
// local message Foo {
// export enum Type {
// TYPE_UNSPECIFIED = 0;
// }
// reserved 1 to max;
// }
PROTOBUF_FUTURE_ADD_EARLY_NODISCARD static bool IsEnumNamespaceMessage(
const Descriptor& container);
// Returns true iff the enum is a namespaced enum. This is an enum that is
// nested within a message that is considered an 'EnumNamespaceMessage' as
// defined above. IsEnumNamespaceMessage must return true for the enums
// container message.
PROTOBUF_FUTURE_ADD_EARLY_NODISCARD static bool IsNamespacedEnum(
const EnumDescriptor& enm);
// Return a list of errors identified in the given FileDescriptor/proto w.r.t
// to SymbolChecking visibility.
PROTOBUF_FUTURE_ADD_EARLY_NODISCARD std::vector<SymbolCheckerError>
CheckSymbolVisibilityRules();
private:
void Initialize();
bool initialized_;
const FileDescriptor* descriptor_;
const FileDescriptorProto& proto_;
internal::SymbolCheckerState state_;
};
} // namespace protobuf
} // namespace google
#include "google/protobuf/port_undef.inc"
#endif // GOOGLE_PROTOBUF_SYMBOL_CHECKER_H__