Skip to content

Commit

Permalink
tmp
Browse files Browse the repository at this point in the history
  • Loading branch information
inclyc committed Jul 25, 2024
1 parent a40a881 commit 3b1dfd4
Show file tree
Hide file tree
Showing 9 changed files with 190 additions and 130 deletions.
10 changes: 9 additions & 1 deletion nixd/lib/Controller/AST.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,21 @@ struct NotAnIdiomException : IdiomSelectorException {
}
};

struct VLAException : std::exception {};

/// \brief No such variable.
struct NoSuchVarException : IdiomSelectorException {
struct NoSuchVarException : VLAException {
[[nodiscard]] const char *what() const noexcept override {
return "no such variable";
}
};

struct UndefinedVarException : VLAException {
[[nodiscard]] const char *what() const noexcept override {
return "undefined variable";
}
};

/// \brief Construct a nixd::Selector from \p Var.
///
/// Try to heuristically find a selector of a variable, based on some known
Expand Down
100 changes: 65 additions & 35 deletions nixd/lib/Controller/Definition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include "nixd/Controller/Controller.h"
#include "nixd/Protocol/AttrSet.h"

#include "lspserver/Protocol.h"

#include <boost/asio/post.hpp>

#include <llvm/Support/Error.h>
Expand Down Expand Up @@ -94,20 +96,26 @@ const ExprVar *findVar(const Node &N, const ParentMapAnalysis &PMA,
return static_cast<const ExprVar *>(PMA.upTo(N, Node::NK_ExprVar));
}

Expected<Location> staticDef(URIForFile URI, const Node &N,
const ParentMapAnalysis &PMA,
const VariableLookupAnalysis &VLA) {
Expected<const Definition &> ExpDef = findDefinition(N, PMA, VLA);
if (!ExpDef)
return ExpDef.takeError();
const Definition &findVarDefinition(const ExprVar &Var,
const VariableLookupAnalysis &VLA) {
LookupResult Result = VLA.query(static_cast<const ExprVar &>(Var));

if (Result.Kind == ResultKind::Undefined)
throw UndefinedVarException();

if (Result.Kind == ResultKind::NoSuchVar)
throw NoSuchVarException();

assert(Result.Def);

if (ExpDef->isBuiltin())
return error("this is a builtin variable defined by nix interpreter");
assert(ExpDef->syntax());
return *Result.Def;
}

/// \brief Convert nixf::Definition to lspserver::Location
Location convertToLocation(const Definition &Def, URIForFile URI) {
return Location{
.uri = std::move(URI),
.range = toLSPRange(ExpDef->syntax()->range()),
.range = toLSPRange(Def.syntax()->range()),
};
}

Expand Down Expand Up @@ -270,6 +278,39 @@ Locations defineSelect(const ExprSelect &Sel, const VariableLookupAnalysis &VLA,
return {};
}

Locations defineVarStatic(const ExprVar &Var, const VariableLookupAnalysis &VLA,
const URIForFile &URI) {
const Definition &Def = findVarDefinition(Var, VLA);
return {convertToLocation(Def, URI)};
}

template <class T>
std::vector<T> mergeVec(std::vector<T> A, const std::vector<T> &B) {
A.insert(A.end(), B.begin(), B.end());
return A;
}

Locations defineVar(const ExprVar &Var, const VariableLookupAnalysis &VLA,
const ParentMapAnalysis &PM, AttrSetClient &NixpkgsClient,
const URIForFile &URI) {
try {
Locations StaticLocs = defineVarStatic(Var, VLA, URI);

// Nixpkgs locations.
try {
Selector Sel = mkIdiomSelector(Var, VLA, PM);
Locations NixpkgsLocs = defineNixpkgsSelector(Sel, NixpkgsClient);
return mergeVec(std::move(StaticLocs), NixpkgsLocs);
} catch (std::exception &E) {
elog("definition/idiom/selector: {0}", E.what());
return StaticLocs;
}
} catch (std::exception &E) {
elog("definition/static: {0}", E.what());
}
return {};
}

/// \brief Squash a vector into smaller json variant.
template <class T> llvm::json::Value squash(std::vector<T> List) {
std::size_t Size = List.size();
Expand All @@ -293,27 +334,17 @@ llvm::Expected<llvm::json::Value> squash(llvm::Expected<std::vector<T>> List) {

} // namespace

Expected<const Definition &>
nixd::findDefinition(const Node &N, const ParentMapAnalysis &PMA,
const VariableLookupAnalysis &VLA) {
const Definition &nixd::findDefinition(const Node &N,
const ParentMapAnalysis &PMA,
const VariableLookupAnalysis &VLA) {
const ExprVar *Var = findVar(N, PMA, VLA);
if (!Var) [[unlikely]] {
if (const Definition *Def = findSelfDefinition(N, PMA, VLA))
return *Def;
return error("cannot find variable on given position");
throw CannotFindVarException();
}
assert(Var->kind() == Node::NK_ExprVar);
LookupResult Result = VLA.query(static_cast<const ExprVar &>(*Var));

if (Result.Kind == ResultKind::Undefined)
return error("this varaible is undefined");

if (Result.Kind == ResultKind::NoSuchVar)
return error("this varaible is not used in var lookup (duplicated attr?)");

assert(Result.Def);

return *Result.Def;
return findVarDefinition(*Var, VLA);
}

void Controller::onDefinition(const TextDocumentPositionParams &Params,
Expand All @@ -340,7 +371,15 @@ void Controller::onDefinition(const TextDocumentPositionParams &Params,
const Node &UpExpr = *MaybeUpExpr;

return Reply(squash([&]() -> llvm::Expected<Locations> {
// Special case for inherited names.
if (const ExprVar *Var = findInheritVar(N, PM, VLA))
return defineVar(*Var, VLA, PM, *nixpkgsClient(), URI);

switch (UpExpr.kind()) {
case Node::NK_ExprVar: {
const auto &Var = static_cast<const ExprVar &>(UpExpr);
return defineVar(Var, VLA, PM, *nixpkgsClient(), URI);
}
case Node::NK_ExprSelect: {
const auto &Sel = static_cast<const ExprSelect &>(UpExpr);
return defineSelect(Sel, VLA, PM, *nixpkgsClient());
Expand All @@ -350,16 +389,7 @@ void Controller::onDefinition(const TextDocumentPositionParams &Params,
default:
break;
}

// Get static locations.
// Likely this will fail, thus just logging errors.
return [&]() -> Locations {
Expected<Location> StaticLoc = staticDef(URI, *MaybeN, PM, VLA);
if (StaticLoc)
return {*StaticLoc};
elog("definition/static: {0}", StaticLoc.takeError());
return {};
}();
return error("unknown node type for definition");
}()));
}
}
Expand Down
12 changes: 9 additions & 3 deletions nixd/lib/Controller/Definition.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,15 @@

namespace nixd {

struct CannotFindVarException : std::exception {
[[nodiscard]] const char *what() const noexcept override {
return "cannot find variable on given node";
}
};

/// \brief Heuristically find definition on some node
llvm::Expected<const nixf::Definition &>
findDefinition(const nixf::Node &N, const nixf::ParentMapAnalysis &PMA,
const nixf::VariableLookupAnalysis &VLA);
const nixf::Definition &findDefinition(const nixf::Node &N,
const nixf::ParentMapAnalysis &PMA,
const nixf::VariableLookupAnalysis &VLA);

} // namespace nixd
67 changes: 33 additions & 34 deletions nixd/lib/Controller/DocumentHighlight.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "nixd/Controller/Controller.h"

#include <boost/asio/post.hpp>
#include <exception>
#include <lspserver/Protocol.h>
#include <nixf/Sema/ParentMap.h>
#include <nixf/Sema/VariableLookup.h>
Expand All @@ -19,30 +20,34 @@ using namespace llvm;
using namespace nixf;

namespace {
Error highlight(const nixf::Node &Desc, const ParentMapAnalysis &PMA,
const VariableLookupAnalysis &VLA, const URIForFile &URI,
std::vector<DocumentHighlight> &Highlights) {

std::vector<DocumentHighlight> highlight(const nixf::Node &Desc,
const ParentMapAnalysis &PMA,
const VariableLookupAnalysis &VLA,
const URIForFile &URI) {
// Find "definition"
if (auto Def = findDefinition(Desc, PMA, VLA)) {
// OK, iterate all uses.
for (const auto *Use : Def->uses()) {
assert(Use);
Highlights.emplace_back(DocumentHighlight{
.range = toLSPRange(Use->range()),
.kind = DocumentHighlightKind::Read,
});
}
if (Def->syntax()) {
const Node &Syntax = *Def->syntax();
Highlights.emplace_back(DocumentHighlight{
.range = toLSPRange(Syntax.range()),
.kind = DocumentHighlightKind::Write,
});
}
return Error::success();
auto Def = findDefinition(Desc, PMA, VLA);

std::vector<DocumentHighlight> Highlights;
// OK, iterate all uses.
for (const auto *Use : Def.uses()) {
assert(Use);
Highlights.emplace_back(DocumentHighlight{
.range = toLSPRange(Use->range()),
.kind = DocumentHighlightKind::Read,
});
}
if (Def.syntax()) {
const Node &Syntax = *Def.syntax();
Highlights.emplace_back(DocumentHighlight{
.range = toLSPRange(Syntax.range()),
.kind = DocumentHighlightKind::Write,
});
}
return error("Cannot find definition of this node");

return Highlights;
}

} // namespace

void Controller::onDocumentHighlight(
Expand All @@ -58,20 +63,14 @@ void Controller::onDocumentHighlight(
Reply(error("cannot find corresponding node on given position"));
return;
}
std::vector<DocumentHighlight> Highlights;
if (auto Err = highlight(*Desc, *TU->parentMap(), *TU->variableLookup(),
URI, Highlights)) {
// FIXME: Empty response if there are no def-use chain found.
// For document highlights, the specification explicitly specified LSP
// should do "fuzzy" things.

// Empty response on error, don't reply all errors because this method
// is very frequently called.
Reply(std::vector<DocumentHighlight>{});
lspserver::elog("textDocument/documentHighlight failed: {0}", Err);
return;
try {
const auto &PM = *TU->parentMap();
const auto &VLA = *TU->variableLookup();
return Reply(highlight(*Desc, PM, VLA, URI));
} catch (std::exception &E) {
elog("textDocument/documentHighlight failed: {0}", E.what());
return Reply(std::vector<DocumentHighlight>{});
}
Reply(std::move(Highlights));
}
}
};
Expand Down
44 changes: 22 additions & 22 deletions nixd/lib/Controller/FindReferences.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,27 @@ using namespace nixf;

namespace {

Error findReferences(const nixf::Node &Desc, const ParentMapAnalysis &PMA,
const VariableLookupAnalysis &VLA, const URIForFile &URI,
std::vector<Location> &Locations) {
std::vector<Location> findReferences(const nixf::Node &Desc,
const ParentMapAnalysis &PMA,
const VariableLookupAnalysis &VLA,
const URIForFile &URI) {

// Two steps.
// 1. Find some "definition" for this node.
// 2. Find all "uses", and construct the vector.

// Find "definition"
if (auto Def = findDefinition(Desc, PMA, VLA)) {
// OK, iterate all uses.
for (const auto *Use : Def->uses()) {
assert(Use);
Locations.emplace_back(Location{
.uri = URI,
.range = toLSPRange(Use->range()),
});
}
return Error::success();
auto Def = findDefinition(Desc, PMA, VLA);
std::vector<Location> Locations;
// OK, iterate all uses.
for (const auto *Use : Def.uses()) {
assert(Use);
Locations.emplace_back(Location{
.uri = URI,
.range = toLSPRange(Use->range()),
});
}
return error("Cannot find definition of this node");
return Locations;
}

} // namespace
Expand All @@ -54,16 +54,16 @@ void Controller::onReferences(const TextDocumentPositionParams &Params,
if (std::shared_ptr<nixf::Node> AST = getAST(*TU, Reply)) [[likely]] {
const nixf::Node *Desc = AST->descend({Pos, Pos});
if (!Desc) {
Reply(error("cannot find corresponding node on given position"));
return;
return Reply(
error("cannot find corresponding node on given position"));
}
std::vector<Location> Locations;
if (auto Err = findReferences(*Desc, *TU->parentMap(),
*TU->variableLookup(), URI, Locations)) {
Reply(std::move(Err));
return;
const auto &PM = *TU->parentMap();
const auto &VLA = *TU->variableLookup();
try {
return Reply(findReferences(*Desc, PM, VLA, URI));
} catch (std::exception &E) {
return Reply(error("references: {0}", E.what()));
}
Reply(std::move(Locations));
}
}
};
Expand Down
Loading

0 comments on commit 3b1dfd4

Please sign in to comment.