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