Skip to content

Commit 8768011

Browse files
authored
ide: support more CTEs in goto def (#783)
1 parent ab45b7c commit 8768011

File tree

2 files changed

+104
-7
lines changed

2 files changed

+104
-7
lines changed

crates/squawk_ide/src/goto_definition.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,6 +1378,66 @@ select "?column?"$0 from x;
13781378
"#);
13791379
}
13801380

1381+
#[test]
1382+
fn goto_cte_star_expansion() {
1383+
assert_snapshot!(goto("
1384+
with t as (select 1 a),
1385+
y as (select * from t)
1386+
select a$0 from y;
1387+
"), @r"
1388+
╭▸
1389+
2 │ with t as (select 1 a),
1390+
│ ─ 2. destination
1391+
3 │ y as (select * from t)
1392+
4 │ select a from y;
1393+
╰╴ ─ 1. source
1394+
");
1395+
}
1396+
1397+
#[test]
1398+
fn goto_cte_reference_inside_cte() {
1399+
assert_snapshot!(goto("
1400+
with t as (select 1 a),
1401+
y as (select a$0 from t)
1402+
select a from y;
1403+
"), @r"
1404+
╭▸
1405+
2 │ with t as (select 1 a),
1406+
│ ─ 2. destination
1407+
3 │ y as (select a from t)
1408+
╰╴ ─ 1. source
1409+
");
1410+
}
1411+
1412+
#[test]
1413+
fn goto_cte_with_column_list() {
1414+
assert_snapshot!(goto("
1415+
with t(a) as (select 1)
1416+
select a$0 from t;
1417+
"), @r"
1418+
╭▸
1419+
2 │ with t(a) as (select 1)
1420+
│ ─ 2. destination
1421+
3 │ select a from t;
1422+
╰╴ ─ 1. source
1423+
");
1424+
}
1425+
1426+
#[test]
1427+
fn goto_cte_shadows_table() {
1428+
assert_snapshot!(goto("
1429+
create table t(a int);
1430+
with t as (select a$0 from t)
1431+
select a from t;
1432+
"), @r"
1433+
╭▸
1434+
2 │ create table t(a int);
1435+
│ ─ 2. destination
1436+
3 │ with t as (select a from t)
1437+
╰╴ ─ 1. source
1438+
");
1439+
}
1440+
13811441
#[test]
13821442
fn goto_insert_table() {
13831443
assert_snapshot!(goto("

crates/squawk_ide/src/resolve.rs

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,7 @@ fn resolve_select_column(binder: &Binder, name_ref: &ast::NameRef) -> Option<Syn
602602
};
603603

604604
if schema.is_none()
605-
&& let Some(cte_column_ptr) = resolve_cte_column(&select, &table_name, &column_name)
605+
&& let Some(cte_column_ptr) = resolve_cte_column(name_ref, &table_name, &column_name)
606606
{
607607
return Some(cte_column_ptr);
608608
}
@@ -787,16 +787,41 @@ fn resolve_cte_table(name_ref: &ast::NameRef, cte_name: &Name) -> Option<SyntaxN
787787
}
788788

789789
fn resolve_cte_column(
790-
select: &ast::Select,
790+
name_ref: &ast::NameRef,
791791
cte_name: &Name,
792792
column_name: &Name,
793793
) -> Option<SyntaxNodePtr> {
794+
let select = name_ref
795+
.syntax()
796+
.ancestors()
797+
.filter_map(ast::Select::cast)
798+
.find(|s| s.with_clause().is_some())?;
794799
let with_clause = select.with_clause()?;
795800

796801
for with_table in with_clause.with_tables() {
797802
if let Some(name) = with_table.name()
798803
&& Name::new(name.syntax().text().to_string()) == *cte_name
799804
{
805+
// Skip if we're inside this CTE's definition (CTE doesn't shadow itself)
806+
if with_table
807+
.syntax()
808+
.text_range()
809+
.contains_range(name_ref.syntax().text_range())
810+
{
811+
continue;
812+
}
813+
814+
if let Some(column_list) = with_table.column_list() {
815+
for column in column_list.columns() {
816+
if let Some(col_name) = column.name()
817+
&& Name::new(col_name.syntax().text().to_string()) == *column_name
818+
{
819+
return Some(SyntaxNodePtr::new(col_name.syntax()));
820+
}
821+
}
822+
return None;
823+
}
824+
800825
let query = with_table.query()?;
801826

802827
let cte_select = match query {
@@ -812,11 +837,23 @@ fn resolve_cte_column(
812837
let target_list = select_clause.target_list()?;
813838

814839
for target in target_list.targets() {
815-
if let Some((col_name, node)) = ColumnName::from_target(target)
816-
&& let Some(col_name_str) = col_name.to_string()
817-
&& Name::new(col_name_str) == *column_name
818-
{
819-
return Some(SyntaxNodePtr::new(&node));
840+
if let Some((col_name, node)) = ColumnName::from_target(target.clone()) {
841+
if let Some(col_name_str) = col_name.to_string()
842+
&& Name::new(col_name_str) == *column_name
843+
{
844+
return Some(SyntaxNodePtr::new(&node));
845+
}
846+
847+
if matches!(col_name, ColumnName::Star) {
848+
if let Some(from_clause) = cte_select.from_clause()
849+
&& let Some(from_item) = from_clause.from_items().next()
850+
&& let Some(from_name_ref) = from_item.name_ref()
851+
{
852+
let from_table_name =
853+
Name::new(from_name_ref.syntax().text().to_string());
854+
return resolve_cte_column(name_ref, &from_table_name, column_name);
855+
}
856+
}
820857
}
821858
}
822859
}

0 commit comments

Comments
 (0)