| 183 | } |
| 184 | |
| 185 | void OutlineNode::appendContext(DUContext* ctx, TopDUContext* top) |
| 186 | { |
| 187 | // qDebug() << ctx->scopeIdentifier().toString() << "context type=" << ctx->type(); |
| 188 | const auto childDecls = ctx->localDeclarations(top); |
| 189 | for (Declaration* childDecl : childDecls) { |
| 190 | if (childDecl) { |
| 191 | m_children.emplace_back(childDecl, this); |
| 192 | } |
| 193 | } |
| 194 | bool certainlyRequiresSorting = false; |
| 195 | const auto childContexts = ctx->childContexts(); |
| 196 | for (DUContext* childContext : childContexts) { |
| 197 | if (childContext->owner()) { |
| 198 | // if there is a onwner, this will already have been handled by the loop above |
| 199 | // TODO: is this always true? With my testing so far it seems to be |
| 200 | // qDebug() << childContext->scopeIdentifier(true).toString() |
| 201 | // << " has an owner declaration: " << childContext->owner()->toString() << "-> skip"; |
| 202 | continue; |
| 203 | } |
| 204 | QVector<Declaration*> decls = childContext->localDeclarations(top); |
| 205 | if (decls.isEmpty()) { |
| 206 | continue; |
| 207 | } |
| 208 | // we now know that we will have o sort since we appended a node in the wrong order |
| 209 | certainlyRequiresSorting = true; |
| 210 | QString ctxName = childContext->scopeIdentifier(true).toString(); |
| 211 | // if child context is a template context or if name is empty append to current list, |
| 212 | // otherwise create a new context node |
| 213 | if (childContext->type() == DUContext::Template || ctxName.isEmpty()) { |
| 214 | //append all subcontexts to this node |
| 215 | appendContext(childContext, top); |
| 216 | } else { |
| 217 | // context without matching declaration, for example the definition of |
| 218 | // "class Foo::Bar if it was forward declared in a namespace before: |
| 219 | // namespace Foo { class Bar; } |
| 220 | // class Foo::Bar { ... }; |
| 221 | // TODO: icon and location for the namespace |
| 222 | if (childContext->type() == DUContext::ContextType::Helper) { |
| 223 | // This context could be for a definition of an existing class method. |
| 224 | // If we don't merge all those context end up with a tree like this: |
| 225 | // +-+- FooClass |
| 226 | // | \-- method1() |
| 227 | // +-+- FooClass |
| 228 | // | \-- method2() |
| 229 | // \ OtherStuff |
| 230 | auto it = std::find_if(m_children.begin(), m_children.end(), [childContext](const OutlineNode& node) { |
| 231 | if (auto* ctx = dynamic_cast<DUContext*>(node.duChainObject())) { |
| 232 | return ctx->equalScopeIdentifier(childContext); |
| 233 | } |
| 234 | return false; |
| 235 | }); |
| 236 | if (it != m_children.end()) { |
| 237 | it->appendContext(childContext, top); |
| 238 | } |
| 239 | else { |
| 240 | // TODO: get the correct icon for the context |
| 241 | m_children.emplace_back(childContext, ctxName, this); |
| 242 | } |
no test coverage detected