⭐️ A friendly language for building type-safe, scalable systems!
at main 759 lines 12 kB view raw
1use std::collections::HashMap; 2 3use lsp_types::{ 4 PartialResultParams, Position, Range, ReferenceContext, ReferenceParams, 5 TextDocumentPositionParams, WorkDoneProgressParams, 6}; 7 8use crate::language_server::tests::{TestProject, find_position_of}; 9 10fn find_references( 11 tester: &TestProject<'_>, 12 position: Position, 13) -> Option<HashMap<String, Vec<Range>>> { 14 let locations = tester.at(position, |engine, params, _| { 15 let params = ReferenceParams { 16 text_document_position: TextDocumentPositionParams { 17 text_document: params.text_document, 18 position, 19 }, 20 work_done_progress_params: WorkDoneProgressParams::default(), 21 partial_result_params: PartialResultParams::default(), 22 context: ReferenceContext { 23 include_declaration: true, 24 }, 25 }; 26 engine.find_references(params).result.unwrap() 27 })?; 28 let mut references: HashMap<String, Vec<Range>> = HashMap::new(); 29 30 for location in locations { 31 let module_name = tester 32 .module_name_from_url(&location.uri) 33 .expect("Valid uri"); 34 _ = references 35 .entry(module_name) 36 .or_default() 37 .push(location.range); 38 } 39 40 Some(references) 41} 42 43fn show_references(code: &str, position: Option<Position>, ranges: &[Range]) -> String { 44 let mut buffer = String::new(); 45 46 for (line_number, line) in code.lines().enumerate() { 47 let mut underline = String::new(); 48 let mut underline_empty = true; 49 let line_number = line_number as u32; 50 51 if let Some(Range { start, end }) = ranges 52 .iter() 53 .find(|range| range.start.line == line_number && range.end.line == line_number) 54 { 55 for (column_number, _) in line.chars().enumerate() { 56 let current_position = Position::new(line_number, column_number as u32); 57 if Some(current_position) == position { 58 underline_empty = false; 59 underline.push('↑'); 60 } else if start.le(&current_position) && current_position.lt(&end) { 61 underline_empty = false; 62 underline.push('▔'); 63 } else { 64 underline.push(' '); 65 } 66 } 67 } 68 69 buffer.push_str(line); 70 if !underline_empty { 71 buffer.push('\n'); 72 buffer.push_str(&underline); 73 } 74 buffer.push('\n'); 75 } 76 77 buffer 78} 79 80macro_rules! assert_references { 81 ($code:literal, $position:expr $(,)?) => { 82 assert_references!(TestProject::for_source($code), $position); 83 }; 84 85 (($module_name:literal, $module_src:literal), $code:literal, $position:expr $(,)?) => { 86 assert_references!( 87 TestProject::for_source($code).add_module($module_name, $module_src), 88 $position 89 ); 90 }; 91 92 ($project:expr, $position:expr $(,)?) => { 93 let project = $project; 94 let src = project.src; 95 let position = $position.find_position(src); 96 let result = find_references(&project, position).expect("References not found"); 97 98 let mut output = String::new(); 99 for (name, src) in project.root_package_modules.iter() { 100 output.push_str(&format!( 101 "-- {name}.gleam\n{}\n\n", 102 show_references(src, None, result.get(*name).unwrap_or(&Vec::new())) 103 )); 104 } 105 output.push_str(&format!( 106 "-- app.gleam\n{}", 107 show_references( 108 src, 109 Some(position), 110 result.get("app").unwrap_or(&Vec::new()) 111 ) 112 )); 113 114 insta::assert_snapshot!(insta::internals::AutoName, output, src); 115 }; 116} 117 118macro_rules! assert_no_references { 119 ($code:literal, $position:expr $(,)?) => { 120 let project = TestProject::for_source($code); 121 assert_no_references!(&project, $position); 122 }; 123 124 ($project:expr, $position:expr $(,)?) => { 125 let src = $project.src; 126 let position = $position.find_position(src); 127 let result = find_references($project, position); 128 assert_eq!(result, None); 129 }; 130} 131 132#[test] 133fn references_for_local_variable() { 134 assert_references!( 135 " 136pub fn main() { 137 let wibble = 10 138 let wobble = wibble + 1 139 wibble + wobble 140} 141", 142 find_position_of("wibble").nth_occurrence(2), 143 ); 144} 145 146#[test] 147fn references_for_local_variable_from_definition() { 148 assert_references!( 149 " 150pub fn main() { 151 let wibble = 10 152 let wobble = wibble + 1 153 wibble + wobble 154} 155", 156 find_position_of("wibble"), 157 ); 158} 159 160#[test] 161fn references_for_private_function() { 162 assert_references!( 163 " 164fn wibble() { 165 wibble() 166} 167 168pub fn main() { 169 let _ = wibble() 170 wibble() + 4 171} 172 173fn wobble() { 174 wibble() || wobble() 175} 176", 177 find_position_of("wibble"), 178 ); 179} 180 181#[test] 182fn references_for_private_function_from_reference() { 183 assert_references!( 184 " 185fn wibble() { 186 wibble() 187} 188 189pub fn main() { 190 let _ = wibble() 191 wibble() + 4 192} 193 194fn wobble() { 195 wibble() || wobble() 196} 197", 198 find_position_of("wibble").nth_occurrence(2), 199 ); 200} 201 202#[test] 203fn references_for_public_function() { 204 assert_references!( 205 ( 206 "mod", 207 " 208import app.{wibble} 209 210fn wobble() { 211 app.wibble() 212} 213 214fn other() { 215 wibble() 216} 217" 218 ), 219 " 220pub fn wibble() { 221 wibble() 222} 223", 224 find_position_of("wibble").nth_occurrence(2), 225 ); 226} 227 228#[test] 229fn references_for_function_from_qualified_reference() { 230 assert_references!( 231 ( 232 "mod", 233 " 234pub fn wibble() { 235 wibble() 236} 237" 238 ), 239 " 240import mod 241 242pub fn main() { 243 let value = mod.wibble() 244 mod.wibble() 245 value 246} 247", 248 find_position_of("wibble"), 249 ); 250} 251 252#[test] 253fn references_for_function_from_unqualified_reference() { 254 assert_references!( 255 ( 256 "mod", 257 " 258pub fn wibble() { 259 wibble() 260} 261" 262 ), 263 " 264import mod.{wibble} 265 266pub fn main() { 267 let value = wibble() 268 mod.wibble() 269 value 270} 271", 272 find_position_of("wibble()"), 273 ); 274} 275 276#[test] 277fn references_for_private_constant() { 278 assert_references!( 279 " 280const wibble = 10 281 282pub fn main() { 283 let _ = wibble 284 wibble + 4 285} 286 287fn wobble() { 288 wibble + wobble() 289} 290", 291 find_position_of("wibble"), 292 ); 293} 294 295#[test] 296fn references_for_private_constant_from_reference() { 297 assert_references!( 298 " 299const wibble = 10 300 301pub fn main() { 302 let _ = wibble 303 wibble + 4 304} 305 306fn wobble() { 307 wibble + wobble() 308} 309", 310 find_position_of("wibble").nth_occurrence(2), 311 ); 312} 313 314#[test] 315fn references_for_public_constant() { 316 assert_references!( 317 ( 318 "mod", 319 " 320import app.{wibble} 321 322fn wobble() { 323 app.wibble 324} 325 326fn other() { 327 wibble 328} 329" 330 ), 331 " 332pub const wibble = 10 333 334pub fn main() { 335 wibble 336} 337", 338 find_position_of("wibble").nth_occurrence(2), 339 ); 340} 341 342#[test] 343fn references_for_constant_from_qualified_reference() { 344 assert_references!( 345 ( 346 "mod", 347 " 348pub const wibble = 10 349 350fn wobble() { 351 wibble 352} 353" 354 ), 355 " 356import mod 357 358pub fn main() { 359 let value = mod.wibble 360 mod.wibble + value 361} 362", 363 find_position_of("wibble"), 364 ); 365} 366 367#[test] 368fn references_for_constant_from_unqualified_reference() { 369 assert_references!( 370 ( 371 "mod", 372 " 373pub const wibble = 10 374 375fn wobble() { 376 wibble 377} 378" 379 ), 380 " 381import mod.{wibble} 382 383pub fn main() { 384 let value = mod.wibble 385 wibble + value 386} 387", 388 find_position_of("wibble +"), 389 ); 390} 391 392#[test] 393fn references_for_private_type_variant() { 394 assert_references!( 395 " 396type Wibble { Wibble } 397 398fn main() { 399 let _ = Wibble 400 Wibble 401} 402 403fn wobble() { 404 Wibble 405 wobble() 406} 407", 408 find_position_of("Wibble }"), 409 ); 410} 411 412#[test] 413fn references_for_private_type_variant_from_reference() { 414 assert_references!( 415 " 416type Wibble { Wibble } 417 418fn main() { 419 let _ = Wibble 420 Wibble 421} 422 423fn wobble() { 424 Wibble 425 wobble() 426} 427", 428 find_position_of(" = Wibble").under_char('W'), 429 ); 430} 431 432#[test] 433fn references_for_public_type_variant() { 434 assert_references!( 435 ( 436 "mod", 437 " 438import app.{Wibble} 439 440fn wobble() { 441 app.Wibble 442} 443 444fn other() { 445 Wibble 446} 447" 448 ), 449 " 450pub type Wibble { Wibble } 451 452pub fn main() { 453 Wibble 454} 455", 456 find_position_of("Wibble }"), 457 ); 458} 459 460#[test] 461fn references_for_type_variant_from_qualified_reference() { 462 assert_references!( 463 ( 464 "mod", 465 " 466pub type Wibble { Wibble } 467 468fn wobble() { 469 Wibble 470} 471" 472 ), 473 " 474import mod 475 476pub fn main() { 477 let value = mod.Wibble 478 mod.Wibble 479 value 480} 481", 482 find_position_of("Wibble"), 483 ); 484} 485 486#[test] 487fn references_for_type_variant_from_unqualified_reference() { 488 assert_references!( 489 ( 490 "mod", 491 " 492pub type Wibble { Wibble } 493 494fn wobble() { 495 Wibble 496} 497" 498 ), 499 " 500import mod.{Wibble} 501 502pub fn main() { 503 let value = mod.Wibble 504 Wibble 505} 506", 507 find_position_of("Wibble").nth_occurrence(3), 508 ); 509} 510 511#[test] 512fn no_references_for_keyword() { 513 assert_no_references!( 514 " 515pub fn wibble() { 516 todo 517} 518", 519 find_position_of("fn") 520 ); 521} 522 523#[test] 524fn references_for_aliased_value() { 525 assert_references!( 526 ( 527 "mod", 528 " 529import app.{Wibble as Wobble} 530 531fn wobble() { 532 Wobble 533} 534" 535 ), 536 " 537pub type Wibble { Wibble } 538 539pub fn main() { 540 Wibble 541} 542", 543 find_position_of("Wibble").nth_occurrence(2), 544 ); 545} 546 547#[test] 548fn references_for_aliased_const() { 549 assert_references!( 550 ( 551 "mod", 552 " 553import app.{wibble as other} 554 555fn wobble() { 556 other 557} 558" 559 ), 560 " 561pub const wibble = 123 562 563pub fn main() { 564 wibble 565} 566", 567 find_position_of("wibble").nth_occurrence(2), 568 ); 569} 570 571#[test] 572fn references_for_aliased_function() { 573 assert_references!( 574 ( 575 "mod", 576 " 577import app.{wibble as other} 578 579fn wobble() { 580 other() 581} 582" 583 ), 584 " 585pub fn wibble() { 586 123 587} 588 589pub fn main() { 590 wibble() 591} 592", 593 find_position_of("wibble").nth_occurrence(2), 594 ); 595} 596 597#[test] 598fn references_for_private_type() { 599 assert_references!( 600 " 601type Wibble { Wibble } 602 603fn main() -> Wibble { 604 todo 605} 606 607fn wobble(w: Wibble) { 608 todo 609} 610", 611 find_position_of("Wibble"), 612 ); 613} 614 615#[test] 616fn references_for_private_type_from_reference() { 617 assert_references!( 618 " 619type Wibble { Wibble } 620 621fn main() -> Wibble { 622 todo 623} 624 625fn wobble(w: Wibble) { 626 todo 627} 628", 629 find_position_of("-> Wibble").under_char('W'), 630 ); 631} 632 633#[test] 634fn references_for_public_type() { 635 assert_references!( 636 ( 637 "mod", 638 " 639import app.{type Wibble} 640 641fn wobble() -> Wibble { 642 todo 643} 644 645fn other(w: app.Wibble) { 646 todo 647} 648" 649 ), 650 " 651pub type Wibble { Wibble } 652 653pub fn main() -> Wibble { 654 todo 655} 656", 657 find_position_of("Wibble"), 658 ); 659} 660 661#[test] 662fn references_for_type_from_qualified_reference() { 663 assert_references!( 664 ( 665 "mod", 666 " 667pub type Wibble { Wibble } 668 669fn wobble() -> Wibble { 670 todo 671} 672" 673 ), 674 " 675import mod 676 677pub fn main() -> mod.Wibble { 678 let _: mod.Wibble = todo 679} 680", 681 find_position_of("Wibble"), 682 ); 683} 684 685#[test] 686fn references_for_type_from_unqualified_reference() { 687 assert_references!( 688 ( 689 "mod", 690 " 691pub type Wibble { Wibble } 692 693fn wobble() -> Wibble { 694 todo 695} 696" 697 ), 698 " 699import mod.{type Wibble} 700 701pub fn main() -> Wibble { 702 let _: mod.Wibble = todo 703} 704", 705 find_position_of("Wibble").nth_occurrence(2), 706 ); 707} 708 709#[test] 710fn references_for_aliased_type() { 711 assert_references!( 712 ( 713 "mod", 714 " 715import app.{type Wibble as Wobble} 716 717fn wobble() -> Wobble { 718 todo 719} 720 721fn other(w: app.Wibble) { 722 todo 723} 724" 725 ), 726 " 727pub type Wibble { Wibble } 728 729pub fn main() -> Wibble { 730 todo 731} 732", 733 find_position_of("-> Wibble").under_char('W'), 734 ); 735} 736 737#[test] 738fn references_for_type_from_let_annotation() { 739 assert_references!( 740 ( 741 "mod", 742 " 743pub type Wibble { Wibble } 744 745fn wobble() -> Wibble { 746 todo 747} 748" 749 ), 750 " 751import mod.{type Wibble} 752 753pub fn main() -> Wibble { 754 let _: mod.Wibble = todo 755} 756", 757 find_position_of("mod.Wibble").under_char('W'), 758 ); 759}