blob: 2781d3926753a38013902553fd0a2c10ca645ce7 [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 SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_INHERITANCE_PATH_H_
#define SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_INHERITANCE_PATH_H_
#include <initializer_list>
#include <vector>
#include "src/developer/debug/zxdb/symbols/collection.h"
#include "src/developer/debug/zxdb/symbols/inherited_from.h"
namespace zxdb {
// Represents a path of inheritance from one class to another.
//
// When one class derives from another, the base classes become effectively a member of the derived
// class. This represents a chain of such inheritance.
//
// Virtual inheritance makes things more complicated. When there is virtual inheritance, a base
// class doesn't live at a predefined offset but rather the compiler stores some way to find the
// base class. This allows the offset to vary according to what the current object hierarchy looks
// like. In this case, there is a DWARF express that must be evaluated that reads class memory to
// compute the offset.
//
// Virtual inheritance is uncommon so most hierarchies can be represented by a simple offset of one
// class within another.
class InheritancePath {
public:
struct Step {
// Use for the 0th entry which has no "from".
Step(fxl::RefPtr<Collection> c) : from(), collection(std::move(c)) {}
// Use for normal steps.
Step(fxl::RefPtr<InheritedFrom> f, fxl::RefPtr<Collection> c)
: from(std::move(f)), collection(std::move(c)) {}
// How to get to the current Step in the vector from the previous (n-1) item in the vector.
// This will be null for path()[0] because it's the start of the inheritance path.
fxl::RefPtr<InheritedFrom> from;
// The collection at this step of the hierarchy.
fxl::RefPtr<Collection> collection;
// Comparison, based on object pointer equality. This is primarily for unit tests.
bool operator==(const Step& other) const {
return from.get() == other.from.get() && collection.get() == other.collection.get();
}
bool operator!=(const Step& other) const { return !operator==(other); }
};
using PathVector = std::vector<Step>;
InheritancePath() = default;
// To just supply one class and not inhertance information.
explicit InheritancePath(fxl::RefPtr<Collection> collection) { path_.emplace_back(collection); }
// Encodes a single level of inheritance from "derived" to "base".
InheritancePath(fxl::RefPtr<Collection> derived, fxl::RefPtr<InheritedFrom> from,
fxl::RefPtr<Collection> base);
// For a full path.
InheritancePath(std::initializer_list<Step> steps) : path_(steps) {}
// If possible, returns the offset of the oldest base class "path().back()" from the derived class
// "path()[0]". As described in the class-level comment above, this will work as long as there is
// no virtual inheritance. If there is virtual inheritance, this will return nullopt.
std::optional<uint32_t> BaseOffsetInDerived() const;
// The inheritance path. The derived class will be at path().front() and the derived class will be
// at path().back(). The intermediate classes to get from one to the other will be sequenced
// in-between:
//
// ( Derived class = path[0].collection ) ----( path[1].from )----
// ( Intermediate class = path[1].collection ) ----( path[2].from )----
// ( Base class = path[2].collection )
PathVector& path() { return path_; }
const PathVector& path() const { return path_; }
// Extracts a subset of the inheritance path.
static constexpr size_t kToEnd = static_cast<size_t>(-1);
InheritancePath SubPath(size_t begin_index, size_t len = kToEnd) const;
// The "derived" is the more specific end (the one deriving from the other classes).
const Collection* derived() const { return path_.front().collection.get(); }
const fxl::RefPtr<Collection> derived_ref() const { return path_.front().collection; }
// The "base" is the base class of derived that this path represents.
//
// Note that in some cases that may not be a concrete type and you will have to convert it to one
// before using.
const Collection* base() const { return path_.back().collection.get(); }
const fxl::RefPtr<Collection> base_ref() const { return path_.back().collection; }
bool operator==(const InheritancePath& other) const { return path_ == other.path_; }
bool operator!=(const InheritancePath& other) const { return !operator==(other); }
public:
PathVector path_;
};
} // namespace zxdb
#endif // SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_INHERITANCE_PATH_H_