File indexing completed on 2024-05-05 16:46:04

0001 /*
0002     SPDX-FileCopyrightText: 2010, 2015 Alex Richardson <alex.richardson@gmx.de>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-or-later
0005 */
0006 
0007 #pragma once
0008 
0009 #include <QString>
0010 #include <QIcon>
0011 #include <memory>
0012 
0013 #include <language/duchain/duchain.h>
0014 #include <language/duchain/duchainbase.h>
0015 #include <language/duchain/duchainlock.h>
0016 #include <language/duchain/duchainpointer.h>
0017 
0018 
0019 namespace KDevelop {
0020 class Declaration;
0021 class DUContext;
0022 }
0023 
0024 class OutlineNode
0025 {
0026     Q_DISABLE_COPY(OutlineNode)
0027     void appendContext(KDevelop::DUContext* ctx, KDevelop::TopDUContext* top);
0028     void sortByLocation(bool requiresSorting);
0029 public:
0030     OutlineNode(const QString& text, OutlineNode* parent);
0031     OutlineNode(OutlineNode&& other) Q_DECL_NOEXCEPT;
0032     OutlineNode& operator=(OutlineNode&& other) Q_DECL_NOEXCEPT;
0033     OutlineNode(KDevelop::Declaration* decl, OutlineNode* parent);
0034     OutlineNode(KDevelop::DUContext* ctx, const QString& name, OutlineNode* parent);
0035     virtual ~OutlineNode();
0036     QIcon icon() const;
0037     QString text() const;
0038     const OutlineNode* parent() const;
0039     const std::vector<OutlineNode>& children() const;
0040     int childCount() const;
0041     const OutlineNode* childAt(int index) const;
0042     int indexOf(const OutlineNode* child) const;
0043     static std::unique_ptr<OutlineNode> fromTopContext(KDevelop::TopDUContext* ctx);
0044     static std::unique_ptr<OutlineNode> dummyNode();
0045     KDevelop::DUChainBase* duChainObject() const;
0046     friend void swap(OutlineNode& n1, OutlineNode& n2);
0047 private:
0048     QString m_cachedText;
0049     QIcon m_cachedIcon;
0050     KDevelop::DUChainBasePointer m_declOrContext;
0051     OutlineNode* m_parent;
0052     std::vector<OutlineNode> m_children;
0053 };
0054 
0055 inline int OutlineNode::childCount() const
0056 {
0057     return static_cast<int>(m_children.size());
0058 }
0059 
0060 inline const std::vector<OutlineNode>& OutlineNode::children() const
0061 {
0062     return m_children;
0063 }
0064 
0065 inline const OutlineNode* OutlineNode::childAt(int index) const
0066 {
0067     return &m_children.at(index);
0068 }
0069 
0070 inline const OutlineNode* OutlineNode::parent() const
0071 {
0072     return m_parent;
0073 }
0074 
0075 inline int OutlineNode::indexOf(const OutlineNode* child) const
0076 {
0077     const auto max = m_children.size();
0078     // Comparing the address here is only fine since we never modify the vector after initial creation
0079     for (size_t i = 0; i < max; i++) {
0080         if (child == &m_children[i]) {
0081             return static_cast<int>(i);
0082         }
0083     }
0084     return -1;
0085 }
0086 
0087 inline QIcon OutlineNode::icon() const
0088 {
0089     return m_cachedIcon;
0090 }
0091 
0092 inline QString OutlineNode::text() const
0093 {
0094     return m_cachedText;
0095 }
0096 
0097 inline KDevelop::DUChainBase* OutlineNode::duChainObject() const
0098 {
0099     ENSURE_CHAIN_READ_LOCKED
0100     return m_declOrContext.data();
0101 }
0102 
0103 
0104 inline OutlineNode::OutlineNode(OutlineNode&& other) Q_DECL_NOEXCEPT
0105     : m_cachedText(std::move(other.m_cachedText))
0106     , m_cachedIcon(std::move(other.m_cachedIcon))
0107     , m_declOrContext(std::move(other.m_declOrContext))
0108     , m_parent(std::move(other.m_parent))
0109     , m_children(std::move(other.m_children))
0110 {
0111     // qDebug("Move ctor %p -> %p", &other, this);
0112     other.m_parent = nullptr;
0113     other.m_declOrContext = nullptr;
0114     for (OutlineNode& child : m_children) {
0115         // when we are moved the parent pointer has to be updated for the children!
0116         child.m_parent = this;
0117     }
0118 }
0119 
0120 inline OutlineNode& OutlineNode::operator=(OutlineNode&& other) Q_DECL_NOEXCEPT
0121 {
0122     if (this == &other) {
0123         return *this;
0124     }
0125     m_cachedText = std::move(other.m_cachedText);
0126     m_cachedIcon = std::move(other.m_cachedIcon);
0127     m_declOrContext = std::move(other.m_declOrContext);
0128     m_parent = std::move(other.m_parent);
0129     m_children = std::move(other.m_children);
0130     // qDebug("Move assignment %p -> %p", &other, this);
0131     other.m_parent = nullptr;
0132     other.m_declOrContext = nullptr;
0133     for (OutlineNode& child : m_children) {
0134         // when we are moved the parent pointer has to be updated for the children!
0135         child.m_parent = this;
0136     }
0137     return *this;
0138 }
0139 
0140 inline void swap(OutlineNode& n1, OutlineNode& n2)
0141 {
0142     // For some reason std::sort only sometimes calls swap and mostly uses move ctor + assign.
0143     // Probably it uses different algorithms for different sequence sizes
0144     // qDebug("Swapping %p and %p", &n1, &n2);
0145     std::swap(n1.m_cachedText, n2.m_cachedText);
0146     std::swap(n1.m_cachedIcon, n2.m_cachedIcon);
0147     std::swap(n1.m_declOrContext, n2.m_declOrContext);
0148     std::swap(n1.m_parent, n2.m_parent);
0149     std::swap(n1.m_children, n2.m_children);
0150 }