blob: dc5c84f2a501799a5ac323cea1ff323698ea5dd7 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef TOOLS_FIDL_FIDLC_INCLUDE_FIDL_FLAT_NAME_H_
#define TOOLS_FIDL_FIDLC_INCLUDE_FIDL_FLAT_NAME_H_
#include <optional>
#include <string>
#include <string_view>
#include <variant>
#include "fidl/source_span.h"
namespace fidl {
namespace flat {
class Library;
// Name represents a named entry in a particular scope.
// Names have different flavors based on their origins, which can be determined by the discriminant
// `Name::Kind`. See the documentation for `Name::Kind` for details.
class Name final {
public:
// Helper type to use when looking up and comparing names. This may be useful for associative
// containers.
//
// Note that this type contains `std::string_view`s, so it must not outlive the strings its
// members reference.
class Key final {
public:
// Intentionally allow for implicit conversions from `Name`, as `Name` should be freely
// convertible to its `Key`.
//
// NOLINTNEXTLINE
Key(const Name& name)
: compare_context_(name.library(), name.decl_name(),
name.member_name().has_value()
? std::make_optional(std::string_view(name.member_name().value()))
: std::nullopt) {}
explicit Key(const Library* library, std::string_view decl_name)
: compare_context_(library, decl_name, std::nullopt) {}
explicit Key(const Library* library, std::string_view decl_name, std::string_view member_name)
: compare_context_(library, decl_name, member_name) {}
friend bool operator==(const Key& lhs, const Key& rhs) {
return lhs.compare_context_ == rhs.compare_context_;
}
friend bool operator!=(const Key& lhs, const Key& rhs) {
return lhs.compare_context_ != rhs.compare_context_;
}
friend bool operator<(const Key& lhs, const Key& rhs) {
return lhs.compare_context_ < rhs.compare_context_;
}
private:
using CompareContext =
std::tuple<const Library*, std::string_view, std::optional<std::string_view>>;
CompareContext compare_context_;
};
static Name CreateSourced(const Library* library, SourceSpan span) {
return Name(library, SourcedNameContext(span), std::nullopt);
}
static Name CreateSourced(const Library* library, SourceSpan span, std::string member_name) {
return Name(library, SourcedNameContext(span), member_name);
}
static Name CreateDerived(const Library* library, SourceSpan span, std::string name) {
return Name(library, DerivedNameContext(std::move(name), span), std::nullopt);
}
static Name CreateIntrinsic(std::string name) {
return Name(nullptr, IntrinsicNameContext(std::move(name)), std::nullopt);
}
Name(const Name& other) noexcept
: library_(other.library_),
name_context_(other.name_context_),
member_name_(other.member_name_) {}
Name(Name&& other) noexcept
: library_(other.library_),
name_context_(std::move(other.name_context_)),
member_name_(std::move(other.member_name_)) {
other.library_ = nullptr;
other.name_context_ = std::monostate();
}
Name& operator=(const Name& other) noexcept {
if (&other == this) {
return *this;
}
library_ = other.library_;
name_context_ = other.name_context_;
return *this;
}
Name& operator=(Name&& other) noexcept {
if (&other == this) {
return *this;
}
library_ = other.library_;
other.library_ = nullptr;
name_context_ = std::move(other.name_context_);
other.name_context_ = std::monostate();
return *this;
}
const Library* library() const { return library_; }
std::optional<SourceSpan> span() const {
return std::visit(
[](auto&& name_context) -> std::optional<SourceSpan> {
using T = std::decay_t<decltype(name_context)>;
if constexpr (std::is_same_v<T, SourcedNameContext>) {
return std::optional(name_context.span);
} else if constexpr (std::is_same_v<T, DerivedNameContext>) {
return std::optional(name_context.span);
} else if constexpr (std::is_same_v<T, IntrinsicNameContext>) {
return std::nullopt;
} else {
abort();
}
},
name_context_);
}
std::string_view decl_name() const {
return std::visit(
[](auto&& name_context) -> std::string_view {
using T = std::decay_t<decltype(name_context)>;
if constexpr (std::is_same_v<T, SourcedNameContext>) {
return name_context.span.data();
} else if constexpr (std::is_same_v<T, DerivedNameContext>) {
return std::string_view(name_context.name);
} else if constexpr (std::is_same_v<T, IntrinsicNameContext>) {
return std::string_view(name_context.name);
} else {
abort();
}
},
name_context_);
}
std::string full_name() const {
auto name = std::string(decl_name());
if (member_name_.has_value()) {
constexpr std::string_view kSeparator = ".";
name.reserve(name.size() + kSeparator.size() + member_name_.value().size());
name.append(kSeparator);
name.append(member_name_.value());
}
return name;
}
const std::optional<std::string>& member_name() const { return member_name_; }
Key memberless_key() const { return Key(library_, decl_name()); }
Key key() const { return Key(*this); }
friend bool operator==(const Name& lhs, const Name& rhs) { return lhs.key() == rhs.key(); }
friend bool operator!=(const Name& lhs, const Name& rhs) { return lhs.key() != rhs.key(); }
friend bool operator<(const Name& lhs, const Name& rhs) { return lhs.key() < rhs.key(); }
private:
struct SourcedNameContext {
explicit SourcedNameContext(SourceSpan span) : span(span) {}
// The span of the name.
SourceSpan span;
};
struct DerivedNameContext {
explicit DerivedNameContext(std::string name, SourceSpan span)
: name(std::move(name)), span(span) {}
// The derived name.
std::string name;
// The span from which the name was derived.
SourceSpan span;
};
struct IntrinsicNameContext {
explicit IntrinsicNameContext(std::string name) : name(std::move(name)) {}
// The intrinsic name.
std::string name;
};
Name(const Library* library, SourcedNameContext name_context,
std::optional<std::string> member_name)
: library_(library),
name_context_(std::move(name_context)),
member_name_(std::move(member_name)) {}
Name(const Library* library, DerivedNameContext name_context,
std::optional<std::string> member_name)
: library_(library),
name_context_(std::move(name_context)),
member_name_(std::move(member_name)) {}
Name(const Library* library, IntrinsicNameContext name_context,
std::optional<std::string> member_name)
: library_(library),
name_context_(std::move(name_context)),
member_name_(std::move(member_name)) {}
const Library* library_;
std::variant<std::monostate, SourcedNameContext, DerivedNameContext, IntrinsicNameContext>
name_context_;
std::optional<std::string> member_name_;
};
} // namespace flat
} // namespace fidl
#endif // TOOLS_FIDL_FIDLC_INCLUDE_FIDL_FLAT_NAME_H_