| // 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_ |