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