diff --git a/duchain/astredux.h b/duchain/astredux.h index 39aad79..2a4168f 100644 --- a/duchain/astredux.h +++ b/duchain/astredux.h @@ -1,67 +1,68 @@ #ifndef ASTREDUX_H #define ASTREDUX_H extern "C" { enum RSNodeKind { Crate, StructDecl, EnumDecl, TraitDecl, ImplDecl, TypeAliasDecl, FieldDecl, EnumVariantDecl, FunctionDecl, ParmDecl, VarDecl, Path, PathSegment, Unexposed }; enum RSVisitResult { Break, Continue, Recurse }; struct RSLocation { int line; int column; }; struct RSRange { RSLocation start; RSLocation end; }; struct RSCrate; struct RSNode; typedef RSVisitResult (*CallbackFn)(RSNode *node, RSNode *parent, void *data); RSCrate *parse_crate(const char *name, const char *source); void destroy_crate(RSCrate *crate); RSNode *node_from_crate(RSCrate *crate); void destroy_node(RSNode *node); +unsigned int node_get_id(RSNode *node); RSCrate *node_get_crate(RSNode *node); RSNodeKind node_get_kind(RSNode *node); const char *node_get_spelling_name(RSNode *node); RSRange node_get_spelling_range(RSNode *node); RSRange node_get_extent(RSNode *node); void destroy_string(const char *str); void visit_children(RSNode *node, CallbackFn callback, void *data); } #endif // ASTREDUX_H diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index 7effd67..5b34207 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -1,93 +1,109 @@ #include "contextbuilder.h" #include #include #include #include "rustducontext.h" #include "nodetraits.h" namespace Rust { RSVisitResult visitCallback(RSNode *node, RSNode *parent, void *data); void ContextBuilder::setParseSession(ParseSession *session) { this->session = session; } RangeInRevision ContextBuilder::editorFindSpellingRange(RustNode *node, const QString &identifier) { RSRange range = node_get_spelling_range(node->data()); KTextEditor::Range incorrectRange = KTextEditor::Range(range.start.line - 1, range.start.column, INT_MAX, INT_MAX); IDocument *document = ICore::self()->documentController() ->documentForUrl(topContext()->url().toUrl()); QVector ranges; if (document) { ranges = document->textDocument()->searchText(incorrectRange, identifier); } else { ranges = { KTextEditor::Range::invalid() }; } return RangeInRevision::castFromSimpleRange(ranges.first()); } +RSVisitResult ContextBuilder::visitNode(RustNode *node, RustNode *parent) +{ + Q_UNUSED(parent); + RustPath name(node); + RSNodeKind kind = node_get_kind(node->data()); + bool hasContext = NodeTraits::hasContext(kind); + + if (hasContext) { + openContext(node, NodeTraits::contextType(kind), &name); + visitChildren(node); + closeContext(); + return Continue; + } + return Recurse; +} + void ContextBuilder::visitChildren(RustNode *node) { visit_children(node->data(), visitCallback, this); } void ContextBuilder::startVisiting(RustNode *node) { visitChildren(node); } void ContextBuilder::setContextOnNode(RustNode *node, KDevelop::DUContext *context) { session->setContextOnNode(node, context); } KDevelop::DUContext *ContextBuilder::contextFromNode(RustNode *node) { return session->contextFromNode(node); } KDevelop::RangeInRevision ContextBuilder::editorFindRange(RustNode *fromNode, RustNode *toNode) { RSRange fromRange = node_get_extent(fromNode->data()); RSRange toRange = node_get_extent(toNode->data()); return RangeInRevision(fromRange.start.line - 1, fromRange.start.column, toRange.end.line - 1, toRange.end.column); } KDevelop::QualifiedIdentifier ContextBuilder::identifierForNode(RustPath *node) { return QualifiedIdentifier(node->value); } KDevelop::DUContext *ContextBuilder::newContext(const KDevelop::RangeInRevision &range) { return new RustNormalDUContext(range, currentContext()); } KDevelop::TopDUContext *ContextBuilder::newTopContext(const KDevelop::RangeInRevision &range, KDevelop::ParsingEnvironmentFile *file) { if (!file) { file = new ParsingEnvironmentFile(document()); file->setLanguage(IndexedString("Rust")); } return new RustTopDUContext(document(), range, file); } RSVisitResult visitCallback(RSNode *node, RSNode *parent, void *data) { ContextBuilder *builder = static_cast(data); RustNode currentNode(node); RustNode parentNode(parent); return builder->visitNode(¤tNode, &parentNode); } } diff --git a/duchain/contextbuilder.h b/duchain/contextbuilder.h index a4a1782..fd9c075 100644 --- a/duchain/contextbuilder.h +++ b/duchain/contextbuilder.h @@ -1,47 +1,47 @@ #ifndef CONTEXTBUILDER_H #define CONTEXTBUILDER_H #include #include "rustnode.h" #include "parsesession.h" namespace Rust { using ContextBuilderBase = KDevelop::AbstractContextBuilder; class ContextBuilder : public ContextBuilderBase { public: ContextBuilder() = default; ~ContextBuilder() override = default; void setParseSession(ParseSession *session); protected: KDevelop::RangeInRevision editorFindSpellingRange(RustNode *node, const QString &identifier); template KDevelop::DUContext *createContext(RSNode *node, const KDevelop::QualifiedIdentifier& scopeId); - virtual RSVisitResult visitNode(RustNode *node, RustNode *parent) = 0; + virtual RSVisitResult visitNode(RustNode *node, RustNode *parent); void visitChildren(RustNode *node); void startVisiting(RustNode *node) override; void setContextOnNode(RustNode *node, KDevelop::DUContext *context) override; KDevelop::DUContext *contextFromNode(RustNode *node) override; KDevelop::RangeInRevision editorFindRange(RustNode *fromNode, RustNode *toNode) override; KDevelop::QualifiedIdentifier identifierForNode(RustPath *node) override; KDevelop::DUContext *newContext(const KDevelop::RangeInRevision &range) override; KDevelop::TopDUContext *newTopContext(const KDevelop::RangeInRevision &range, KDevelop::ParsingEnvironmentFile *file) override; private: friend RSVisitResult visitCallback(RSNode *node, RSNode *parent, void *data); ParseSession *session; }; } #endif // CONTEXTBUILDER_H diff --git a/duchain/parsesession.cpp b/duchain/parsesession.cpp index b51eb9d..3ef5013 100644 --- a/duchain/parsesession.cpp +++ b/duchain/parsesession.cpp @@ -1,70 +1,70 @@ #include "parsesession.h" namespace Rust { ParseSessionData::ParseSessionData(const KDevelop::IndexedString &document, const QByteArray &contents) : m_document(document), m_contents(contents), m_crate(nullptr) { } ParseSessionData::~ParseSessionData() { if (m_crate != nullptr) { destroy_crate(m_crate); } } void ParseSessionData::parse() { m_crate = parse_crate(m_document.c_str(), m_contents); } ParseSession::ParseSession(const ParseSessionData::Ptr &data) : d(data) { } ParseSession::~ParseSession() { } void ParseSession::parse() { d->parse(); } ParseSessionData::Ptr ParseSession::data() const { return d; } void ParseSession::setData(const ParseSessionData::Ptr data) { this->d = data; } KDevelop::IndexedString ParseSession::document() const { return d->m_document; } RSCrate *ParseSession::crate() const { return d->m_crate; } void ParseSession::setContextOnNode(RustNode *node, KDevelop::DUContext *context) { - node->setContext(context); + d->m_nodeContextMap.insert(node_get_id(node->data()), context); } KDevelop::DUContext *ParseSession::contextFromNode(RustNode *node) { - return node->getContext(); + return d->m_nodeContextMap.value(node_get_id(node->data())); } } diff --git a/duchain/parsesession.h b/duchain/parsesession.h index 65e48d8..4657fb5 100644 --- a/duchain/parsesession.h +++ b/duchain/parsesession.h @@ -1,59 +1,62 @@ #ifndef PARSESESSION_H #define PARSESESSION_H +#include + #include #include #include #include "astredux.h" #include "rustnode.h" namespace Rust { class ParseSessionData : public KDevelop::IAstContainer { public: typedef QExplicitlySharedDataPointer Ptr; ParseSessionData(const KDevelop::IndexedString &document, const QByteArray &contents); ~ParseSessionData() override; private: friend class ParseSession; void parse(); KDevelop::IndexedString m_document; QByteArray m_contents; RSCrate *m_crate; + QMap m_nodeContextMap; }; class ParseSession { public: explicit ParseSession(const ParseSessionData::Ptr &data); ~ParseSession(); void parse(); ParseSessionData::Ptr data() const; void setData(const ParseSessionData::Ptr data); KDevelop::IndexedString document() const; RSCrate *crate() const; void setContextOnNode(RustNode *node, KDevelop::DUContext *context); KDevelop::DUContext *contextFromNode(RustNode *node); private: Q_DISABLE_COPY(ParseSession) ParseSessionData::Ptr d; }; } #endif // PARSESESSION_H diff --git a/duchain/rustnode.cpp b/duchain/rustnode.cpp index ab4e0a8..36297f9 100644 --- a/duchain/rustnode.cpp +++ b/duchain/rustnode.cpp @@ -1,69 +1,57 @@ #include "rustnode.h" namespace Rust { RustPath::RustPath(RustNode *node) { RustString name = RustString(node_get_spelling_name(node->data())); if (*name == nullptr) { value = "unknown"; } else { value = QString::fromUtf8(*name); } } RustNode::RustNode(RSNode *node) - : RustAllocatedObject(node), - context(nullptr) + : RustAllocatedObject(node) { } RustNode::RustNode(RustOwnedNode &node) - : RustAllocatedObject(node.data()), - context(nullptr) + : RustAllocatedObject(node.data()) { } -KDevelop::DUContext *RustNode::getContext() -{ - return context; -} - -void RustNode::setContext(KDevelop::DUContext *context) -{ - this->context = context; -} - template RustAllocatedObject::RustAllocatedObject(RustObjectType *object) : object(object) { } template RustAllocatedObject::~RustAllocatedObject() { RustDestructor(object); object = nullptr; } template RustObjectType *RustAllocatedObject::data() { return object; } template RustObjectType *RustAllocatedObject::operator *() { return object; } template class RustAllocatedObject; template class RustAllocatedObject; template class RustAllocatedObject; template class RustAllocatedObject; } diff --git a/duchain/rustnode.h b/duchain/rustnode.h index ba4c6b7..1251ea8 100644 --- a/duchain/rustnode.h +++ b/duchain/rustnode.h @@ -1,67 +1,61 @@ #ifndef RUSTNODE_H #define RUSTNODE_H #include #include "astredux.h" namespace Rust { template class RustAllocatedObject { public: RustAllocatedObject(RustObjectType *object); ~RustAllocatedObject(); RustObjectType *data(); RustObjectType *operator *(); private: RustObjectType *object; }; class RustString : public RustAllocatedObject { public: RustString(const char *str) : RustAllocatedObject(str) { } operator const char *() { return data(); } }; template void noop_destructor(T *) {} using RustCrate = RustAllocatedObject; using RustOwnedNode = RustAllocatedObject; class RustNode : public RustAllocatedObject { public: RustNode(RSNode *node); RustNode(RustOwnedNode &node); - - KDevelop::DUContext *getContext(); - void setContext(KDevelop::DUContext *context); - -private: - KDevelop::DUContext *context; }; class RustPath { public: explicit RustPath(RustNode *node); QString value; }; } #endif // RUSTNODE_H diff --git a/duchain/usebuilder.cpp b/duchain/usebuilder.cpp index d6bf2d8..31dfa6d 100644 --- a/duchain/usebuilder.cpp +++ b/duchain/usebuilder.cpp @@ -1,62 +1,62 @@ #include "usebuilder.h" #include #include #include #include #include "rustdebug.h" namespace Rust { UseBuilder::UseBuilder(const KDevelop::IndexedString &document) : document(document) { } RSVisitResult UseBuilder::visitNode(RustNode *node, RustNode *parent) { using namespace KDevelop; RSNodeKind kind = node_get_kind(node->data()); if (kind == PathSegment) { RustPath segment(node); RustPath path(parent); QualifiedIdentifier qualifiedPath = identifierForNode(&path); IndexedIdentifier pathSegment = IndexedIdentifier(Identifier(segment.value)); // eh, this feels way too much like a hack while (qualifiedPath.last() != pathSegment) { qualifiedPath.pop(); } RangeInRevision useRange = editorFindRange(node, node); DUContext *context = topContext()->findContextAt(useRange.start); QList declarations = context->findDeclarations(qualifiedPath); // qCDebug(KDEV_RUST) << "USE:" << segment.value << "; spelling range: (" // << useRange.start.line + 1 << ":" << useRange.start.column << "-" // << useRange.end.line + 1 << ":" << useRange.end.column << "); context:" // << context->localScopeIdentifier() // << context->range(); if (declarations.isEmpty() || !declarations.first()) { ProblemPointer p = ProblemPointer(new Problem()); p->setFinalLocation(DocumentRange(document, useRange.castToSimpleRange())); p->setSource(IProblem::SemanticAnalysis); p->setSeverity(IProblem::Hint); p->setDescription(i18n("Undefined %1", path.value)); DUChainWriteLocker lock(DUChain::lock()); topContext()->addProblem(p); } else if (declarations.first()->range() != useRange) { UseBuilderBase::newUse(node, useRange, DeclarationPointer(declarations.first())); } } - return Recurse; + return ContextBuilder::visitNode(node, parent); } }