1use std::{iter, mem::discriminant};
2
3use crate::Analysis;
4use crate::{
5 FilePosition, NavigationTarget, RangeInfo, TryToNav, UpmappingResult,
6 doc_links::token_as_doc_comment,
7 navigation_target::{self, ToNav},
8};
9use hir::{
10 AsAssocItem, AssocItem, CallableKind, FileRange, HasCrate, InFile, ModuleDef, Semantics, sym,
11};
12use ide_db::{MiniCore, ra_fixture::UpmapFromRaFixture};
13use ide_db::{
14 RootDatabase, SymbolKind,
15 base_db::{AnchoredPath, SourceDatabase},
16 defs::{Definition, IdentClass},
17 famous_defs::FamousDefs,
18 helpers::pick_best_token,
19 syntax_helpers::node_ext::find_loops,
20};
21use itertools::Itertools;
22use span::FileId;
23use syntax::{
24 AstNode, AstToken, SyntaxKind::*, SyntaxNode, SyntaxToken, T, TextRange, ast, match_ast,
25};
26
27#[derive(Debug)]
28pub struct GotoDefinitionConfig<'a> {
29 pub minicore: MiniCore<'a>,
30}
31
32pub(crate) fn goto_definition(
44 db: &RootDatabase,
45 FilePosition { file_id, offset }: FilePosition,
46 config: &GotoDefinitionConfig<'_>,
47) -> Option<RangeInfo<Vec<NavigationTarget>>> {
48 let sema = &Semantics::new(db);
49 let file = sema.parse_guess_edition(file_id).syntax().clone();
50 let edition = sema.attach_first_edition(file_id).edition(db);
51 let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
52 IDENT
53 | INT_NUMBER
54 | LIFETIME_IDENT
55 | T![self]
56 | T![super]
57 | T![crate]
58 | T![Self]
59 | COMMENT => 4,
60 T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] => 3,
62 kind if kind.is_keyword(edition) => 2,
63 T!['('] | T![')'] => 2,
64 kind if kind.is_trivia() => 0,
65 _ => 1,
66 })?;
67 if let Some(doc_comment) = token_as_doc_comment(&original_token) {
68 return doc_comment.get_definition_with_descend_at(sema, offset, |def, _, link_range| {
69 let nav = def.try_to_nav(sema)?;
70 Some(RangeInfo::new(link_range, nav.collect()))
71 });
72 }
73
74 if let Some((range, _, _, resolution)) =
75 sema.check_for_format_args_template(original_token.clone(), offset)
76 {
77 return Some(RangeInfo::new(
78 range,
79 match resolution {
80 Some(res) => def_to_nav(sema, Definition::from(res)),
81 None => vec![],
82 },
83 ));
84 }
85
86 if let Some(navs) = handle_control_flow_keywords(sema, &original_token) {
87 return Some(RangeInfo::new(original_token.text_range(), navs));
88 }
89
90 let tokens = sema.descend_into_macros_no_opaque(original_token.clone(), false);
91 let mut navs = Vec::new();
92 for token in tokens {
93 if let Some(n) = find_definition_for_known_blanket_dual_impls(sema, &token.value) {
94 navs.extend(n);
95 continue;
96 }
97
98 if let Some(token) = ast::String::cast(token.value.clone())
99 && let Some(original_token) = ast::String::cast(original_token.clone())
100 && let Some((analysis, fixture_analysis)) =
101 Analysis::from_ra_fixture(sema, original_token, &token, config.minicore)
102 && let Some((virtual_file_id, file_offset)) = fixture_analysis.map_offset_down(offset)
103 {
104 return hir::attach_db_allow_change(&analysis.db, || {
105 goto_definition(
106 &analysis.db,
107 FilePosition { file_id: virtual_file_id, offset: file_offset },
108 config,
109 )
110 })
111 .and_then(|navs| {
112 navs.upmap_from_ra_fixture(&fixture_analysis, virtual_file_id, file_id).ok()
113 });
114 }
115
116 let parent = token.value.parent()?;
117
118 let token_file_id = token.file_id;
119 if let Some(token) = ast::String::cast(token.value.clone())
120 && let Some(x) =
121 try_lookup_include_path(sema, InFile::new(token_file_id, token), file_id)
122 {
123 navs.push(x);
124 continue;
125 }
126
127 if ast::TokenTree::can_cast(parent.kind())
128 && let Some(x) = try_lookup_macro_def_in_macro_use(sema, token.value)
129 {
130 navs.push(x);
131 continue;
132 }
133
134 let Some(ident_class) = IdentClass::classify_node(sema, &parent) else { continue };
135 navs.extend(ident_class.definitions().into_iter().flat_map(|(def, _)| {
136 if let Definition::ExternCrateDecl(crate_def) = def {
137 return crate_def
138 .resolved_crate(db)
139 .map(|it| it.root_module(db).to_nav(db))
140 .into_iter()
141 .flatten()
142 .collect();
143 }
144 try_filter_trait_item_definition(sema, &def).unwrap_or_else(|| def_to_nav(sema, def))
145 }));
146 }
147 let navs = navs.into_iter().unique().collect();
148
149 Some(RangeInfo::new(original_token.text_range(), navs))
150}
151
152fn find_definition_for_known_blanket_dual_impls(
154 sema: &Semantics<'_, RootDatabase>,
155 original_token: &SyntaxToken,
156) -> Option<Vec<NavigationTarget>> {
157 let method_call = ast::MethodCallExpr::cast(original_token.parent()?.parent()?)?;
158 let callable = sema.resolve_method_call_as_callable(&method_call)?;
159 let CallableKind::Function(f) = callable.kind() else { return None };
160 let assoc = f.as_assoc_item(sema.db)?;
161
162 let return_type = callable.return_type();
163 let fd = FamousDefs(sema, return_type.krate(sema.db));
164
165 let t = match assoc.container(sema.db) {
166 hir::AssocItemContainer::Trait(t) => t,
167 hir::AssocItemContainer::Impl(impl_)
168 if impl_.self_ty(sema.db).is_str() && f.name(sema.db) == sym::parse =>
169 {
170 let t = fd.core_convert_FromStr()?;
171 let t_f = t.function(sema.db, &sym::from_str)?;
172 return sema
173 .resolve_trait_impl_method(
174 return_type.clone(),
175 t,
176 t_f,
177 [return_type.type_arguments().next()?],
178 )
179 .map(|f| def_to_nav(sema, f.into()));
180 }
181 hir::AssocItemContainer::Impl(_) => return None,
182 };
183
184 let fn_name = f.name(sema.db);
185 let f = if fn_name == sym::into && fd.core_convert_Into() == Some(t) {
186 let dual = fd.core_convert_From()?;
187 let dual_f = dual.function(sema.db, &sym::from)?;
188 sema.resolve_trait_impl_method(
189 return_type.clone(),
190 dual,
191 dual_f,
192 [return_type, callable.receiver_param(sema.db)?.1],
193 )?
194 } else if fn_name == sym::try_into && fd.core_convert_TryInto() == Some(t) {
195 let dual = fd.core_convert_TryFrom()?;
196 let dual_f = dual.function(sema.db, &sym::try_from)?;
197 sema.resolve_trait_impl_method(
198 return_type.clone(),
199 dual,
200 dual_f,
201 [return_type.type_arguments().next()?, callable.receiver_param(sema.db)?.1],
203 )?
204 } else if fn_name == sym::to_string && fd.alloc_string_ToString() == Some(t) {
205 let dual = fd.core_fmt_Display()?;
206 let dual_f = dual.function(sema.db, &sym::fmt)?;
207 sema.resolve_trait_impl_method(
208 return_type.clone(),
209 dual,
210 dual_f,
211 [callable.receiver_param(sema.db)?.1.strip_reference()],
212 )?
213 } else {
214 return None;
215 };
216 let _t = f.as_assoc_item(sema.db)?.implemented_trait(sema.db)?;
219 let def = Definition::from(f);
220 Some(def_to_nav(sema, def))
221}
222
223fn try_lookup_include_path(
224 sema: &Semantics<'_, RootDatabase>,
225 token: InFile<ast::String>,
226 file_id: FileId,
227) -> Option<NavigationTarget> {
228 let file = token.file_id.macro_file()?;
229
230 if !iter::successors(Some(file), |file| file.parent(sema.db).macro_file())
233 .any(|file| file.is_include_like_macro(sema.db) && file.eager_arg(sema.db).is_none())
234 {
235 return None;
236 }
237 let path = token.value.value().ok()?;
238
239 let file_id = sema.db.resolve_path(AnchoredPath { anchor: file_id, path: &path })?;
240 let size = sema.db.file_text(file_id).text(sema.db).len().try_into().ok()?;
241 Some(NavigationTarget {
242 file_id,
243 full_range: TextRange::new(0.into(), size),
244 name: hir::Symbol::intern(&path),
245 alias: None,
246 focus_range: None,
247 kind: None,
248 container_name: None,
249 description: None,
250 docs: None,
251 })
252}
253
254fn try_lookup_macro_def_in_macro_use(
255 sema: &Semantics<'_, RootDatabase>,
256 token: SyntaxToken,
257) -> Option<NavigationTarget> {
258 let extern_crate = token.parent()?.ancestors().find_map(ast::ExternCrate::cast)?;
259 let extern_crate = sema.to_def(&extern_crate)?;
260 let krate = extern_crate.resolved_crate(sema.db)?;
261
262 for mod_def in krate.root_module(sema.db).declarations(sema.db) {
263 if let ModuleDef::Macro(mac) = mod_def
264 && mac.name(sema.db).as_str() == token.text()
265 && let Some(nav) = mac.try_to_nav(sema)
266 {
267 return Some(nav.call_site);
268 }
269 }
270
271 None
272}
273
274fn try_filter_trait_item_definition(
282 sema: &Semantics<'_, RootDatabase>,
283 def: &Definition,
284) -> Option<Vec<NavigationTarget>> {
285 let db = sema.db;
286 let assoc = def.as_assoc_item(db)?;
287 match assoc {
288 AssocItem::Function(..) => None,
289 AssocItem::Const(..) | AssocItem::TypeAlias(..) => {
290 let trait_ = assoc.implemented_trait(db)?;
291 let name = def.name(db)?;
292 let discriminant_value = discriminant(&assoc);
293 trait_
294 .items(db)
295 .iter()
296 .filter(|itm| discriminant(*itm) == discriminant_value)
297 .find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(sema)).flatten())
298 .map(|it| it.collect())
299 }
300 }
301}
302
303fn handle_control_flow_keywords(
304 sema: &Semantics<'_, RootDatabase>,
305 token: &SyntaxToken,
306) -> Option<Vec<NavigationTarget>> {
307 match token.kind() {
308 T![fn] | T![async] | T![try] | T![return] => nav_for_exit_points(sema, token),
311 T![loop] | T![while] | T![break] | T![continue] => nav_for_break_points(sema, token),
312 T![for] if token.parent().and_then(ast::ForExpr::cast).is_some() => {
313 nav_for_break_points(sema, token)
314 }
315 T![match] | T![=>] | T![if] => nav_for_branch_exit_points(sema, token),
316 _ => None,
317 }
318}
319
320pub(crate) fn find_fn_or_blocks(
321 sema: &Semantics<'_, RootDatabase>,
322 token: &SyntaxToken,
323) -> Vec<SyntaxNode> {
324 let find_ancestors = |token: SyntaxToken| {
325 let token_kind = token.kind();
326
327 for anc in sema.token_ancestors_with_macros(token) {
328 let node = match_ast! {
329 match anc {
330 ast::Fn(fn_) => fn_.syntax().clone(),
331 ast::ClosureExpr(c) => c.syntax().clone(),
332 ast::BlockExpr(blk) => {
333 match blk.modifier() {
334 Some(ast::BlockModifier::Async(_)) => blk.syntax().clone(),
335 Some(ast::BlockModifier::Try { .. }) if token_kind != T![return] => blk.syntax().clone(),
336 _ => continue,
337 }
338 },
339 _ => continue,
340 }
341 };
342
343 return Some(node);
344 }
345 None
346 };
347
348 sema.descend_into_macros(token.clone()).into_iter().filter_map(find_ancestors).collect_vec()
349}
350
351fn nav_for_exit_points(
352 sema: &Semantics<'_, RootDatabase>,
353 token: &SyntaxToken,
354) -> Option<Vec<NavigationTarget>> {
355 let db = sema.db;
356 let token_kind = token.kind();
357
358 let navs = find_fn_or_blocks(sema, token)
359 .into_iter()
360 .filter_map(|node| {
361 let file_id = sema.hir_file_for(&node);
362
363 match_ast! {
364 match node {
365 ast::Fn(fn_) => {
366 let mut nav = sema.to_def(&fn_)?.try_to_nav(sema)?;
367 let focus_token = if matches!(token_kind, T![async]) {
370 fn_.async_token()?
371 } else {
372 fn_.fn_token()?
373 };
374
375 let focus_frange = InFile::new(file_id, focus_token.text_range())
376 .original_node_file_range_opt(db)
377 .map(|(frange, _)| frange);
378
379 if let Some(FileRange { file_id, range }) = focus_frange {
380 let contains_frange = |nav: &NavigationTarget| {
381 nav.file_id == file_id.file_id(db) && nav.full_range.contains_range(range)
382 };
383
384 if let Some(def_site) = nav.def_site.as_mut() {
385 if contains_frange(def_site) {
386 def_site.focus_range = Some(range);
387 }
388 } else if contains_frange(&nav.call_site) {
389 nav.call_site.focus_range = Some(range);
390 }
391 }
392
393 Some(nav)
394 },
395 ast::ClosureExpr(c) => {
396 let pipe_tok = c.param_list().and_then(|it| it.pipe_token())?.text_range();
397 let closure_in_file = InFile::new(file_id, c.into());
398 Some(expr_to_nav(db, closure_in_file, Some(pipe_tok)))
399 },
400 ast::BlockExpr(blk) => {
401 match blk.modifier() {
402 Some(ast::BlockModifier::Async(_)) => {
403 let async_tok = blk.async_token()?.text_range();
404 let blk_in_file = InFile::new(file_id, blk.into());
405 Some(expr_to_nav(db, blk_in_file, Some(async_tok)))
406 },
407 Some(ast::BlockModifier::Try { .. }) if token_kind != T![return] => {
408 let try_tok = blk.try_block_modifier()?.try_token()?.text_range();
409 let blk_in_file = InFile::new(file_id, blk.into());
410 Some(expr_to_nav(db, blk_in_file, Some(try_tok)))
411 },
412 _ => None,
413 }
414 },
415 _ => None,
416 }
417 }
418 })
419 .flatten()
420 .collect_vec();
421
422 Some(navs)
423}
424
425pub(crate) fn find_branch_root(
426 sema: &Semantics<'_, RootDatabase>,
427 token: &SyntaxToken,
428) -> Vec<SyntaxNode> {
429 let find_nodes = |node_filter: fn(SyntaxNode) -> Option<SyntaxNode>| {
430 sema.descend_into_macros(token.clone())
431 .into_iter()
432 .filter_map(|token| node_filter(token.parent()?))
433 .collect_vec()
434 };
435
436 match token.kind() {
437 T![match] => find_nodes(|node| Some(ast::MatchExpr::cast(node)?.syntax().clone())),
438 T![=>] => find_nodes(|node| Some(ast::MatchArm::cast(node)?.syntax().clone())),
439 T![if] => find_nodes(|node| {
440 let if_expr = ast::IfExpr::cast(node)?;
441
442 let root_if = iter::successors(Some(if_expr.clone()), |if_expr| {
443 let parent_if = if_expr.syntax().parent().and_then(ast::IfExpr::cast)?;
444 let ast::ElseBranch::IfExpr(else_branch) = parent_if.else_branch()? else {
445 return None;
446 };
447
448 (else_branch.syntax() == if_expr.syntax()).then_some(parent_if)
449 })
450 .last()?;
451
452 Some(root_if.syntax().clone())
453 }),
454 _ => vec![],
455 }
456}
457
458fn nav_for_branch_exit_points(
459 sema: &Semantics<'_, RootDatabase>,
460 token: &SyntaxToken,
461) -> Option<Vec<NavigationTarget>> {
462 let db = sema.db;
463
464 let navs = match token.kind() {
465 T![match] => find_branch_root(sema, token)
466 .into_iter()
467 .filter_map(|node| {
468 let file_id = sema.hir_file_for(&node);
469 let match_expr = ast::MatchExpr::cast(node)?;
470 let focus_range = match_expr.match_token()?.text_range();
471 let match_expr_in_file = InFile::new(file_id, match_expr.into());
472 Some(expr_to_nav(db, match_expr_in_file, Some(focus_range)))
473 })
474 .flatten()
475 .collect_vec(),
476
477 T![=>] => find_branch_root(sema, token)
478 .into_iter()
479 .filter_map(|node| {
480 let match_arm = ast::MatchArm::cast(node)?;
481 let match_expr = sema
482 .ancestors_with_macros(match_arm.syntax().clone())
483 .find_map(ast::MatchExpr::cast)?;
484 let file_id = sema.hir_file_for(match_expr.syntax());
485 let focus_range = match_arm.fat_arrow_token()?.text_range();
486 let match_expr_in_file = InFile::new(file_id, match_expr.into());
487 Some(expr_to_nav(db, match_expr_in_file, Some(focus_range)))
488 })
489 .flatten()
490 .collect_vec(),
491
492 T![if] => find_branch_root(sema, token)
493 .into_iter()
494 .filter_map(|node| {
495 let file_id = sema.hir_file_for(&node);
496 let if_expr = ast::IfExpr::cast(node)?;
497 let focus_range = if_expr.if_token()?.text_range();
498 let if_expr_in_file = InFile::new(file_id, if_expr.into());
499 Some(expr_to_nav(db, if_expr_in_file, Some(focus_range)))
500 })
501 .flatten()
502 .collect_vec(),
503
504 _ => return Some(Vec::new()),
505 };
506
507 Some(navs)
508}
509
510fn nav_for_break_points(
511 sema: &Semantics<'_, RootDatabase>,
512 token: &SyntaxToken,
513) -> Option<Vec<NavigationTarget>> {
514 let db = sema.db;
515
516 let navs = find_loops(sema, token)?
517 .filter_map(|expr| {
518 let file_id = sema.hir_file_for(expr.syntax());
519 let expr_in_file = InFile::new(file_id, expr.clone());
520 let focus_range = match expr {
521 ast::Expr::LoopExpr(loop_) => loop_.loop_token()?.text_range(),
522 ast::Expr::WhileExpr(while_) => while_.while_token()?.text_range(),
523 ast::Expr::ForExpr(for_) => for_.for_token()?.text_range(),
524 ast::Expr::BlockExpr(blk) => blk.label().unwrap().syntax().text_range(),
526 _ => return None,
527 };
528 let nav = expr_to_nav(db, expr_in_file, Some(focus_range));
529 Some(nav)
530 })
531 .flatten()
532 .collect_vec();
533
534 Some(navs)
535}
536
537fn def_to_nav(sema: &Semantics<'_, RootDatabase>, def: Definition) -> Vec<NavigationTarget> {
538 def.try_to_nav(sema).map(|it| it.collect()).unwrap_or_default()
539}
540
541fn expr_to_nav(
542 db: &RootDatabase,
543 InFile { file_id, value }: InFile<ast::Expr>,
544 focus_range: Option<TextRange>,
545) -> UpmappingResult<NavigationTarget> {
546 let kind = SymbolKind::Label;
547
548 let value_range = value.syntax().text_range();
549 let navs = navigation_target::orig_range_with_focus_r(db, file_id, value_range, focus_range);
550 navs.map(|(hir::FileRangeWrapper { file_id, range }, focus_range)| {
551 NavigationTarget::from_syntax(
552 file_id,
553 hir::Symbol::intern("<expr>"),
554 focus_range,
555 range,
556 kind,
557 )
558 })
559}
560
561#[cfg(test)]
562mod tests {
563 use crate::{GotoDefinitionConfig, fixture};
564 use ide_db::{FileRange, MiniCore};
565 use itertools::Itertools;
566
567 const TEST_CONFIG: GotoDefinitionConfig<'_> =
568 GotoDefinitionConfig { minicore: MiniCore::default() };
569
570 #[track_caller]
571 fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
572 let (analysis, position, expected) = fixture::annotations(ra_fixture);
573 let navs = analysis
574 .goto_definition(position, &TEST_CONFIG)
575 .unwrap()
576 .expect("no definition found")
577 .info;
578
579 let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start());
580 let navs = navs
581 .into_iter()
582 .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
583 .sorted_by_key(cmp)
584 .collect::<Vec<_>>();
585 let expected = expected
586 .into_iter()
587 .map(|(FileRange { file_id, range }, _)| FileRange { file_id, range })
588 .sorted_by_key(cmp)
589 .collect::<Vec<_>>();
590
591 assert_eq!(expected, navs);
592 }
593
594 fn check_unresolved(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
595 let (analysis, position) = fixture::position(ra_fixture);
596 let navs = analysis
597 .goto_definition(position, &TEST_CONFIG)
598 .unwrap()
599 .expect("no definition found")
600 .info;
601
602 assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {navs:?}")
603 }
604
605 fn check_name(expected_name: &str, #[rust_analyzer::rust_fixture] ra_fixture: &str) {
606 let (analysis, position, _) = fixture::annotations(ra_fixture);
607 let navs = analysis
608 .goto_definition(position, &TEST_CONFIG)
609 .unwrap()
610 .expect("no definition found")
611 .info;
612 assert!(navs.len() < 2, "expected single navigation target but encountered {}", navs.len());
613 let Some(target) = navs.into_iter().next() else {
614 panic!("expected single navigation target but encountered none");
615 };
616 assert_eq!(target.name, hir::Symbol::intern(expected_name));
617 }
618
619 #[test]
620 fn goto_def_pat_range_to_inclusive() {
621 check_name(
622 "RangeToInclusive",
623 r#"
624//- minicore: range
625fn f(ch: char) -> bool {
626 match ch {
627 ..$0='z' => true,
628 _ => false
629 }
630}
631"#,
632 );
633 }
634
635 #[test]
636 fn goto_def_pat_range_to() {
637 check_name(
638 "RangeTo",
639 r#"
640//- minicore: range
641fn f(ch: char) -> bool {
642 match ch {
643 .$0.'z' => true,
644 _ => false
645 }
646}
647"#,
648 );
649 }
650
651 #[test]
652 fn goto_def_pat_range() {
653 check_name(
654 "Range",
655 r#"
656//- minicore: range
657fn f(ch: char) -> bool {
658 match ch {
659 'a'.$0.'z' => true,
660 _ => false
661 }
662}
663"#,
664 );
665 }
666
667 #[test]
668 fn goto_def_pat_range_inclusive() {
669 check_name(
670 "RangeInclusive",
671 r#"
672//- minicore: range
673fn f(ch: char) -> bool {
674 match ch {
675 'a'..$0='z' => true,
676 _ => false
677 }
678}
679"#,
680 );
681 }
682
683 #[test]
684 fn goto_def_pat_range_from() {
685 check_name(
686 "RangeFrom",
687 r#"
688//- minicore: range
689fn f(ch: char) -> bool {
690 match ch {
691 'a'..$0 => true,
692 _ => false
693 }
694}
695"#,
696 );
697 }
698
699 #[test]
700 fn goto_def_expr_range() {
701 check_name(
702 "Range",
703 r#"
704//- minicore: range
705let x = 0.$0.1;
706"#,
707 );
708 }
709
710 #[test]
711 fn goto_def_expr_range_from() {
712 check_name(
713 "RangeFrom",
714 r#"
715//- minicore: range
716fn f(arr: &[i32]) -> &[i32] {
717 &arr[0.$0.]
718}
719"#,
720 );
721 }
722
723 #[test]
724 fn goto_def_expr_range_inclusive() {
725 check_name(
726 "RangeInclusive",
727 r#"
728//- minicore: range
729let x = 0.$0.=1;
730"#,
731 );
732 }
733
734 #[test]
735 fn goto_def_expr_range_full() {
736 check_name(
737 "RangeFull",
738 r#"
739//- minicore: range
740fn f(arr: &[i32]) -> &[i32] {
741 &arr[.$0.]
742}
743"#,
744 );
745 }
746
747 #[test]
748 fn goto_def_expr_range_to() {
749 check_name(
750 "RangeTo",
751 r#"
752//- minicore: range
753fn f(arr: &[i32]) -> &[i32] {
754 &arr[.$0.10]
755}
756"#,
757 );
758 }
759
760 #[test]
761 fn goto_def_expr_range_to_inclusive() {
762 check_name(
763 "RangeToInclusive",
764 r#"
765//- minicore: range
766fn f(arr: &[i32]) -> &[i32] {
767 &arr[.$0.=10]
768}
769"#,
770 );
771 }
772
773 #[test]
774 fn goto_def_in_included_file() {
775 check(
776 r#"
777//- minicore:include
778//- /main.rs
779
780include!("a.rs");
781
782fn main() {
783 foo();
784}
785
786//- /a.rs
787fn func_in_include() {
788 //^^^^^^^^^^^^^^^
789}
790
791fn foo() {
792 func_in_include$0();
793}
794"#,
795 );
796 }
797
798 #[test]
799 fn goto_def_in_included_file_nested() {
800 check(
801 r#"
802//- minicore:include
803//- /main.rs
804
805macro_rules! passthrough {
806 ($($tt:tt)*) => { $($tt)* }
807}
808
809passthrough!(include!("a.rs"));
810
811fn main() {
812 foo();
813}
814
815//- /a.rs
816fn func_in_include() {
817 //^^^^^^^^^^^^^^^
818}
819
820fn foo() {
821 func_in_include$0();
822}
823"#,
824 );
825 }
826
827 #[test]
828 fn goto_def_in_included_file_inside_mod() {
829 check(
830 r#"
831//- minicore:include
832//- /main.rs
833mod a {
834 include!("b.rs");
835}
836//- /b.rs
837fn func_in_include() {
838 //^^^^^^^^^^^^^^^
839}
840fn foo() {
841 func_in_include$0();
842}
843"#,
844 );
845
846 check(
847 r#"
848//- minicore:include
849//- /main.rs
850mod a {
851 include!("a.rs");
852}
853//- /a.rs
854fn func_in_include() {
855 //^^^^^^^^^^^^^^^
856}
857
858fn foo() {
859 func_in_include$0();
860}
861"#,
862 );
863 }
864
865 #[test]
866 fn goto_def_if_items_same_name() {
867 check(
868 r#"
869trait Trait {
870 type A;
871 const A: i32;
872 //^
873}
874
875struct T;
876impl Trait for T {
877 type A = i32;
878 const A$0: i32 = -9;
879}"#,
880 );
881 }
882 #[test]
883 fn goto_def_in_mac_call_in_attr_invoc() {
884 check(
885 r#"
886//- proc_macros: identity
887pub struct Struct {
888 // ^^^^^^
889 field: i32,
890}
891
892macro_rules! identity {
893 ($($tt:tt)*) => {$($tt)*};
894}
895
896#[proc_macros::identity]
897fn function() {
898 identity!(Struct$0 { field: 0 });
899}
900
901"#,
902 )
903 }
904
905 #[test]
906 fn goto_def_for_extern_crate() {
907 check(
908 r#"
909//- /main.rs crate:main deps:std
910extern crate std$0;
911//- /std/lib.rs crate:std
912// empty
913//^file
914"#,
915 )
916 }
917
918 #[test]
919 fn goto_def_for_renamed_extern_crate() {
920 check(
921 r#"
922//- /main.rs crate:main deps:std
923extern crate std as abc$0;
924//- /std/lib.rs crate:std
925// empty
926//^file
927"#,
928 )
929 }
930
931 #[test]
932 fn goto_def_in_items() {
933 check(
934 r#"
935struct Foo;
936 //^^^
937enum E { X(Foo$0) }
938"#,
939 );
940 }
941
942 #[test]
943 fn goto_def_at_start_of_item() {
944 check(
945 r#"
946struct Foo;
947 //^^^
948enum E { X($0Foo) }
949"#,
950 );
951 }
952
953 #[test]
954 fn goto_definition_resolves_correct_name() {
955 check(
956 r#"
957//- /lib.rs
958use a::Foo;
959mod a;
960mod b;
961enum E { X(Foo$0) }
962
963//- /a.rs
964pub struct Foo;
965 //^^^
966//- /b.rs
967pub struct Foo;
968"#,
969 );
970 }
971
972 #[test]
973 fn goto_def_for_module_declaration() {
974 check(
975 r#"
976//- /lib.rs
977mod $0foo;
978
979//- /foo.rs
980// empty
981//^file
982"#,
983 );
984
985 check(
986 r#"
987//- /lib.rs
988mod $0foo;
989
990//- /foo/mod.rs
991// empty
992//^file
993"#,
994 );
995 }
996
997 #[test]
998 fn goto_def_for_macros() {
999 check(
1000 r#"
1001macro_rules! foo { () => { () } }
1002 //^^^
1003fn bar() {
1004 $0foo!();
1005}
1006"#,
1007 );
1008 }
1009
1010 #[test]
1011 fn goto_def_for_macros_from_other_crates() {
1012 check(
1013 r#"
1014//- /lib.rs crate:main deps:foo
1015use foo::foo;
1016fn bar() {
1017 $0foo!();
1018}
1019
1020//- /foo/lib.rs crate:foo
1021#[macro_export]
1022macro_rules! foo { () => { () } }
1023 //^^^
1024"#,
1025 );
1026 }
1027
1028 #[test]
1029 fn goto_def_for_macros_in_use_tree() {
1030 check(
1031 r#"
1032//- /lib.rs crate:main deps:foo
1033use foo::foo$0;
1034
1035//- /foo/lib.rs crate:foo
1036#[macro_export]
1037macro_rules! foo { () => { () } }
1038 //^^^
1039"#,
1040 );
1041 }
1042
1043 #[test]
1044 fn goto_def_for_macro_defined_fn_with_arg() {
1045 check(
1046 r#"
1047//- /lib.rs
1048macro_rules! define_fn {
1049 ($name:ident) => (fn $name() {})
1050}
1051
1052define_fn!(foo);
1053 //^^^
1054
1055fn bar() {
1056 $0foo();
1057}
1058"#,
1059 );
1060 }
1061
1062 #[test]
1063 fn goto_def_for_macro_defined_fn_no_arg() {
1064 check(
1065 r#"
1066//- /lib.rs
1067macro_rules! define_fn {
1068 () => (fn foo() {})
1069 //^^^
1070}
1071
1072 define_fn!();
1073//^^^^^^^^^^
1074fn bar() {
1075 $0foo();
1076}
1077"#,
1078 );
1079 }
1080
1081 #[test]
1082 fn goto_definition_works_for_macro_inside_pattern() {
1083 check(
1084 r#"
1085//- /lib.rs
1086macro_rules! foo {() => {0}}
1087 //^^^
1088
1089fn bar() {
1090 match (0,1) {
1091 ($0foo!(), _) => {}
1092 }
1093}
1094"#,
1095 );
1096 }
1097
1098 #[test]
1099 fn goto_definition_works_for_macro_inside_match_arm_lhs() {
1100 check(
1101 r#"
1102//- /lib.rs
1103macro_rules! foo {() => {0}}
1104 //^^^
1105fn bar() {
1106 match 0 {
1107 $0foo!() => {}
1108 }
1109}
1110"#,
1111 );
1112 }
1113
1114 #[test]
1115 fn goto_definition_works_for_consts_inside_range_pattern() {
1116 check(
1117 r#"
1118//- /lib.rs
1119const A: u32 = 0;
1120 //^
1121
1122fn bar(v: u32) {
1123 match v {
1124 0..=$0A => {}
1125 _ => {}
1126 }
1127}
1128"#,
1129 );
1130 }
1131
1132 #[test]
1133 fn goto_def_for_use_alias() {
1134 check(
1135 r#"
1136//- /lib.rs crate:main deps:foo
1137use foo as bar$0;
1138
1139//- /foo/lib.rs crate:foo
1140// empty
1141//^file
1142"#,
1143 );
1144 }
1145
1146 #[test]
1147 fn goto_def_for_use_alias_foo_macro() {
1148 check(
1149 r#"
1150//- /lib.rs crate:main deps:foo
1151use foo::foo as bar$0;
1152
1153//- /foo/lib.rs crate:foo
1154#[macro_export]
1155macro_rules! foo { () => { () } }
1156 //^^^
1157"#,
1158 );
1159 }
1160
1161 #[test]
1162 fn goto_def_for_methods() {
1163 check(
1164 r#"
1165struct Foo;
1166impl Foo {
1167 fn frobnicate(&self) { }
1168 //^^^^^^^^^^
1169}
1170
1171fn bar(foo: &Foo) {
1172 foo.frobnicate$0();
1173}
1174"#,
1175 );
1176 }
1177
1178 #[test]
1179 fn goto_def_for_fields() {
1180 check(
1181 r#"
1182struct Foo {
1183 spam: u32,
1184} //^^^^
1185
1186fn bar(foo: &Foo) {
1187 foo.spam$0;
1188}
1189"#,
1190 );
1191 }
1192
1193 #[test]
1194 fn goto_def_for_record_fields() {
1195 check(
1196 r#"
1197//- /lib.rs
1198struct Foo {
1199 spam: u32,
1200} //^^^^
1201
1202fn bar() -> Foo {
1203 Foo {
1204 spam$0: 0,
1205 }
1206}
1207"#,
1208 );
1209 }
1210
1211 #[test]
1212 fn goto_def_for_record_pat_fields() {
1213 check(
1214 r#"
1215//- /lib.rs
1216struct Foo {
1217 spam: u32,
1218} //^^^^
1219
1220fn bar(foo: Foo) -> Foo {
1221 let Foo { spam$0: _, } = foo
1222}
1223"#,
1224 );
1225 }
1226
1227 #[test]
1228 fn goto_def_for_record_fields_macros() {
1229 check(
1230 r"
1231macro_rules! m { () => { 92 };}
1232struct Foo { spam: u32 }
1233 //^^^^
1234
1235fn bar() -> Foo {
1236 Foo { spam$0: m!() }
1237}
1238",
1239 );
1240 }
1241
1242 #[test]
1243 fn goto_for_tuple_fields() {
1244 check(
1245 r#"
1246struct Foo(u32);
1247 //^^^
1248
1249fn bar() {
1250 let foo = Foo(0);
1251 foo.$00;
1252}
1253"#,
1254 );
1255 }
1256
1257 #[test]
1258 fn goto_def_for_ufcs_inherent_methods() {
1259 check(
1260 r#"
1261struct Foo;
1262impl Foo {
1263 fn frobnicate() { }
1264} //^^^^^^^^^^
1265
1266fn bar(foo: &Foo) {
1267 Foo::frobnicate$0();
1268}
1269"#,
1270 );
1271 }
1272
1273 #[test]
1274 fn goto_def_for_ufcs_trait_methods_through_traits() {
1275 check(
1276 r#"
1277trait Foo {
1278 fn frobnicate();
1279} //^^^^^^^^^^
1280
1281fn bar() {
1282 Foo::frobnicate$0();
1283}
1284"#,
1285 );
1286 }
1287
1288 #[test]
1289 fn goto_def_for_ufcs_trait_methods_through_self() {
1290 check(
1291 r#"
1292struct Foo;
1293trait Trait {
1294 fn frobnicate();
1295} //^^^^^^^^^^
1296impl Trait for Foo {}
1297
1298fn bar() {
1299 Foo::frobnicate$0();
1300}
1301"#,
1302 );
1303 }
1304
1305 #[test]
1306 fn goto_definition_on_self() {
1307 check(
1308 r#"
1309struct Foo;
1310impl Foo {
1311 //^^^
1312 pub fn new() -> Self {
1313 Self$0 {}
1314 }
1315}
1316"#,
1317 );
1318 check(
1319 r#"
1320struct Foo;
1321impl Foo {
1322 //^^^
1323 pub fn new() -> Self$0 {
1324 Self {}
1325 }
1326}
1327"#,
1328 );
1329
1330 check(
1331 r#"
1332enum Foo { A }
1333impl Foo {
1334 //^^^
1335 pub fn new() -> Self$0 {
1336 Foo::A
1337 }
1338}
1339"#,
1340 );
1341
1342 check(
1343 r#"
1344enum Foo { A }
1345impl Foo {
1346 //^^^
1347 pub fn thing(a: &Self$0) {
1348 }
1349}
1350"#,
1351 );
1352 }
1353
1354 #[test]
1355 fn goto_definition_on_self_in_trait_impl() {
1356 check(
1357 r#"
1358struct Foo;
1359trait Make {
1360 fn new() -> Self;
1361}
1362impl Make for Foo {
1363 //^^^
1364 fn new() -> Self {
1365 Self$0 {}
1366 }
1367}
1368"#,
1369 );
1370
1371 check(
1372 r#"
1373struct Foo;
1374trait Make {
1375 fn new() -> Self;
1376}
1377impl Make for Foo {
1378 //^^^
1379 fn new() -> Self$0 {
1380 Self {}
1381 }
1382}
1383"#,
1384 );
1385 }
1386
1387 #[test]
1388 fn goto_def_when_used_on_definition_name_itself() {
1389 check(
1390 r#"
1391struct Foo$0 { value: u32 }
1392 //^^^
1393 "#,
1394 );
1395
1396 check(
1397 r#"
1398struct Foo {
1399 field$0: string,
1400} //^^^^^
1401"#,
1402 );
1403
1404 check(
1405 r#"
1406fn foo_test$0() { }
1407 //^^^^^^^^
1408"#,
1409 );
1410
1411 check(
1412 r#"
1413enum Foo$0 { Variant }
1414 //^^^
1415"#,
1416 );
1417
1418 check(
1419 r#"
1420enum Foo {
1421 Variant1,
1422 Variant2$0,
1423 //^^^^^^^^
1424 Variant3,
1425}
1426"#,
1427 );
1428
1429 check(
1430 r#"
1431static INNER$0: &str = "";
1432 //^^^^^
1433"#,
1434 );
1435
1436 check(
1437 r#"
1438const INNER$0: &str = "";
1439 //^^^^^
1440"#,
1441 );
1442
1443 check(
1444 r#"
1445type Thing$0 = Option<()>;
1446 //^^^^^
1447"#,
1448 );
1449
1450 check(
1451 r#"
1452trait Foo$0 { }
1453 //^^^
1454"#,
1455 );
1456
1457 check(
1458 r#"
1459trait Foo$0 = ;
1460 //^^^
1461"#,
1462 );
1463
1464 check(
1465 r#"
1466mod bar$0 { }
1467 //^^^
1468"#,
1469 );
1470 }
1471
1472 #[test]
1473 fn goto_from_macro() {
1474 check(
1475 r#"
1476macro_rules! id {
1477 ($($tt:tt)*) => { $($tt)* }
1478}
1479fn foo() {}
1480 //^^^
1481id! {
1482 fn bar() {
1483 fo$0o();
1484 }
1485}
1486mod confuse_index { fn foo(); }
1487"#,
1488 );
1489 }
1490
1491 #[test]
1492 fn goto_through_format() {
1493 check(
1494 r#"
1495//- minicore: fmt
1496#[macro_export]
1497macro_rules! format {
1498 ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*)))
1499}
1500pub mod __export {
1501 pub use core::format_args;
1502 fn foo() {} // for index confusion
1503}
1504fn foo() -> i8 {}
1505 //^^^
1506fn test() {
1507 format!("{}", fo$0o())
1508}
1509"#,
1510 );
1511 }
1512
1513 #[test]
1514 fn goto_through_included_file() {
1515 check(
1516 r#"
1517//- /main.rs
1518#[rustc_builtin_macro]
1519macro_rules! include {}
1520
1521include!("foo.rs");
1522
1523fn f() {
1524 foo$0();
1525}
1526
1527mod confuse_index {
1528 pub fn foo() {}
1529}
1530
1531//- /foo.rs
1532fn foo() {}
1533 //^^^
1534 "#,
1535 );
1536 }
1537
1538 #[test]
1539 fn goto_through_included_file_struct_with_doc_comment() {
1540 check(
1541 r#"
1542//- /main.rs
1543#[rustc_builtin_macro]
1544macro_rules! include {}
1545
1546include!("foo.rs");
1547
1548fn f() {
1549 let x = Foo$0;
1550}
1551
1552mod confuse_index {
1553 pub struct Foo;
1554}
1555
1556//- /foo.rs
1557/// This is a doc comment
1558pub struct Foo;
1559 //^^^
1560 "#,
1561 );
1562 }
1563
1564 #[test]
1565 fn goto_for_type_param() {
1566 check(
1567 r#"
1568struct Foo<T: Clone> { t: $0T }
1569 //^
1570"#,
1571 );
1572 }
1573
1574 #[test]
1575 fn goto_within_macro() {
1576 check(
1577 r#"
1578macro_rules! id {
1579 ($($tt:tt)*) => ($($tt)*)
1580}
1581
1582fn foo() {
1583 let x = 1;
1584 //^
1585 id!({
1586 let y = $0x;
1587 let z = y;
1588 });
1589}
1590"#,
1591 );
1592
1593 check(
1594 r#"
1595macro_rules! id {
1596 ($($tt:tt)*) => ($($tt)*)
1597}
1598
1599fn foo() {
1600 let x = 1;
1601 id!({
1602 let y = x;
1603 //^
1604 let z = $0y;
1605 });
1606}
1607"#,
1608 );
1609 }
1610
1611 #[test]
1612 fn goto_def_in_local_fn() {
1613 check(
1614 r#"
1615fn main() {
1616 fn foo() {
1617 let x = 92;
1618 //^
1619 $0x;
1620 }
1621}
1622"#,
1623 );
1624 }
1625
1626 #[test]
1627 fn goto_def_in_local_macro() {
1628 check(
1629 r#"
1630fn bar() {
1631 macro_rules! foo { () => { () } }
1632 //^^^
1633 $0foo!();
1634}
1635"#,
1636 );
1637 }
1638
1639 #[test]
1640 fn goto_def_for_field_init_shorthand() {
1641 check(
1642 r#"
1643struct Foo { x: i32 }
1644 //^
1645fn main() {
1646 let x = 92;
1647 //^
1648 Foo { x$0 };
1649}
1650"#,
1651 )
1652 }
1653
1654 #[test]
1655 fn goto_def_for_enum_variant_field() {
1656 check(
1657 r#"
1658enum Foo {
1659 Bar { x: i32 }
1660 //^
1661}
1662fn baz(foo: Foo) {
1663 match foo {
1664 Foo::Bar { x$0 } => x
1665 //^
1666 };
1667}
1668"#,
1669 );
1670 }
1671
1672 #[test]
1673 fn goto_def_for_enum_variant_self_pattern_const() {
1674 check(
1675 r#"
1676enum Foo { Bar }
1677 //^^^
1678impl Foo {
1679 fn baz(self) {
1680 match self { Self::Bar$0 => {} }
1681 }
1682}
1683"#,
1684 );
1685 }
1686
1687 #[test]
1688 fn goto_def_for_enum_variant_self_pattern_record() {
1689 check(
1690 r#"
1691enum Foo { Bar { val: i32 } }
1692 //^^^
1693impl Foo {
1694 fn baz(self) -> i32 {
1695 match self { Self::Bar$0 { val } => {} }
1696 }
1697}
1698"#,
1699 );
1700 }
1701
1702 #[test]
1703 fn goto_def_for_enum_variant_self_expr_const() {
1704 check(
1705 r#"
1706enum Foo { Bar }
1707 //^^^
1708impl Foo {
1709 fn baz(self) { Self::Bar$0; }
1710}
1711"#,
1712 );
1713 }
1714
1715 #[test]
1716 fn goto_def_for_enum_variant_self_expr_record() {
1717 check(
1718 r#"
1719enum Foo { Bar { val: i32 } }
1720 //^^^
1721impl Foo {
1722 fn baz(self) { Self::Bar$0 {val: 4}; }
1723}
1724"#,
1725 );
1726 }
1727
1728 #[test]
1729 fn goto_def_for_type_alias_generic_parameter() {
1730 check(
1731 r#"
1732type Alias<T> = T$0;
1733 //^
1734"#,
1735 )
1736 }
1737
1738 #[test]
1739 fn goto_def_for_macro_container() {
1740 check(
1741 r#"
1742//- /lib.rs crate:main deps:foo
1743foo::module$0::mac!();
1744
1745//- /foo/lib.rs crate:foo
1746pub mod module {
1747 //^^^^^^
1748 #[macro_export]
1749 macro_rules! _mac { () => { () } }
1750 pub use crate::_mac as mac;
1751}
1752"#,
1753 );
1754 }
1755
1756 #[test]
1757 fn goto_def_for_assoc_ty_in_path() {
1758 check(
1759 r#"
1760trait Iterator {
1761 type Item;
1762 //^^^^
1763}
1764
1765fn f() -> impl Iterator<Item$0 = u8> {}
1766"#,
1767 );
1768 }
1769
1770 #[test]
1771 fn goto_def_for_super_assoc_ty_in_path() {
1772 check(
1773 r#"
1774trait Super {
1775 type Item;
1776 //^^^^
1777}
1778
1779trait Sub: Super {}
1780
1781fn f() -> impl Sub<Item$0 = u8> {}
1782"#,
1783 );
1784 }
1785
1786 #[test]
1787 fn goto_def_for_module_declaration_in_path_if_types_and_values_same_name() {
1788 check(
1789 r#"
1790mod bar {
1791 pub struct Foo {}
1792 //^^^
1793 pub fn Foo() {}
1794}
1795
1796fn baz() {
1797 let _foo_enum: bar::Foo$0 = bar::Foo {};
1798}
1799 "#,
1800 )
1801 }
1802
1803 #[test]
1804 fn unknown_assoc_ty() {
1805 check_unresolved(
1806 r#"
1807trait Iterator { type Item; }
1808fn f() -> impl Iterator<Invalid$0 = u8> {}
1809"#,
1810 )
1811 }
1812
1813 #[test]
1814 fn goto_def_for_assoc_ty_in_path_multiple() {
1815 check(
1816 r#"
1817trait Iterator {
1818 type A;
1819 //^
1820 type B;
1821}
1822
1823fn f() -> impl Iterator<A$0 = u8, B = ()> {}
1824"#,
1825 );
1826 check(
1827 r#"
1828trait Iterator {
1829 type A;
1830 type B;
1831 //^
1832}
1833
1834fn f() -> impl Iterator<A = u8, B$0 = ()> {}
1835"#,
1836 );
1837 }
1838
1839 #[test]
1840 fn goto_def_for_assoc_ty_ufcs() {
1841 check(
1842 r#"
1843trait Iterator {
1844 type Item;
1845 //^^^^
1846}
1847
1848fn g() -> <() as Iterator<Item$0 = ()>>::Item {}
1849"#,
1850 );
1851 }
1852
1853 #[test]
1854 fn goto_def_for_assoc_ty_ufcs_multiple() {
1855 check(
1856 r#"
1857trait Iterator {
1858 type A;
1859 //^
1860 type B;
1861}
1862
1863fn g() -> <() as Iterator<A$0 = (), B = u8>>::B {}
1864"#,
1865 );
1866 check(
1867 r#"
1868trait Iterator {
1869 type A;
1870 type B;
1871 //^
1872}
1873
1874fn g() -> <() as Iterator<A = (), B$0 = u8>>::A {}
1875"#,
1876 );
1877 }
1878
1879 #[test]
1880 fn goto_self_param_ty_specified() {
1881 check(
1882 r#"
1883struct Foo {}
1884
1885impl Foo {
1886 fn bar(self: &Foo) {
1887 //^^^^
1888 let foo = sel$0f;
1889 }
1890}"#,
1891 )
1892 }
1893
1894 #[test]
1895 fn goto_self_param_on_decl() {
1896 check(
1897 r#"
1898struct Foo {}
1899
1900impl Foo {
1901 fn bar(&self$0) {
1902 //^^^^
1903 }
1904}"#,
1905 )
1906 }
1907
1908 #[test]
1909 fn goto_lifetime_param_on_decl() {
1910 check(
1911 r#"
1912fn foo<'foobar$0>(_: &'foobar ()) {
1913 //^^^^^^^
1914}"#,
1915 )
1916 }
1917
1918 #[test]
1919 fn goto_lifetime_param_decl() {
1920 check(
1921 r#"
1922fn foo<'foobar>(_: &'foobar$0 ()) {
1923 //^^^^^^^
1924}"#,
1925 )
1926 }
1927
1928 #[test]
1929 fn goto_lifetime_param_decl_nested() {
1930 check(
1931 r#"
1932fn foo<'foobar>(_: &'foobar ()) {
1933 fn foo<'foobar>(_: &'foobar$0 ()) {}
1934 //^^^^^^^
1935}"#,
1936 )
1937 }
1938
1939 #[test]
1940 fn goto_lifetime_hrtb() {
1941 check_unresolved(
1943 r#"
1944trait Foo<T> {}
1945fn foo<T>() where for<'a> T: Foo<&'a$0 (u8, u16)>, {}
1946 //^^
1947"#,
1948 );
1949 check_unresolved(
1950 r#"
1951trait Foo<T> {}
1952fn foo<T>() where for<'a$0> T: Foo<&'a (u8, u16)>, {}
1953 //^^
1954"#,
1955 );
1956 }
1957
1958 #[test]
1959 fn goto_lifetime_hrtb_for_type() {
1960 check_unresolved(
1962 r#"trait Foo<T> {}
1963fn foo<T>() where T: for<'a> Foo<&'a$0 (u8, u16)>, {}
1964 //^^
1965"#,
1966 );
1967 }
1968
1969 #[test]
1970 fn goto_label() {
1971 check(
1972 r#"
1973fn foo<'foo>(_: &'foo ()) {
1974 'foo: {
1975 //^^^^
1976 'bar: loop {
1977 break 'foo$0;
1978 }
1979 }
1980}"#,
1981 )
1982 }
1983
1984 #[test]
1985 fn goto_def_for_intra_doc_link_same_file() {
1986 check(
1987 r#"
1988/// Blah, [`bar`](bar) .. [`foo`](foo$0) has [`bar`](bar)
1989pub fn bar() { }
1990
1991/// You might want to see [`std::fs::read()`] too.
1992pub fn foo() { }
1993 //^^^
1994
1995}"#,
1996 )
1997 }
1998
1999 #[test]
2000 fn goto_def_for_intra_doc_link_outer_same_file() {
2001 check(
2002 r#"
2003/// [`S$0`]
2004mod m {
2005 //! [`super::S`]
2006}
2007struct S;
2008 //^
2009 "#,
2010 );
2011
2012 check(
2013 r#"
2014/// [`S$0`]
2015mod m {}
2016struct S;
2017 //^
2018 "#,
2019 );
2020
2021 check(
2022 r#"
2023/// [`S$0`]
2024fn f() {
2025 //! [`S`]
2026}
2027struct S;
2028 //^
2029 "#,
2030 );
2031 }
2032
2033 #[test]
2034 fn goto_def_for_intra_doc_link_inner_same_file() {
2035 check(
2036 r#"
2037/// [`S`]
2038mod m {
2039 //! [`super::S$0`]
2040}
2041struct S;
2042 //^
2043 "#,
2044 );
2045
2046 check(
2047 r#"
2048mod m {
2049 //! [`super::S$0`]
2050}
2051struct S;
2052 //^
2053 "#,
2054 );
2055
2056 check(
2057 r#"
2058fn f() {
2059 //! [`S$0`]
2060}
2061struct S;
2062 //^
2063 "#,
2064 );
2065 }
2066
2067 #[test]
2068 fn goto_def_for_intra_doc_link_inner() {
2069 check(
2070 r#"
2071//- /main.rs
2072mod m;
2073struct S;
2074 //^
2075
2076//- /m.rs
2077//! [`super::S$0`]
2078"#,
2079 )
2080 }
2081
2082 #[test]
2083 fn goto_incomplete_field() {
2084 check(
2085 r#"
2086struct A { a: u32 }
2087 //^
2088fn foo() { A { a$0: }; }
2089"#,
2090 )
2091 }
2092
2093 #[test]
2094 fn goto_proc_macro() {
2095 check(
2096 r#"
2097//- /main.rs crate:main deps:mac
2098use mac::fn_macro;
2099
2100fn_macro$0!();
2101
2102//- /mac.rs crate:mac
2103#![crate_type="proc-macro"]
2104#[proc_macro]
2105fn fn_macro() {}
2106 //^^^^^^^^
2107 "#,
2108 )
2109 }
2110
2111 #[test]
2112 fn goto_intra_doc_links() {
2113 check(
2114 r#"
2115
2116pub mod theitem {
2117 /// This is the item. Cool!
2118 pub struct TheItem;
2119 //^^^^^^^
2120}
2121
2122/// Gives you a [`TheItem$0`].
2123///
2124/// [`TheItem`]: theitem::TheItem
2125pub fn gimme() -> theitem::TheItem {
2126 theitem::TheItem
2127}
2128"#,
2129 );
2130 }
2131
2132 #[test]
2133 fn goto_ident_from_pat_macro() {
2134 check(
2135 r#"
2136macro_rules! pat {
2137 ($name:ident) => { Enum::Variant1($name) }
2138}
2139
2140enum Enum {
2141 Variant1(u8),
2142 Variant2,
2143}
2144
2145fn f(e: Enum) {
2146 match e {
2147 pat!(bind) => {
2148 //^^^^
2149 bind$0
2150 }
2151 Enum::Variant2 => {}
2152 }
2153}
2154"#,
2155 );
2156 }
2157
2158 #[test]
2159 fn goto_include() {
2160 check(
2161 r#"
2162//- /main.rs
2163
2164#[rustc_builtin_macro]
2165macro_rules! include_str {}
2166
2167fn main() {
2168 let str = include_str!("foo.txt$0");
2169}
2170//- /foo.txt
2171// empty
2172//^file
2173"#,
2174 );
2175 }
2176
2177 #[test]
2178 fn goto_include_has_eager_input() {
2179 check(
2180 r#"
2181//- /main.rs
2182#[rustc_builtin_macro]
2183macro_rules! include_str {}
2184#[rustc_builtin_macro]
2185macro_rules! concat {}
2186
2187fn main() {
2188 let str = include_str!(concat!("foo", ".tx$0t"));
2189}
2190//- /foo.txt
2191// empty
2192//^file
2193"#,
2194 );
2195 }
2196
2197 #[test]
2199 #[should_panic]
2201 fn goto_doc_include_str() {
2202 check(
2203 r#"
2204//- /main.rs
2205#[rustc_builtin_macro]
2206macro_rules! include_str {}
2207
2208#[doc = include_str!("docs.md$0")]
2209struct Item;
2210
2211//- /docs.md
2212// docs
2213//^file
2214"#,
2215 );
2216 }
2217
2218 #[test]
2219 fn goto_shadow_include() {
2220 check(
2221 r#"
2222//- /main.rs
2223macro_rules! include {
2224 ("included.rs") => {}
2225}
2226
2227include!("included.rs$0");
2228
2229//- /included.rs
2230// empty
2231"#,
2232 );
2233 }
2234
2235 mod goto_impl_of_trait_fn {
2236 use super::check;
2237 #[test]
2238 fn cursor_on_impl() {
2239 check(
2240 r#"
2241trait Twait {
2242 fn a();
2243}
2244
2245struct Stwuct;
2246
2247impl Twait for Stwuct {
2248 fn a$0();
2249 //^
2250}
2251 "#,
2252 );
2253 }
2254 #[test]
2255 fn method_call() {
2256 check(
2257 r#"
2258trait Twait {
2259 fn a(&self);
2260}
2261
2262struct Stwuct;
2263
2264impl Twait for Stwuct {
2265 fn a(&self){};
2266 //^
2267}
2268fn f() {
2269 let s = Stwuct;
2270 s.a$0();
2271}
2272 "#,
2273 );
2274 }
2275 #[test]
2276 fn method_call_inside_block() {
2277 check(
2278 r#"
2279trait Twait {
2280 fn a(&self);
2281}
2282
2283fn outer() {
2284 struct Stwuct;
2285
2286 impl Twait for Stwuct {
2287 fn a(&self){}
2288 //^
2289 }
2290 fn f() {
2291 let s = Stwuct;
2292 s.a$0();
2293 }
2294}
2295 "#,
2296 );
2297 }
2298 #[test]
2299 fn path_call() {
2300 check(
2301 r#"
2302trait Twait {
2303 fn a(&self);
2304}
2305
2306struct Stwuct;
2307
2308impl Twait for Stwuct {
2309 fn a(&self){};
2310 //^
2311}
2312fn f() {
2313 let s = Stwuct;
2314 Stwuct::a$0(&s);
2315}
2316 "#,
2317 );
2318 }
2319 #[test]
2320 fn where_clause_can_work() {
2321 check(
2322 r#"
2323trait G {
2324 fn g(&self);
2325}
2326trait Bound{}
2327trait EA{}
2328struct Gen<T>(T);
2329impl <T:EA> G for Gen<T> {
2330 fn g(&self) {
2331 }
2332}
2333impl <T> G for Gen<T>
2334where T : Bound
2335{
2336 fn g(&self){
2337 //^
2338 }
2339}
2340struct A;
2341impl Bound for A{}
2342fn f() {
2343 let g = Gen::<A>(A);
2344 g.g$0();
2345}
2346 "#,
2347 );
2348 }
2349 #[test]
2350 fn wc_case_is_ok() {
2351 check(
2352 r#"
2353trait G {
2354 fn g(&self);
2355}
2356trait BParent{}
2357trait Bound: BParent{}
2358struct Gen<T>(T);
2359impl <T> G for Gen<T>
2360where T : Bound
2361{
2362 fn g(&self){
2363 //^
2364 }
2365}
2366struct A;
2367impl Bound for A{}
2368fn f() {
2369 let g = Gen::<A>(A);
2370 g.g$0();
2371}
2372"#,
2373 );
2374 }
2375
2376 #[test]
2377 fn method_call_defaulted() {
2378 check(
2379 r#"
2380trait Twait {
2381 fn a(&self) {}
2382 //^
2383}
2384
2385struct Stwuct;
2386
2387impl Twait for Stwuct {
2388}
2389fn f() {
2390 let s = Stwuct;
2391 s.a$0();
2392}
2393 "#,
2394 );
2395 }
2396
2397 #[test]
2398 fn method_call_on_generic() {
2399 check(
2400 r#"
2401trait Twait {
2402 fn a(&self) {}
2403 //^
2404}
2405
2406fn f<T: Twait>(s: T) {
2407 s.a$0();
2408}
2409 "#,
2410 );
2411 }
2412 }
2413
2414 #[test]
2415 fn goto_def_of_trait_impl_const() {
2416 check(
2417 r#"
2418trait Twait {
2419 const NOMS: bool;
2420 // ^^^^
2421}
2422
2423struct Stwuct;
2424
2425impl Twait for Stwuct {
2426 const NOMS$0: bool = true;
2427}
2428"#,
2429 );
2430 }
2431
2432 #[test]
2433 fn goto_def_of_trait_impl_type_alias() {
2434 check(
2435 r#"
2436trait Twait {
2437 type IsBad;
2438 // ^^^^^
2439}
2440
2441struct Stwuct;
2442
2443impl Twait for Stwuct {
2444 type IsBad$0 = !;
2445}
2446"#,
2447 );
2448 }
2449
2450 #[test]
2451 fn goto_def_derive_input() {
2452 check(
2453 r#"
2454 //- minicore:derive
2455 #[rustc_builtin_macro]
2456 pub macro Copy {}
2457 // ^^^^
2458 #[derive(Copy$0)]
2459 struct Foo;
2460 "#,
2461 );
2462 check(
2463 r#"
2464//- minicore:derive
2465#[rustc_builtin_macro]
2466pub macro Copy {}
2467 // ^^^^
2468#[cfg_attr(feature = "false", derive)]
2469#[derive(Copy$0)]
2470struct Foo;
2471 "#,
2472 );
2473 check(
2474 r#"
2475//- minicore:derive
2476mod foo {
2477 #[rustc_builtin_macro]
2478 pub macro Copy {}
2479 // ^^^^
2480}
2481#[derive(foo::Copy$0)]
2482struct Foo;
2483 "#,
2484 );
2485 check(
2486 r#"
2487//- minicore:derive
2488mod foo {
2489 // ^^^
2490 #[rustc_builtin_macro]
2491 pub macro Copy {}
2492}
2493#[derive(foo$0::Copy)]
2494struct Foo;
2495 "#,
2496 );
2497 }
2498
2499 #[test]
2500 fn goto_def_in_macro_multi() {
2501 check(
2502 r#"
2503struct Foo {
2504 foo: ()
2505 //^^^
2506}
2507macro_rules! foo {
2508 ($ident:ident) => {
2509 fn $ident(Foo { $ident }: Foo) {}
2510 }
2511}
2512 foo!(foo$0);
2513 //^^^
2514 //^^^
2515"#,
2516 );
2517 check(
2518 r#"
2519fn bar() {}
2520 //^^^
2521struct bar;
2522 //^^^
2523macro_rules! foo {
2524 ($ident:ident) => {
2525 fn foo() {
2526 let _: $ident = $ident;
2527 }
2528 }
2529}
2530
2531foo!(bar$0);
2532"#,
2533 );
2534 }
2535
2536 #[test]
2537 fn goto_await_poll() {
2538 check(
2539 r#"
2540//- minicore: future
2541
2542struct MyFut;
2543
2544impl core::future::Future for MyFut {
2545 type Output = ();
2546
2547 fn poll(
2548 //^^^^
2549 self: std::pin::Pin<&mut Self>,
2550 cx: &mut std::task::Context<'_>
2551 ) -> std::task::Poll<Self::Output>
2552 {
2553 ()
2554 }
2555}
2556
2557fn f() {
2558 MyFut.await$0;
2559}
2560"#,
2561 );
2562 }
2563
2564 #[test]
2565 fn goto_await_into_future_poll() {
2566 check(
2567 r#"
2568//- minicore: future
2569
2570struct Futurable;
2571
2572impl core::future::IntoFuture for Futurable {
2573 type IntoFuture = MyFut;
2574}
2575
2576struct MyFut;
2577
2578impl core::future::Future for MyFut {
2579 type Output = ();
2580
2581 fn poll(
2582 //^^^^
2583 self: std::pin::Pin<&mut Self>,
2584 cx: &mut std::task::Context<'_>
2585 ) -> std::task::Poll<Self::Output>
2586 {
2587 ()
2588 }
2589}
2590
2591fn f() {
2592 Futurable.await$0;
2593}
2594"#,
2595 );
2596 }
2597
2598 #[test]
2599 fn goto_try_op() {
2600 check(
2601 r#"
2602//- minicore: try
2603
2604struct Struct;
2605
2606impl core::ops::Try for Struct {
2607 fn branch(
2608 //^^^^^^
2609 self
2610 ) {}
2611}
2612
2613fn f() {
2614 Struct?$0;
2615}
2616"#,
2617 );
2618 }
2619
2620 #[test]
2621 fn goto_index_op() {
2622 check(
2623 r#"
2624//- minicore: index
2625
2626struct Struct;
2627
2628impl core::ops::Index<usize> for Struct {
2629 fn index(
2630 //^^^^^
2631 self
2632 ) {}
2633}
2634
2635fn f() {
2636 Struct[0]$0;
2637}
2638"#,
2639 );
2640 }
2641
2642 #[test]
2643 fn goto_index_mut_op() {
2644 check(
2645 r#"
2646//- minicore: index
2647
2648struct Foo;
2649struct Bar;
2650
2651impl core::ops::Index<usize> for Foo {
2652 type Output = Bar;
2653
2654 fn index(&self, index: usize) -> &Self::Output {}
2655}
2656
2657impl core::ops::IndexMut<usize> for Foo {
2658 fn index_mut(&mut self, index: usize) -> &mut Self::Output {}
2659 //^^^^^^^^^
2660}
2661
2662fn f() {
2663 let mut foo = Foo;
2664 foo[0]$0 = Bar;
2665}
2666"#,
2667 );
2668 }
2669
2670 #[test]
2671 fn goto_prefix_op() {
2672 check(
2673 r#"
2674//- minicore: deref
2675
2676struct Struct;
2677
2678impl core::ops::Deref for Struct {
2679 fn deref(
2680 //^^^^^
2681 self
2682 ) {}
2683}
2684
2685fn f() {
2686 $0*Struct;
2687}
2688"#,
2689 );
2690 }
2691
2692 #[test]
2693 fn goto_deref_mut() {
2694 check(
2695 r#"
2696//- minicore: deref, deref_mut
2697
2698struct Foo;
2699struct Bar;
2700
2701impl core::ops::Deref for Foo {
2702 type Target = Bar;
2703 fn deref(&self) -> &Self::Target {}
2704}
2705
2706impl core::ops::DerefMut for Foo {
2707 fn deref_mut(&mut self) -> &mut Self::Target {}
2708 //^^^^^^^^^
2709}
2710
2711fn f() {
2712 let a = Foo;
2713 $0*a = Bar;
2714}
2715"#,
2716 );
2717 }
2718
2719 #[test]
2720 fn goto_bin_op() {
2721 check(
2722 r#"
2723//- minicore: add
2724
2725struct Struct;
2726
2727impl core::ops::Add for Struct {
2728 fn add(
2729 //^^^
2730 self
2731 ) {}
2732}
2733
2734fn f() {
2735 Struct +$0 Struct;
2736}
2737"#,
2738 );
2739 }
2740
2741 #[test]
2742 fn goto_bin_op_multiple_impl() {
2743 check(
2744 r#"
2745//- minicore: add
2746struct S;
2747impl core::ops::Add for S {
2748 fn add(
2749 //^^^
2750 ) {}
2751}
2752impl core::ops::Add<usize> for S {
2753 fn add(
2754 ) {}
2755}
2756
2757fn f() {
2758 S +$0 S
2759}
2760"#,
2761 );
2762
2763 check(
2764 r#"
2765//- minicore: add
2766struct S;
2767impl core::ops::Add for S {
2768 fn add(
2769 ) {}
2770}
2771impl core::ops::Add<usize> for S {
2772 fn add(
2773 //^^^
2774 ) {}
2775}
2776
2777fn f() {
2778 S +$0 0usize
2779}
2780"#,
2781 );
2782 }
2783
2784 #[test]
2785 fn path_call_multiple_trait_impl() {
2786 check(
2787 r#"
2788trait Trait<T> {
2789 fn f(_: T);
2790}
2791impl Trait<i32> for usize {
2792 fn f(_: i32) {}
2793 //^
2794}
2795impl Trait<i64> for usize {
2796 fn f(_: i64) {}
2797}
2798fn main() {
2799 usize::f$0(0i32);
2800}
2801"#,
2802 );
2803
2804 check(
2805 r#"
2806trait Trait<T> {
2807 fn f(_: T);
2808}
2809impl Trait<i32> for usize {
2810 fn f(_: i32) {}
2811}
2812impl Trait<i64> for usize {
2813 fn f(_: i64) {}
2814 //^
2815}
2816fn main() {
2817 usize::f$0(0i64);
2818}
2819"#,
2820 )
2821 }
2822
2823 #[test]
2824 fn query_impls_in_nearest_block() {
2825 check(
2826 r#"
2827struct S1;
2828impl S1 {
2829 fn e() -> () {}
2830}
2831fn f1() {
2832 struct S1;
2833 impl S1 {
2834 fn e() -> () {}
2835 //^
2836 }
2837 fn f2() {
2838 fn f3() {
2839 S1::e$0();
2840 }
2841 }
2842}
2843"#,
2844 );
2845
2846 check(
2847 r#"
2848struct S1;
2849impl S1 {
2850 fn e() -> () {}
2851}
2852fn f1() {
2853 struct S1;
2854 impl S1 {
2855 fn e() -> () {}
2856 //^
2857 }
2858 fn f2() {
2859 struct S2;
2860 S1::e$0();
2861 }
2862}
2863fn f12() {
2864 struct S1;
2865 impl S1 {
2866 fn e() -> () {}
2867 }
2868}
2869"#,
2870 );
2871
2872 check(
2873 r#"
2874struct S1;
2875impl S1 {
2876 fn e() -> () {}
2877 //^
2878}
2879fn f2() {
2880 struct S2;
2881 S1::e$0();
2882}
2883"#,
2884 );
2885 }
2886
2887 #[test]
2888 fn implicit_format_args() {
2889 check(
2890 r#"
2891//- minicore: fmt
2892fn test() {
2893 let a = "world";
2894 // ^
2895 format_args!("hello {a$0}");
2896}
2897"#,
2898 );
2899 }
2900
2901 #[test]
2902 fn goto_macro_def_from_macro_use() {
2903 check(
2904 r#"
2905//- /main.rs crate:main deps:mac
2906#[macro_use(foo$0)]
2907extern crate mac;
2908
2909//- /mac.rs crate:mac
2910#[macro_export]
2911macro_rules! foo {
2912 //^^^
2913 () => {};
2914}
2915 "#,
2916 );
2917
2918 check(
2919 r#"
2920//- /main.rs crate:main deps:mac
2921#[macro_use(foo, bar$0, baz)]
2922extern crate mac;
2923
2924//- /mac.rs crate:mac
2925#[macro_export]
2926macro_rules! foo {
2927 () => {};
2928}
2929
2930#[macro_export]
2931macro_rules! bar {
2932 //^^^
2933 () => {};
2934}
2935
2936#[macro_export]
2937macro_rules! baz {
2938 () => {};
2939}
2940 "#,
2941 );
2942 }
2943
2944 #[test]
2945 fn goto_shadowed_preludes_in_block_module() {
2946 check(
2947 r#"
2948//- /main.rs crate:main edition:2021 deps:core
2949pub struct S;
2950 //^
2951
2952fn main() {
2953 fn f() -> S$0 {
2954 fn inner() {} // forces a block def map
2955 return S;
2956 }
2957}
2958//- /core.rs crate:core
2959pub mod prelude {
2960 pub mod rust_2021 {
2961 pub enum S;
2962 }
2963}
2964 "#,
2965 );
2966 }
2967
2968 #[test]
2969 fn goto_def_on_return_kw() {
2970 check(
2971 r#"
2972macro_rules! N {
2973 ($i:ident, $x:expr, $blk:expr) => {
2974 for $i in 0..$x {
2975 $blk
2976 }
2977 };
2978}
2979
2980fn main() {
2981 fn f() {
2982 // ^^
2983 N!(i, 5, {
2984 println!("{}", i);
2985 return$0;
2986 });
2987
2988 for i in 1..5 {
2989 return;
2990 }
2991 (|| {
2992 return;
2993 })();
2994 }
2995}
2996"#,
2997 )
2998 }
2999
3000 #[test]
3001 fn goto_def_on_return_kw_in_closure() {
3002 check(
3003 r#"
3004macro_rules! N {
3005 ($i:ident, $x:expr, $blk:expr) => {
3006 for $i in 0..$x {
3007 $blk
3008 }
3009 };
3010}
3011
3012fn main() {
3013 fn f() {
3014 N!(i, 5, {
3015 println!("{}", i);
3016 return;
3017 });
3018
3019 for i in 1..5 {
3020 return;
3021 }
3022 (|| {
3023 // ^
3024 return$0;
3025 })();
3026 }
3027}
3028"#,
3029 )
3030 }
3031
3032 #[test]
3033 fn goto_def_on_break_kw() {
3034 check(
3035 r#"
3036fn main() {
3037 for i in 1..5 {
3038 // ^^^
3039 break$0;
3040 }
3041}
3042"#,
3043 )
3044 }
3045
3046 #[test]
3047 fn goto_def_on_continue_kw() {
3048 check(
3049 r#"
3050fn main() {
3051 for i in 1..5 {
3052 // ^^^
3053 continue$0;
3054 }
3055}
3056"#,
3057 )
3058 }
3059
3060 #[test]
3061 fn goto_def_on_break_kw_for_block() {
3062 check(
3063 r#"
3064fn main() {
3065 'a:{
3066 // ^^^
3067 break$0 'a;
3068 }
3069}
3070"#,
3071 )
3072 }
3073
3074 #[test]
3075 fn goto_def_on_break_with_label() {
3076 check(
3077 r#"
3078fn foo() {
3079 'outer: loop {
3080 // ^^^^
3081 'inner: loop {
3082 'innermost: loop {
3083 }
3084 break$0 'outer;
3085 }
3086 }
3087}
3088"#,
3089 );
3090 }
3091
3092 #[test]
3093 fn label_inside_macro() {
3094 check(
3095 r#"
3096macro_rules! m {
3097 ($s:stmt) => { $s };
3098}
3099
3100fn foo() {
3101 'label: loop {
3102 // ^^^^^^
3103 m!(continue 'label$0);
3104 }
3105}
3106"#,
3107 );
3108 }
3109
3110 #[test]
3111 fn goto_def_on_return_in_try() {
3112 check(
3113 r#"
3114fn main() {
3115 fn f() {
3116 // ^^
3117 try {
3118 return$0;
3119 }
3120
3121 return;
3122 }
3123}
3124"#,
3125 )
3126 }
3127
3128 #[test]
3129 fn goto_def_on_break_in_try() {
3130 check(
3131 r#"
3132fn main() {
3133 for i in 1..100 {
3134 // ^^^
3135 let x: Result<(), ()> = try {
3136 break$0;
3137 };
3138 }
3139}
3140"#,
3141 )
3142 }
3143
3144 #[test]
3145 fn goto_def_on_return_in_async_block() {
3146 check(
3147 r#"
3148fn main() {
3149 async {
3150 // ^^^^^
3151 return$0;
3152 }
3153}
3154"#,
3155 )
3156 }
3157
3158 #[test]
3159 fn goto_def_on_for_kw() {
3160 check(
3161 r#"
3162fn main() {
3163 for$0 i in 1..5 {}
3164 // ^^^
3165}
3166"#,
3167 )
3168 }
3169
3170 #[test]
3171 fn goto_def_on_fn_kw() {
3172 check(
3173 r#"
3174fn main() {
3175 fn$0 foo() {}
3176 // ^^
3177}
3178"#,
3179 )
3180 }
3181
3182 #[test]
3183 fn shadow_builtin_macro() {
3184 check(
3185 r#"
3186//- minicore: column
3187//- /a.rs crate:a
3188#[macro_export]
3189macro_rules! column { () => {} }
3190 // ^^^^^^
3191
3192//- /b.rs crate:b deps:a
3193use a::column;
3194fn foo() {
3195 $0column!();
3196}
3197 "#,
3198 );
3199 }
3200
3201 #[test]
3202 fn issue_18138() {
3203 check(
3204 r#"
3205mod foo {
3206 macro_rules! x {
3207 () => {
3208 pub struct Foo;
3209 // ^^^
3210 };
3211 }
3212 pub(crate) use x as m;
3213}
3214
3215mod bar {
3216 use crate::m;
3217
3218 m!();
3219 // ^^
3220
3221 fn qux() {
3222 Foo$0;
3223 }
3224}
3225
3226mod m {}
3227
3228use foo::m;
3229"#,
3230 );
3231 }
3232
3233 #[test]
3234 fn macro_label_hygiene() {
3235 check(
3236 r#"
3237macro_rules! m {
3238 ($x:stmt) => {
3239 'bar: loop { $x }
3240 };
3241}
3242
3243fn foo() {
3244 'bar: loop {
3245 // ^^^^
3246 m!(continue 'bar$0);
3247 }
3248}
3249"#,
3250 );
3251 }
3252 #[test]
3253 fn into_call_to_from_definition() {
3254 check(
3255 r#"
3256//- minicore: from
3257struct A;
3258
3259struct B;
3260
3261impl From<A> for B {
3262 fn from(value: A) -> Self {
3263 //^^^^
3264 B
3265 }
3266}
3267
3268fn f() {
3269 let a = A;
3270 let b: B = a.into$0();
3271}
3272 "#,
3273 );
3274 }
3275
3276 #[test]
3277 fn into_call_to_from_definition_within_macro() {
3278 check(
3279 r#"
3280//- proc_macros: identity
3281//- minicore: from
3282struct A;
3283
3284struct B;
3285
3286impl From<A> for B {
3287 fn from(value: A) -> Self {
3288 //^^^^
3289 B
3290 }
3291}
3292
3293#[proc_macros::identity]
3294fn f() {
3295 let a = A;
3296 let b: B = a.into$0();
3297}
3298 "#,
3299 );
3300 }
3301
3302 #[test]
3303 fn into_call_to_from_definition_with_trait_bounds() {
3304 check(
3305 r#"
3306//- minicore: from, iterator
3307struct A;
3308
3309impl<T> From<T> for A
3310where
3311 T: IntoIterator<Item = i64>,
3312{
3313 fn from(value: T) -> Self {
3314 //^^^^
3315 A
3316 }
3317}
3318
3319fn f() {
3320 let a: A = [1, 2, 3].into$0();
3321}
3322 "#,
3323 );
3324 }
3325
3326 #[test]
3327 fn goto_into_definition_if_exists() {
3328 check(
3329 r#"
3330//- minicore: from
3331struct A;
3332
3333struct B;
3334
3335impl Into<B> for A {
3336 fn into(self) -> B {
3337 //^^^^
3338 B
3339 }
3340}
3341
3342fn f() {
3343 let a = A;
3344 let b: B = a.into$0();
3345}
3346 "#,
3347 );
3348 }
3349
3350 #[test]
3351 fn try_into_call_to_try_from_definition() {
3352 check(
3353 r#"
3354//- minicore: from
3355struct A;
3356
3357struct B;
3358
3359impl TryFrom<A> for B {
3360 type Error = String;
3361
3362 fn try_from(value: A) -> Result<Self, Self::Error> {
3363 //^^^^^^^^
3364 Ok(B)
3365 }
3366}
3367
3368fn f() {
3369 let a = A;
3370 let b: Result<B, _> = a.try_into$0();
3371}
3372 "#,
3373 );
3374 }
3375
3376 #[test]
3377 fn goto_try_into_definition_if_exists() {
3378 check(
3379 r#"
3380//- minicore: from
3381struct A;
3382
3383struct B;
3384
3385impl TryInto<B> for A {
3386 type Error = String;
3387
3388 fn try_into(self) -> Result<B, Self::Error> {
3389 //^^^^^^^^
3390 Ok(B)
3391 }
3392}
3393
3394fn f() {
3395 let a = A;
3396 let b: Result<B, _> = a.try_into$0();
3397}
3398 "#,
3399 );
3400 }
3401
3402 #[test]
3403 fn parse_call_to_from_str_definition() {
3404 check(
3405 r#"
3406//- minicore: from, str
3407struct A;
3408impl FromStr for A {
3409 type Error = String;
3410 fn from_str(value: &str) -> Result<Self, Self::Error> {
3411 //^^^^^^^^
3412 Ok(A)
3413 }
3414}
3415fn f() {
3416 let a: Result<A, _> = "aaaaaa".parse$0();
3417}
3418 "#,
3419 );
3420 }
3421
3422 #[test]
3423 fn to_string_call_to_display_definition() {
3424 check(
3425 r#"
3426//- minicore:fmt
3427//- /alloc.rs crate:alloc
3428pub mod string {
3429 pub struct String;
3430 pub trait ToString {
3431 fn to_string(&self) -> String;
3432 }
3433
3434 impl<T: core::fmt::Display> ToString for T {
3435 fn to_string(&self) -> String { String }
3436 }
3437}
3438//- /lib.rs crate:lib deps:alloc
3439use alloc::string::ToString;
3440struct A;
3441impl core::fmt::Display for A {
3442 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {}
3443 // ^^^
3444}
3445fn f() {
3446 A.to_string$0();
3447}
3448 "#,
3449 );
3450 }
3451
3452 #[test]
3453 fn use_inside_body() {
3454 check(
3455 r#"
3456fn main() {
3457 mod nice_module {
3458 pub(super) struct NiceStruct;
3459 // ^^^^^^^^^^
3460 }
3461
3462 use nice_module::NiceStruct$0;
3463
3464 let _ = NiceStruct;
3465}
3466 "#,
3467 );
3468 }
3469
3470 #[test]
3471 fn shadow_builtin_type_by_module() {
3472 check(
3473 r#"
3474mod Foo{
3475pub mod str {
3476 // ^^^
3477 pub fn foo() {}
3478}
3479}
3480
3481fn main() {
3482 use Foo::str;
3483 let s = st$0r::foo();
3484}
3485"#,
3486 );
3487 }
3488
3489 #[test]
3490 fn not_goto_module_because_str_is_builtin_type() {
3491 check(
3492 r#"
3493mod str {
3494pub fn foo() {}
3495}
3496
3497fn main() {
3498 let s = st$0r::f();
3499}
3500"#,
3501 );
3502 }
3503
3504 #[test]
3505 fn struct_shadow_by_module() {
3506 check(
3507 r#"
3508mod foo {
3509 pub mod bar {
3510 // ^^^
3511 pub type baz = usize;
3512 }
3513}
3514struct bar;
3515fn main() {
3516 use foo::bar;
3517 let x: ba$0r::baz = 5;
3518
3519}
3520"#,
3521 );
3522 }
3523
3524 #[test]
3525 fn type_alias_shadow_by_module() {
3526 check(
3527 r#"
3528mod foo {
3529 pub mod bar {
3530 // ^^^
3531 pub fn baz() {}
3532 }
3533}
3534
3535trait Qux {}
3536
3537fn item<bar: Qux>() {
3538 use foo::bar;
3539 ba$0r::baz();
3540}
3541}
3542"#,
3543 );
3544
3545 check(
3546 r#"
3547mod foo {
3548 pub mod bar {
3549 // ^^^
3550 pub fn baz() {}
3551 }
3552}
3553
3554fn item<bar>(x: bar) {
3555 use foo::bar;
3556 let x: bar$0 = x;
3557}
3558"#,
3559 );
3560 }
3561
3562 #[test]
3563 fn trait_shadow_by_module() {
3564 check(
3565 r#"
3566pub mod foo {
3567 pub mod Bar {}
3568 // ^^^
3569}
3570
3571trait Bar {}
3572
3573fn main() {
3574 use foo::Bar;
3575 fn f<Qux: B$0ar>() {}
3576}
3577 "#,
3578 );
3579 }
3580
3581 #[test]
3582 fn const_shadow_by_module() {
3583 check(
3584 r#"
3585pub mod foo {
3586 pub struct u8 {}
3587 pub mod bar {
3588 pub mod u8 {}
3589 }
3590}
3591
3592fn main() {
3593 use foo::u8;
3594 {
3595 use foo::bar::u8;
3596
3597 fn f1<const N: u$08>() {}
3598 }
3599 fn f2<const N: u8>() {}
3600}
3601"#,
3602 );
3603
3604 check(
3605 r#"
3606pub mod foo {
3607 pub struct u8 {}
3608 // ^^
3609 pub mod bar {
3610 pub mod u8 {}
3611 }
3612}
3613
3614fn main() {
3615 use foo::u8;
3616 {
3617 use foo::bar::u8;
3618
3619 fn f1<const N: u8>() {}
3620 }
3621 fn f2<const N: u$08>() {}
3622}
3623"#,
3624 );
3625
3626 check(
3627 r#"
3628pub mod foo {
3629 pub struct buz {}
3630 pub mod bar {
3631 pub mod buz {}
3632 // ^^^
3633 }
3634}
3635
3636fn main() {
3637 use foo::buz;
3638 {
3639 use foo::bar::buz;
3640
3641 fn f1<const N: buz$0>() {}
3642 }
3643}
3644"#,
3645 );
3646 }
3647
3648 #[test]
3649 fn offset_of() {
3650 check(
3651 r#"
3652//- minicore: offset_of
3653struct Foo {
3654 field: i32,
3655 // ^^^^^
3656}
3657
3658fn foo() {
3659 let _ = core::mem::offset_of!(Foo, fiel$0d);
3660}
3661 "#,
3662 );
3663
3664 check(
3665 r#"
3666//- minicore: offset_of
3667struct Bar(Foo);
3668struct Foo {
3669 field: i32,
3670 // ^^^^^
3671}
3672
3673fn foo() {
3674 let _ = core::mem::offset_of!(Bar, 0.fiel$0d);
3675}
3676 "#,
3677 );
3678
3679 check(
3680 r#"
3681//- minicore: offset_of
3682struct Bar(Baz);
3683enum Baz {
3684 Abc(Foo),
3685 None,
3686}
3687struct Foo {
3688 field: i32,
3689 // ^^^^^
3690}
3691
3692fn foo() {
3693 let _ = core::mem::offset_of!(Bar, 0.Abc.0.fiel$0d);
3694}
3695 "#,
3696 );
3697
3698 check(
3699 r#"
3700//- minicore: offset_of
3701struct Bar(Baz);
3702enum Baz {
3703 Abc(Foo),
3704 // ^^^
3705 None,
3706}
3707struct Foo {
3708 field: i32,
3709}
3710
3711fn foo() {
3712 let _ = core::mem::offset_of!(Bar, 0.Ab$0c.0.field);
3713}
3714 "#,
3715 );
3716 }
3717
3718 #[test]
3719 fn goto_def_for_match_keyword() {
3720 check(
3721 r#"
3722fn main() {
3723 match$0 0 {
3724 // ^^^^^
3725 0 => {},
3726 _ => {},
3727 }
3728}
3729"#,
3730 );
3731 }
3732
3733 #[test]
3734 fn goto_def_for_match_arm_fat_arrow() {
3735 check(
3736 r#"
3737fn main() {
3738 match 0 {
3739 0 =>$0 {},
3740 // ^^
3741 _ => {},
3742 }
3743}
3744"#,
3745 );
3746 }
3747
3748 #[test]
3749 fn goto_def_for_if_keyword() {
3750 check(
3751 r#"
3752fn main() {
3753 if$0 true {
3754 // ^^
3755 ()
3756 }
3757}
3758"#,
3759 );
3760 }
3761
3762 #[test]
3763 fn goto_def_for_match_nested_in_if() {
3764 check(
3765 r#"
3766fn main() {
3767 if true {
3768 match$0 0 {
3769 // ^^^^^
3770 0 => {},
3771 _ => {},
3772 }
3773 }
3774}
3775"#,
3776 );
3777 }
3778
3779 #[test]
3780 fn goto_def_for_multiple_match_expressions() {
3781 check(
3782 r#"
3783fn main() {
3784 match 0 {
3785 0 => {},
3786 _ => {},
3787 };
3788
3789 match$0 1 {
3790 // ^^^^^
3791 1 => {},
3792 _ => {},
3793 }
3794}
3795"#,
3796 );
3797 }
3798
3799 #[test]
3800 fn goto_def_for_nested_match_expressions() {
3801 check(
3802 r#"
3803fn main() {
3804 match 0 {
3805 0 => match$0 1 {
3806 // ^^^^^
3807 1 => {},
3808 _ => {},
3809 },
3810 _ => {},
3811 }
3812}
3813"#,
3814 );
3815 }
3816
3817 #[test]
3818 fn goto_def_for_if_else_chains() {
3819 check(
3820 r#"
3821fn main() {
3822 if true {
3823 // ^^
3824 ()
3825 } else if$0 false {
3826 ()
3827 } else {
3828 ()
3829 }
3830}
3831"#,
3832 );
3833 }
3834
3835 #[test]
3836 fn goto_def_for_match_with_guards() {
3837 check(
3838 r#"
3839fn main() {
3840 match 42 {
3841 x if x > 0 =>$0 {},
3842 // ^^
3843 _ => {},
3844 }
3845}
3846"#,
3847 );
3848 }
3849
3850 #[test]
3851 fn goto_def_for_match_with_macro_arm() {
3852 check(
3853 r#"
3854macro_rules! arm {
3855 () => { 0 => {} };
3856}
3857
3858fn main() {
3859 match$0 0 {
3860 // ^^^^^
3861 arm!(),
3862 _ => {},
3863 }
3864}
3865"#,
3866 );
3867 }
3868
3869 #[test]
3870 fn goto_const_from_match_pat_with_tuple_struct() {
3871 check(
3872 r#"
3873struct Tag(u8);
3874struct Path {}
3875
3876const Path: u8 = 0;
3877 // ^^^^
3878fn main() {
3879 match Tag(Path) {
3880 Tag(Path$0) => {}
3881 _ => {}
3882 }
3883}
3884
3885"#,
3886 );
3887 }
3888
3889 #[test]
3890 fn goto_const_from_match_pat() {
3891 check(
3892 r#"
3893type T1 = u8;
3894const T1: u8 = 0;
3895 // ^^
3896fn main() {
3897 let x = 0;
3898 match x {
3899 T1$0 => {}
3900 _ => {}
3901 }
3902}
3903"#,
3904 );
3905 }
3906
3907 #[test]
3908 fn goto_struct_from_match_pat() {
3909 check(
3910 r#"
3911struct T1;
3912 // ^^
3913fn main() {
3914 let x = 0;
3915 match x {
3916 T1$0 => {}
3917 _ => {}
3918 }
3919}
3920"#,
3921 );
3922 }
3923
3924 #[test]
3925 fn no_goto_trait_from_match_pat() {
3926 check(
3927 r#"
3928trait T1 {}
3929fn main() {
3930 let x = 0;
3931 match x {
3932 T1$0 => {}
3933 // ^^
3934 _ => {}
3935 }
3936}
3937"#,
3938 );
3939 }
3940
3941 #[test]
3942 fn goto_builtin_type() {
3943 check(
3944 r#"
3945//- /main.rs crate:main deps:std
3946const _: &str$0 = ""; }
3947
3948//- /libstd.rs crate:std
3949mod prim_str {}
3950// ^^^^^^^^
3951"#,
3952 );
3953 }
3954
3955 #[test]
3956 fn ra_fixture() {
3957 check(
3958 r##"
3959fn fixture(#[rust_analyzer::rust_fixture] ra_fixture: &str) {}
3960
3961fn foo() {
3962 fixture(r#"
3963fn foo() {}
3964// ^^^
3965fn bar() {
3966 f$0oo();
3967}
3968 "#)
3969}
3970 "##,
3971 );
3972 }
3973
3974 #[test]
3975 fn regression_20038() {
3976 check(
3977 r#"
3978//- minicore: clone, fn
3979struct Map<Fut, F>(Fut, F);
3980
3981struct InspectFn<F>(F);
3982
3983trait FnOnce1<A> {
3984 type Output;
3985}
3986
3987trait Future1 {
3988 type Output;
3989}
3990
3991trait FusedFuture1: Future1 {
3992 fn is_terminated(&self) -> bool;
3993 //^^^^^^^^^^^^^
3994}
3995
3996impl<T, A, R> FnOnce1<A> for T
3997where
3998 T: FnOnce(A) -> R,
3999{
4000 type Output = R;
4001}
4002
4003impl<F, A> FnOnce1<A> for InspectFn<F>
4004where
4005 F: for<'a> FnOnce1<&'a A, Output = ()>,
4006{
4007 type Output = A;
4008}
4009
4010impl<Fut, F, T> Future1 for Map<Fut, F>
4011where
4012 Fut: Future1,
4013 F: FnOnce1<Fut::Output, Output = T>,
4014{
4015 type Output = T;
4016}
4017
4018impl<Fut, F, T> FusedFuture1 for Map<Fut, F>
4019where
4020 Fut: Future1,
4021 F: FnOnce1<Fut::Output, Output = T>,
4022{
4023 fn is_terminated(&self) -> bool {
4024 false
4025 }
4026}
4027
4028fn overflows<Fut, F>(inner: &Map<Fut, InspectFn<F>>)
4029where
4030 Map<Fut, InspectFn<F>>: FusedFuture1
4031{
4032 let _x = inner.is_terminated$0();
4033}
4034"#,
4035 )
4036 }
4037}