29bool hasNestedWithScope(
const nixf::ExprWith &With,
30 const nixf::VariableLookupAnalysis &VLA) {
32 const nixf::Definition *Def = VLA.
toDef(With.
kwWith());
37 for (
const nixf::ExprVar *Var : Def->
uses()) {
47 if (WithScopes.size() > 1 && WithScopes.front() != &With) {
58bool isCursorOnWithKeyword(
const nixf::ExprWith &With,
const nixf::Node &N) {
60 const auto &KwWith = With.
kwWith();
61 auto KwRange = KwWith.
range();
62 auto NRange = N.
range();
65 return NRange.
lCur().
offset() <= KwRange.rCur().offset() &&
66 NRange.rCur().offset() >= KwRange.lCur().offset();
72collectWithVariables(
const nixf::ExprWith &With,
73 const nixf::VariableLookupAnalysis &VLA) {
74 std::set<std::string> VarNames;
77 const nixf::Definition *Def = VLA.
toDef(With.
kwWith());
82 for (
const nixf::ExprVar *Var : Def->
uses()) {
84 VarNames.insert(std::string(Var->id().name()));
92std::string generateLetInherit(
const nixf::ExprWith &With,
93 const std::set<std::string> &VarNames,
94 llvm::StringRef Src) {
98 std::string_view SourceExpr;
100 SourceExpr = With.
with()->
src(Src);
105 std::string_view BodyExpr;
107 BodyExpr = With.
expr()->
src(Src);
112 Result.reserve(SourceExpr.size() + BodyExpr.size() + VarNames.size() * 10 +
115 Result +=
"let inherit (";
116 Result += SourceExpr;
120 for (
const auto &Name : VarNames) {
135 const std::string &FileURI, llvm::StringRef Src,
136 std::vector<lspserver::CodeAction> &Actions) {
142 const auto &With =
static_cast<const nixf::ExprWith &
>(*WithNode);
145 if (!isCursorOnWithKeyword(With, N))
154 if (hasNestedWithScope(With, VLA))
158 std::set<std::string> VarNames = collectWithVariables(With, VLA);
162 if (VarNames.empty())
166 std::string NewText = generateLetInherit(With, VarNames, Src);
172 "Convert `with` to `let/inherit`",
Convert between LSP and nixf types.
Shared utilities for code actions.
Code action for converting with expressions to let/inherit.
const std::vector< const ExprVar * > & uses() const
const Misc & kwWith() const
std::size_t offset() const
Offset in the source file, starting from 0.
std::string_view src(std::string_view Src) const
LexerCursorRange range() const
const Node * upTo(const Node &N, Node::NodeKind Kind) const
Search up until some kind of node is found.
const Definition * toDef(const Node &N) const
Get definition record for some name.
std::vector< const ExprWith * > getWithScopes(const ExprVar &Var) const
Get all with expressions that could provide the binding for a variable.
void addWithToLetAction(const nixf::Node &N, const nixf::ParentMapAnalysis &PM, const nixf::VariableLookupAnalysis &VLA, const std::string &FileURI, llvm::StringRef Src, std::vector< lspserver::CodeAction > &Actions)
Add code action to convert with expression to let/inherit.
lspserver::CodeAction createSingleEditAction(const std::string &Title, llvm::StringLiteral Kind, const std::string &FileURI, const lspserver::Range &EditRange, std::string NewText)
Create a CodeAction with a single text edit.
lspserver::Range toLSPRange(llvm::StringRef Code, const nixf::LexerCursorRange &R)
static const llvm::StringLiteral REFACTOR_REWRITE_KIND