diff --git a/duchain/usebuilder.cpp b/duchain/usebuilder.cpp index 6b0abcd..b1e39ac 100644 --- a/duchain/usebuilder.cpp +++ b/duchain/usebuilder.cpp @@ -1,63 +1,90 @@ #include "usebuilder.h" #include #include #include #include #include "rustdebug.h" namespace Rust { +using namespace KDevelop; + 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()); RSNodeKind parentKind = node_get_kind(parent->data()); - if (parentKind == Path && kind == PathSegment) { - RustPath segment(node); - RustPath path(parent); - QualifiedIdentifier qualifiedPath = identifierForNode(&path); - IndexedIdentifier pathSegment = IndexedIdentifier(Identifier(segment.value)); + if (kind == Path) { + visitPath(node, parent); + } else if (parentKind == Path && kind == PathSegment) { + visitPathSegment(node, parent); + } - // eh, this feels way too much like a hack - while (qualifiedPath.last() != pathSegment) { - qualifiedPath.pop(); - } + return ContextBuilder::visitNode(node, parent); +} - RangeInRevision useRange = editorFindRange(node, node); - DUContext *context = topContext()->findContextAt(useRange.start); - QList declarations = context->findDeclarations(qualifiedPath); +void UseBuilder::visitPath(RustNode *node, RustNode *parent) +{ + RustPath path(node); + fullPath = identifierForNode(&path); + currentPath.clear(); +} -// 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(); +void UseBuilder::visitPathSegment(RustNode *node, RustNode *parent) +{ + RustPath segment(node); + IndexedIdentifier pathSegment = IndexedIdentifier(Identifier(segment.value)); + currentPath.push(pathSegment); - 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)); + DUContext::SearchFlags flags = DUContext::NoSearchFlags; - DUChainWriteLocker lock(DUChain::lock()); - topContext()->addProblem(p); - } else if (declarations.first()->range() != useRange) { - UseBuilderBase::newUse(node, useRange, DeclarationPointer(declarations.first())); - } + if (fullPath.isQualified()) { + flags = DUContext::NoFiltering; } - return ContextBuilder::visitNode(node, parent); + RangeInRevision useRange = editorFindRange(node, node); + DUContext *context = topContext()->findContextAt(useRange.start); + QList declarations = context->findDeclarations(currentPath, + CursorInRevision::invalid(), + AbstractType::Ptr(), + nullptr, + flags); + + 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", fullPath.toString())); + + DUChainWriteLocker lock(DUChain::lock()); + topContext()->addProblem(p); + } else { + for (Declaration *declaration : declarations) { + if (fullPath.isQualified() && currentPath != fullPath) { + // We are dealing with a container-like path, ignore functions and variables + if (!declaration->internalContext() + || declaration->internalContext()->type() == DUContext::Other + || declaration->internalContext()->type() == DUContext::Function) { + continue; + } + } + + if (declaration->range() != useRange) { + UseBuilderBase::newUse(node, useRange, DeclarationPointer(declaration)); + break; + } + } + } } } diff --git a/duchain/usebuilder.h b/duchain/usebuilder.h index 91219d4..3f0a87c 100644 --- a/duchain/usebuilder.h +++ b/duchain/usebuilder.h @@ -1,31 +1,37 @@ #ifndef USEBUILDER_H #define USEBUILDER_H #include #include #include "contextbuilder.h" #include "rustnode.h" #include "kdevrustduchain_export.h" namespace Rust { using UseBuilderBase = KDevelop::AbstractUseBuilder; class KDEVRUSTDUCHAIN_EXPORT UseBuilder : public UseBuilderBase { public: UseBuilder(const KDevelop::IndexedString &document); ~UseBuilder() override = default; RSVisitResult visitNode(RustNode *node, RustNode *parent) override; private: + void visitPath(RustNode *node, RustNode *parent); + void visitPathSegment(RustNode *node, RustNode *parent); + + KDevelop::QualifiedIdentifier fullPath; + KDevelop::QualifiedIdentifier currentPath; + KDevelop::IndexedString document; }; } #endif // USEBUILDER_H