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