feat(lsp): module-path segment rename for Std::Io imports (0.12)
Index import A::B path segments and rename with left-prefix match so Std::Io does not clobber Foo::Io, bare idents, or enum Color::Red.
This commit is contained in:
Executable
+104
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env bash
|
||||
# Smoke: module-path segment rename (bux-lsp 0.12) — import Std::Io style
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
LSP="$ROOT/tools/bux-lsp"
|
||||
TMP=$(mktemp -d)
|
||||
trap 'rm -rf "$TMP"' EXIT
|
||||
|
||||
if [[ ! -x "$LSP" ]]; then
|
||||
(cd "$ROOT" && make lsp >/dev/null)
|
||||
fi
|
||||
|
||||
# Two files share Std::Io imports; also an unrelated Foo::Io and enum Color::Red
|
||||
# so rename of Io under Std:: must not touch them.
|
||||
cat > "$TMP/Main.bux" <<'EOF'
|
||||
import Std::Io::{PrintLine, PrintInt};
|
||||
import Foo::Io::Helper;
|
||||
enum Color {
|
||||
Red,
|
||||
Green
|
||||
}
|
||||
func Main() -> int {
|
||||
let c: Color = Color::Red;
|
||||
PrintLine("hi");
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
|
||||
cat > "$TMP/Util.bux" <<'EOF'
|
||||
import Std::Io::PrintLine;
|
||||
func Util() -> int {
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
|
||||
rpc() {
|
||||
local body="$1"
|
||||
local len
|
||||
len=$(printf '%s' "$body" | wc -c)
|
||||
printf 'Content-Length: %s\r\n\r\n%s' "$len" "$body"
|
||||
}
|
||||
|
||||
CONTENT_JSON=$(python3 -c 'import json,sys; print(json.dumps(open(sys.argv[1]).read()))' "$TMP/Main.bux")
|
||||
URI="file://$TMP/Main.bux"
|
||||
URI2="file://$TMP/Util.bux"
|
||||
CONTENT2_JSON=$(python3 -c 'import json,sys; print(json.dumps(open(sys.argv[1]).read()))' "$TMP/Util.bux")
|
||||
|
||||
# import Std::Io — "Io" starts after "import Std::" = col 12 on line 0
|
||||
# "Std" starts at col 7 on line 0
|
||||
{
|
||||
rpc '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"capabilities":{},"rootUri":"file://'"$TMP"'"}}'
|
||||
rpc '{"jsonrpc":"2.0","method":"initialized","params":{}}'
|
||||
rpc '{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"'"$URI"'","languageId":"bux","version":1,"text":'"$CONTENT_JSON"'}}}'
|
||||
rpc '{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"'"$URI2"'","languageId":"bux","version":1,"text":'"$CONTENT2_JSON"'}}}'
|
||||
# rename Io (module segment under Std) → Net
|
||||
rpc '{"jsonrpc":"2.0","id":2,"method":"textDocument/rename","params":{"textDocument":{"uri":"'"$URI"'"},"position":{"line":0,"character":12},"newName":"Net"}}'
|
||||
# rename Std (path head) → Core — should hit Std:: only
|
||||
rpc '{"jsonrpc":"2.0","id":3,"method":"textDocument/rename","params":{"textDocument":{"uri":"'"$URI"'"},"position":{"line":0,"character":7},"newName":"Core"}}'
|
||||
# rename Red (enum variant) must still work as member — not path
|
||||
rpc '{"jsonrpc":"2.0","id":4,"method":"textDocument/rename","params":{"textDocument":{"uri":"'"$URI"'"},"position":{"line":3,"character":4},"newName":"Crimson"}}'
|
||||
rpc '{"jsonrpc":"2.0","id":5,"method":"shutdown","params":null}'
|
||||
rpc '{"jsonrpc":"2.0","method":"exit","params":null}'
|
||||
} | "$LSP" 2>/dev/null | tr '\r' '\n' > "$TMP/out.txt"
|
||||
|
||||
if ! grep -q '0.12.0' "$TMP/out.txt"; then
|
||||
echo "WARN: version not 0.12.0"
|
||||
fi
|
||||
|
||||
# Io → Net: Main import Std::Io + Util import Std::Io (≥2), NOT Foo::Io
|
||||
net_edits=$(grep -o '"newText":"Net"' "$TMP/out.txt" | wc -l)
|
||||
if [[ "$net_edits" -lt 2 ]]; then
|
||||
echo "FAIL: path Io→Net expected ≥2 edits (Main+Util), got $net_edits"
|
||||
cat "$TMP/out.txt"
|
||||
exit 1
|
||||
fi
|
||||
# Must not rewrite Foo::Io — if it did, we'd still only get Net on Io segments.
|
||||
# Check that a Net edit range is not on the Foo line by ensuring we have exactly
|
||||
# the Std::Io sites (2) and not 3 (which would include Foo::Io).
|
||||
if [[ "$net_edits" -ge 3 ]]; then
|
||||
echo "FAIL: path Io→Net too many edits ($net_edits) — may have hit Foo::Io"
|
||||
cat "$TMP/out.txt"
|
||||
exit 1
|
||||
fi
|
||||
echo " path Io→Net edits: $net_edits"
|
||||
|
||||
# Std → Core: Main Std::Io + Util Std::Io (≥2); not Color:: or bare
|
||||
core_edits=$(grep -o '"newText":"Core"' "$TMP/out.txt" | wc -l)
|
||||
if [[ "$core_edits" -lt 2 ]]; then
|
||||
echo "FAIL: path Std→Core expected ≥2 edits, got $core_edits"
|
||||
cat "$TMP/out.txt"
|
||||
exit 1
|
||||
fi
|
||||
echo " path Std→Core edits: $core_edits"
|
||||
|
||||
# Red → Crimson: decl + Color::Red use (≥2)
|
||||
crimson_edits=$(grep -o '"newText":"Crimson"' "$TMP/out.txt" | wc -l)
|
||||
if [[ "$crimson_edits" -lt 2 ]]; then
|
||||
echo "FAIL: enum Red→Crimson expected ≥2 (still member rename), got $crimson_edits"
|
||||
cat "$TMP/out.txt"
|
||||
exit 1
|
||||
fi
|
||||
echo " enum Red→Crimson edits: $crimson_edits"
|
||||
|
||||
echo "PASS: LSP module-path segment rename (0.12)"
|
||||
Reference in New Issue
Block a user