Skip to main content

hir/
semantics.rs

1//! See `Semantics`.
2
3mod child_by_source;
4mod source_to_def;
5
6use std::{
7    cell::RefCell,
8    convert::Infallible,
9    fmt, iter, mem,
10    ops::{self, ControlFlow, Not},
11};
12
13use base_db::{FxIndexSet, all_crates, toolchain_channel};
14use either::Either;
15use hir_def::{
16    BuiltinDeriveImplId, DefWithBodyId, ExpressionStoreOwnerId, GenericDefId, HasModule, MacroId,
17    StructId, TraitId, VariantId,
18    attrs::parse_extra_crate_attrs,
19    expr_store::{Body, ExprOrPatSource, ExpressionStore, HygieneId, path::Path},
20    hir::{BindingId, Expr, ExprId, ExprOrPatId, Unsafe},
21    nameres::{ModuleOrigin, crate_def_map},
22    resolver::{self, HasResolver, Resolver, TypeNs, ValueNs},
23    type_ref::Mutability,
24};
25use hir_expand::{
26    EditionedFileId, ExpandResult, FileRange, HirFileId, InMacroFile, MacroCallId,
27    attrs::AstPathExt,
28    builtin::{BuiltinFnLikeExpander, EagerExpander},
29    files::{FileRangeWrapper, HirFileRange, InRealFile},
30    mod_path::{ModPath, PathKind},
31    name::AsName,
32};
33use hir_ty::{
34    InferBodyId, InferenceResult, LoweringMode,
35    db::AnonConstId,
36    diagnostics::unsafe_operations,
37    infer_query_with_inspect,
38    next_solver::{
39        AnyImplId, DbInterner,
40        format_proof_tree::{ProofTreeData, dump_proof_tree_structured},
41    },
42};
43use intern::{Interned, Symbol, sym};
44use itertools::Itertools;
45use rustc_hash::{FxHashMap, FxHashSet};
46use smallvec::{SmallVec, smallvec};
47use span::{FileId, SyntaxContext};
48use stdx::{TupleExt, always};
49use syntax::{
50    AstNode, AstPtr, AstToken, Direction, SmolStr, SmolStrBuilder, SyntaxElement, SyntaxKind,
51    SyntaxNode, SyntaxNodePtr, SyntaxToken, T, TextRange, TextSize,
52    algo::skip_trivia_token,
53    ast::{self, HasAttrs as _, HasGenericParams},
54};
55
56use crate::{
57    Adjust, Adjustment, Adt, AnyFunctionId, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const,
58    ConstParam, Crate, DeriveHelper, Enum, EnumVariant, ExpressionStoreOwner, Field, Function,
59    GenericSubstitution, HasSource, Impl, InFile, InlineAsmOperand, ItemInNs, Label, LifetimeParam,
60    Local, Macro, Module, ModuleDef, Name, OverloadedDeref, ScopeDef, Static, Struct, ToolModule,
61    Trait, TupleField, Type, TypeAlias, TypeParam, Union, Variant,
62    db::HirDatabase,
63    semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
64    source_analyzer::{SourceAnalyzer, resolve_hir_path},
65};
66
67const CONTINUE_NO_BREAKS: ControlFlow<Infallible, ()> = ControlFlow::Continue(());
68
69#[derive(Debug, Copy, Clone, PartialEq, Eq)]
70pub enum PathResolution<'db> {
71    /// An item
72    Def(ModuleDef),
73    /// A local binding (only value namespace)
74    Local(Local<'db>),
75    /// A type parameter
76    TypeParam(TypeParam),
77    /// A const parameter
78    ConstParam(ConstParam),
79    SelfType(Impl),
80    BuiltinAttr(BuiltinAttr),
81    ToolModule(ToolModule),
82    DeriveHelper(DeriveHelper),
83}
84
85impl<'db> PathResolution<'db> {
86    pub(crate) fn in_type_ns(&self) -> Option<TypeNs> {
87        match self {
88            PathResolution::Def(ModuleDef::Adt(adt)) => Some(TypeNs::AdtId((*adt).into())),
89            PathResolution::Def(ModuleDef::BuiltinType(builtin)) => {
90                Some(TypeNs::BuiltinType((*builtin).into()))
91            }
92            PathResolution::Def(
93                ModuleDef::Const(_)
94                | ModuleDef::EnumVariant(_)
95                | ModuleDef::Macro(_)
96                | ModuleDef::Function(_)
97                | ModuleDef::Module(_)
98                | ModuleDef::Static(_)
99                | ModuleDef::Trait(_),
100            ) => None,
101            PathResolution::Def(ModuleDef::TypeAlias(alias)) => {
102                Some(TypeNs::TypeAliasId((*alias).into()))
103            }
104            PathResolution::BuiltinAttr(_)
105            | PathResolution::ToolModule(_)
106            | PathResolution::Local(_)
107            | PathResolution::DeriveHelper(_)
108            | PathResolution::ConstParam(_) => None,
109            PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())),
110            PathResolution::SelfType(impl_def) => match impl_def.id {
111                AnyImplId::ImplId(id) => Some(TypeNs::SelfType(id)),
112                AnyImplId::BuiltinDeriveImplId(_) => None,
113            },
114        }
115    }
116}
117
118#[derive(Debug, Copy, Clone, PartialEq, Eq)]
119pub struct PathResolutionPerNs<'db> {
120    pub type_ns: Option<PathResolution<'db>>,
121    pub value_ns: Option<PathResolution<'db>>,
122    pub macro_ns: Option<PathResolution<'db>>,
123}
124
125impl<'db> PathResolutionPerNs<'db> {
126    pub fn new(
127        type_ns: Option<PathResolution<'db>>,
128        value_ns: Option<PathResolution<'db>>,
129        macro_ns: Option<PathResolution<'db>>,
130    ) -> Self {
131        PathResolutionPerNs { type_ns, value_ns, macro_ns }
132    }
133    pub fn any(&self) -> Option<PathResolution<'db>> {
134        self.type_ns.or(self.value_ns).or(self.macro_ns)
135    }
136}
137
138#[derive(Debug)]
139pub struct TypeInfo<'db> {
140    /// The original type of the expression or pattern.
141    pub original: Type<'db>,
142    /// The adjusted type, if an adjustment happened.
143    pub adjusted: Option<Type<'db>>,
144}
145
146impl<'db> TypeInfo<'db> {
147    pub fn original(self) -> Type<'db> {
148        self.original
149    }
150
151    pub fn has_adjustment(&self) -> bool {
152        self.adjusted.is_some()
153    }
154
155    /// The adjusted type, or the original in case no adjustments occurred.
156    pub fn adjusted(self) -> Type<'db> {
157        self.adjusted.unwrap_or(self.original)
158    }
159}
160
161/// Primary API to get semantic information, like types, from syntax trees.
162pub struct Semantics<'db, DB: ?Sized> {
163    pub db: &'db DB,
164    imp: SemanticsImpl<'db>,
165}
166
167type DefWithoutBodyWithAnonConsts = Either<GenericDefId, VariantId>;
168type ExprToAnonConst<'db> = FxHashMap<ExprId, AnonConstId<'db>>;
169type DefAnonConstsMap<'db> = FxHashMap<DefWithoutBodyWithAnonConsts, ExprToAnonConst<'db>>;
170
171pub struct SemanticsImpl<'db> {
172    pub db: &'db dyn HirDatabase,
173    s2d_cache: RefCell<SourceToDefCache<'db>>,
174    /// MacroCall to its expansion's MacroCallId cache
175    macro_call_cache: RefCell<FxHashMap<InFile<ast::MacroCall>, MacroCallId>>,
176    /// All anon consts defined by a *signature* (not a body).
177    signature_anon_consts_cache: RefCell<DefAnonConstsMap<'db>>,
178}
179
180impl<DB: ?Sized> fmt::Debug for Semantics<'_, DB> {
181    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182        write!(f, "Semantics {{ ... }}")
183    }
184}
185
186impl<'db, DB: ?Sized> ops::Deref for Semantics<'db, DB> {
187    type Target = SemanticsImpl<'db>;
188
189    fn deref(&self) -> &Self::Target {
190        &self.imp
191    }
192}
193
194#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
195pub enum LintAttr {
196    Allow,
197    Expect,
198    Warn,
199    Deny,
200    Forbid,
201}
202
203// Note: while this variant of `Semantics<'_, _>` might seem unused, as it does not
204// find actual use within the rust-analyzer project itself, it exists to enable the use
205// within e.g. tracked salsa functions in third-party crates that build upon `ra_ap_hir`.
206impl Semantics<'_, dyn HirDatabase> {
207    /// Creates an instance that's weakly coupled to its underlying database type.
208    pub fn new_dyn(db: &'_ dyn HirDatabase) -> Semantics<'_, dyn HirDatabase> {
209        let impl_ = SemanticsImpl::new(db);
210        Semantics { db, imp: impl_ }
211    }
212}
213
214impl<DB: HirDatabase> Semantics<'_, DB> {
215    /// Creates an instance that's strongly coupled to its underlying database type.
216    pub fn new(db: &DB) -> Semantics<'_, DB> {
217        let impl_ = SemanticsImpl::new(db);
218        Semantics { db, imp: impl_ }
219    }
220}
221
222// Note: We take `DB` as `?Sized` here in order to support type-erased
223// use of `Semantics` via `Semantics<'_, dyn HirDatabase>`:
224impl<DB: HirDatabase + ?Sized> Semantics<'_, DB> {
225    pub fn hir_file_for(&self, syntax_node: &SyntaxNode) -> HirFileId {
226        self.imp.find_file(syntax_node).file_id
227    }
228
229    pub fn token_ancestors_with_macros(
230        &self,
231        token: SyntaxToken,
232    ) -> impl Iterator<Item = SyntaxNode> + '_ {
233        token.parent().into_iter().flat_map(move |it| self.ancestors_with_macros(it))
234    }
235
236    /// Find an AstNode by offset inside SyntaxNode, if it is inside *Macrofile*,
237    /// search up until it is of the target AstNode type
238    pub fn find_node_at_offset_with_macros<N: AstNode>(
239        &self,
240        node: &SyntaxNode,
241        offset: TextSize,
242    ) -> Option<N> {
243        self.imp.ancestors_at_offset_with_macros(node, offset).find_map(N::cast)
244    }
245
246    /// Find an AstNode by offset inside SyntaxNode, if it is inside *MacroCall*,
247    /// descend it and find again
248    // FIXME: Rethink this API
249    pub fn find_node_at_offset_with_descend<N: AstNode>(
250        &self,
251        node: &SyntaxNode,
252        offset: TextSize,
253    ) -> Option<N> {
254        self.imp.descend_node_at_offset(node, offset).flatten().find_map(N::cast)
255    }
256
257    /// Find an AstNode by offset inside SyntaxNode, if it is inside an attribute macro call,
258    /// descend it and find again
259    // FIXME: Rethink this API
260    pub fn find_nodes_at_offset_with_descend<'slf, N: AstNode + 'slf>(
261        &'slf self,
262        node: &SyntaxNode,
263        offset: TextSize,
264    ) -> impl Iterator<Item = N> + 'slf {
265        self.imp.descend_node_at_offset(node, offset).filter_map(|mut it| it.find_map(N::cast))
266    }
267
268    // FIXME: Rethink this API
269    pub fn find_namelike_at_offset_with_descend<'slf>(
270        &'slf self,
271        node: &SyntaxNode,
272        offset: TextSize,
273    ) -> impl Iterator<Item = ast::NameLike> + 'slf {
274        node.token_at_offset(offset)
275            .map(move |token| self.descend_into_macros_no_opaque(token, true))
276            .map(|descendants| descendants.into_iter().filter_map(move |it| it.value.parent()))
277            // re-order the tokens from token_at_offset by returning the ancestors with the smaller first nodes first
278            // See algo::ancestors_at_offset, which uses the same approach
279            .kmerge_by(|left, right| left.text_range().len().lt(&right.text_range().len()))
280            .filter_map(ast::NameLike::cast)
281    }
282
283    pub fn lint_attrs(
284        &self,
285        file_id: FileId,
286        krate: Crate,
287        item: ast::AnyHasAttrs,
288    ) -> impl DoubleEndedIterator<Item = (LintAttr, SmolStr)> {
289        let mut cfg_options = None;
290        let cfg_options = || *cfg_options.get_or_insert_with(|| krate.id.cfg_options(self.db));
291
292        let is_crate_root = file_id == krate.root_file(self.imp.db);
293        let is_source_file = ast::SourceFile::can_cast(item.syntax().kind());
294        let extra_crate_attrs = (is_crate_root && is_source_file)
295            .then(|| {
296                parse_extra_crate_attrs(self.imp.db, krate.id)
297                    .into_iter()
298                    .flat_map(|src| src.attrs())
299            })
300            .into_iter()
301            .flatten();
302
303        let mut result = Vec::new();
304        hir_expand::attrs::expand_cfg_attr::<Infallible>(
305            extra_crate_attrs.chain(ast::attrs_including_inner(&item)),
306            cfg_options,
307            |attr, _| {
308                let ast::Meta::TokenTreeMeta(attr) = attr else {
309                    return ControlFlow::Continue(());
310                };
311                let (Some(segment), Some(tt)) = (attr.path().as_one_segment(), attr.token_tree())
312                else {
313                    return ControlFlow::Continue(());
314                };
315                let lint_attr = match &*segment {
316                    "allow" => LintAttr::Allow,
317                    "expect" => LintAttr::Expect,
318                    "warn" => LintAttr::Warn,
319                    "deny" => LintAttr::Deny,
320                    "forbid" => LintAttr::Forbid,
321                    _ => return ControlFlow::Continue(()),
322                };
323                let mut lint = SmolStrBuilder::new();
324                for token in
325                    tt.syntax().children_with_tokens().filter_map(SyntaxElement::into_token)
326                {
327                    match token.kind() {
328                        T![:] | T![::] => lint.push_str(token.text()),
329                        kind if kind.is_any_identifier() => lint.push_str(token.text()),
330                        T![,] => {
331                            let lint = mem::replace(&mut lint, SmolStrBuilder::new()).finish();
332                            if !lint.is_empty() {
333                                result.push((lint_attr, lint));
334                            }
335                        }
336                        _ => {}
337                    }
338                }
339                let lint = lint.finish();
340                if !lint.is_empty() {
341                    result.push((lint_attr, lint));
342                }
343
344                ControlFlow::Continue(())
345            },
346        );
347        result.into_iter()
348    }
349
350    pub fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<Struct> {
351        self.imp.resolve_range_pat(range_pat).map(Struct::from)
352    }
353
354    pub fn resolve_range_expr(&self, range_expr: &ast::RangeExpr) -> Option<Struct> {
355        self.imp.resolve_range_expr(range_expr).map(Struct::from)
356    }
357
358    pub fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<Function> {
359        self.imp.resolve_await_to_poll(await_expr)
360    }
361
362    pub fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option<Function> {
363        self.imp.resolve_prefix_expr(prefix_expr)
364    }
365
366    pub fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option<Function> {
367        self.imp.resolve_index_expr(index_expr)
368    }
369
370    pub fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option<Function> {
371        self.imp.resolve_bin_expr(bin_expr)
372    }
373
374    pub fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option<Function> {
375        self.imp.resolve_try_expr(try_expr)
376    }
377
378    pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<Variant> {
379        self.imp.resolve_variant(record_lit).map(Variant::from)
380    }
381
382    pub fn file_to_module_def(&self, file: impl Into<FileId>) -> Option<Module> {
383        self.imp.file_to_module_defs(file.into()).next()
384    }
385
386    pub fn file_to_module_defs(&self, file: impl Into<FileId>) -> impl Iterator<Item = Module> {
387        self.imp.file_to_module_defs(file.into())
388    }
389
390    pub fn hir_file_to_module_def(&self, file: impl Into<HirFileId>) -> Option<Module> {
391        self.imp.hir_file_to_module_defs(file.into()).next()
392    }
393
394    pub fn hir_file_to_module_defs(
395        &self,
396        file: impl Into<HirFileId>,
397    ) -> impl Iterator<Item = Module> {
398        self.imp.hir_file_to_module_defs(file.into())
399    }
400
401    pub fn is_nightly(&self, krate: Crate) -> bool {
402        let toolchain = toolchain_channel(self.db.as_dyn_database(), krate.into());
403        // `toolchain == None` means we're in some detached files. Since we have no information on
404        // the toolchain being used, let's just allow unstable items to be listed.
405        matches!(toolchain, Some(base_db::ReleaseChannel::Nightly) | None)
406    }
407
408    pub fn to_adt_def(&self, a: &ast::Adt) -> Option<Adt> {
409        self.imp.to_def(a)
410    }
411
412    pub fn to_const_def(&self, c: &ast::Const) -> Option<Const> {
413        self.imp.to_def(c)
414    }
415
416    pub fn to_enum_def(&self, e: &ast::Enum) -> Option<Enum> {
417        self.imp.to_def(e)
418    }
419
420    pub fn to_enum_variant_def(&self, v: &ast::Variant) -> Option<EnumVariant> {
421        self.imp.to_def(v)
422    }
423
424    pub fn to_fn_def(&self, f: &ast::Fn) -> Option<Function> {
425        self.imp.to_def(f)
426    }
427
428    pub fn to_impl_def(&self, i: &ast::Impl) -> Option<Impl> {
429        self.imp.to_def(i)
430    }
431
432    pub fn to_macro_def(&self, m: &ast::Macro) -> Option<Macro> {
433        self.imp.to_def(m)
434    }
435
436    pub fn to_module_def(&self, m: &ast::Module) -> Option<Module> {
437        self.imp.to_def(m)
438    }
439
440    pub fn to_static_def(&self, s: &ast::Static) -> Option<Static> {
441        self.imp.to_def(s)
442    }
443
444    pub fn to_struct_def(&self, s: &ast::Struct) -> Option<Struct> {
445        self.imp.to_def(s)
446    }
447
448    pub fn to_trait_def(&self, t: &ast::Trait) -> Option<Trait> {
449        self.imp.to_def(t)
450    }
451
452    pub fn to_type_alias_def(&self, t: &ast::TypeAlias) -> Option<TypeAlias> {
453        self.imp.to_def(t)
454    }
455
456    pub fn to_union_def(&self, u: &ast::Union) -> Option<Union> {
457        self.imp.to_def(u)
458    }
459}
460
461impl<'db> SemanticsImpl<'db> {
462    fn new(db: &'db dyn HirDatabase) -> Self {
463        SemanticsImpl {
464            db,
465            s2d_cache: Default::default(),
466            macro_call_cache: Default::default(),
467            signature_anon_consts_cache: Default::default(),
468        }
469    }
470
471    pub fn parse(&self, file_id: EditionedFileId) -> ast::SourceFile {
472        let hir_file_id = file_id.into();
473        let tree = file_id.parse(self.db).tree();
474        self.cache(tree.syntax().clone(), hir_file_id);
475        tree
476    }
477
478    /// If not crate is found for the file, try to return the last crate in topological order.
479    pub fn first_crate(&self, file: FileId) -> Option<Crate> {
480        match self.file_to_module_defs(file).next() {
481            Some(module) => Some(module.krate(self.db)),
482            None => all_crates(self.db).last().copied().map(Into::into),
483        }
484    }
485
486    pub fn attach_first_edition_opt(&self, file: FileId) -> Option<EditionedFileId> {
487        let krate = self.file_to_module_defs(file).next()?.krate(self.db);
488        Some(EditionedFileId::new(self.db, file, krate.edition(self.db)))
489    }
490
491    pub fn attach_first_edition(&self, file: FileId) -> EditionedFileId {
492        self.attach_first_edition_opt(file)
493            .unwrap_or_else(|| EditionedFileId::current_edition(self.db, file))
494    }
495
496    pub fn parse_guess_edition(&self, file_id: FileId) -> ast::SourceFile {
497        let file_id = self.attach_first_edition(file_id);
498
499        let tree = file_id.parse(self.db).tree();
500        self.cache(tree.syntax().clone(), file_id.into());
501        tree
502    }
503
504    pub fn adjust_edition(&self, file_id: HirFileId) -> HirFileId {
505        if let Some(editioned_file_id) = file_id.file_id() {
506            self.attach_first_edition_opt(editioned_file_id.file_id(self.db))
507                .map_or(file_id, Into::into)
508        } else {
509            file_id
510        }
511    }
512
513    pub fn find_parent_file(&self, file_id: HirFileId) -> Option<InFile<SyntaxNode>> {
514        match file_id {
515            HirFileId::FileId(file_id) => {
516                let module = self.file_to_module_defs(file_id.file_id(self.db)).next()?;
517                let def_map = crate_def_map(self.db, module.krate(self.db).id);
518                match def_map[module.id].origin {
519                    ModuleOrigin::CrateRoot { .. } => None,
520                    ModuleOrigin::File { declaration, declaration_tree_id, .. } => {
521                        let file_id = declaration_tree_id.file_id();
522                        let in_file = InFile::new(file_id, declaration);
523                        let node = in_file.to_node(self.db);
524                        let root = node.syntax().tree_top();
525                        self.cache(root, file_id);
526                        Some(in_file.with_value(node.syntax().clone()))
527                    }
528                    _ => unreachable!("FileId can only belong to a file module"),
529                }
530            }
531            HirFileId::MacroFile(macro_file) => {
532                let node = macro_file.loc(self.db).to_node(self.db);
533                let root = node.value.tree_top();
534                self.cache(root, node.file_id);
535                Some(node)
536            }
537        }
538    }
539
540    /// Returns the `SyntaxNode` of the module. If this is a file module, returns
541    /// the `SyntaxNode` of the *definition* file, not of the *declaration*.
542    pub fn module_definition_node(&self, module: Module) -> InFile<SyntaxNode> {
543        let def_map = module.id.def_map(self.db);
544        let definition = def_map[module.id].origin.definition_source(self.db);
545        let definition = definition.map(|it| it.node());
546        let root_node = definition.value.tree_top();
547        self.cache(root_node, definition.file_id);
548        definition
549    }
550
551    pub fn parse_or_expand(&self, file_id: HirFileId) -> SyntaxNode {
552        let node = file_id.parse_or_expand(self.db);
553        self.cache(node.clone(), file_id);
554        node
555    }
556
557    pub fn to_node_syntax(&self, ptr: InFile<SyntaxNodePtr>) -> SyntaxNode {
558        ptr.value.to_node(&self.parse_or_expand(ptr.file_id))
559    }
560
561    pub fn to_node<N: AstNode>(&self, ptr: InFile<AstPtr<N>>) -> N {
562        ptr.value.to_node(&self.parse_or_expand(ptr.file_id))
563    }
564
565    pub fn expand(&self, file_id: MacroCallId) -> ExpandResult<SyntaxNode> {
566        let res = file_id.parse_macro_expansion(self.db).as_ref().map(|it| it.0.syntax_node());
567        self.cache(res.value.clone(), file_id.into());
568        res
569    }
570
571    pub fn expand_macro_call(&self, macro_call: &ast::MacroCall) -> Option<InFile<SyntaxNode>> {
572        let file_id = self.to_def(macro_call)?;
573        let node = self.parse_or_expand(file_id.into());
574        Some(InFile::new(file_id.into(), node))
575    }
576
577    /// Expands the macro if it isn't one of the built-in ones that expand to custom syntax or dummy
578    /// expansions.
579    pub fn expand_allowed_builtins(
580        &self,
581        macro_call: &ast::MacroCall,
582    ) -> Option<ExpandResult<SyntaxNode>> {
583        let file_id = self.to_def(macro_call)?;
584        let macro_call = file_id.loc(self.db);
585
586        let skip = matches!(
587            macro_call.def.kind,
588            hir_expand::MacroDefKind::BuiltIn(
589                _,
590                BuiltinFnLikeExpander::Column
591                    | BuiltinFnLikeExpander::File
592                    | BuiltinFnLikeExpander::ModulePath
593                    | BuiltinFnLikeExpander::Asm
594                    | BuiltinFnLikeExpander::GlobalAsm
595                    | BuiltinFnLikeExpander::NakedAsm
596                    | BuiltinFnLikeExpander::LogSyntax
597                    | BuiltinFnLikeExpander::TraceMacros
598                    | BuiltinFnLikeExpander::FormatArgs
599                    | BuiltinFnLikeExpander::FormatArgsNl
600                    | BuiltinFnLikeExpander::ConstFormatArgs,
601            ) | hir_expand::MacroDefKind::BuiltInEager(_, EagerExpander::CompileError)
602        );
603        if skip {
604            // these macros expand to custom builtin syntax and/or dummy things, no point in
605            // showing these to the user
606            return None;
607        }
608
609        let node = self.expand(file_id);
610        Some(node)
611    }
612
613    /// If `item` has an attribute macro attached to it, expands it.
614    pub fn expand_attr_macro(&self, item: &ast::Item) -> Option<ExpandResult<InFile<SyntaxNode>>> {
615        let src = self.wrap_node_infile(item.clone());
616        let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(src.as_ref()))?;
617        Some(self.expand(macro_call_id).map(|it| InFile::new(macro_call_id.into(), it)))
618    }
619
620    pub fn expand_derive_as_pseudo_attr_macro(&self, attr: &ast::Meta) -> Option<SyntaxNode> {
621        let adt = attr.parent_attr()?.syntax().parent().and_then(ast::Adt::cast)?;
622        let src = self.wrap_node_infile(attr.clone());
623        let call_id = self.with_ctx(|ctx| {
624            ctx.attr_to_derive_macro_call(src.with_value(&adt), src).map(|(_, it, _)| it)
625        })?;
626        Some(self.parse_or_expand(call_id.into()))
627    }
628
629    pub fn resolve_derive_macro(&self, attr: &ast::Meta) -> Option<Vec<Option<Macro>>> {
630        let calls = self.derive_macro_calls(attr)?;
631        self.with_ctx(|ctx| {
632            Some(
633                calls
634                    .into_iter()
635                    .map(|call| {
636                        let call = call?;
637                        match call {
638                            Either::Left(call) => {
639                                macro_call_to_macro_id(ctx, call).map(|id| Macro { id })
640                            }
641                            Either::Right(call) => {
642                                let call = call.loc(self.db);
643                                let krate = call.krate(self.db);
644                                let lang_items = hir_def::lang_item::lang_items(self.db, krate);
645                                call.trait_.derive_macro(lang_items).map(|id| Macro { id })
646                            }
647                        }
648                    })
649                    .collect(),
650            )
651        })
652    }
653
654    pub fn expand_derive_macro(
655        &self,
656        attr: &ast::Meta,
657    ) -> Option<Vec<Option<ExpandResult<SyntaxNode>>>> {
658        let res: Vec<_> = self
659            .derive_macro_calls(attr)?
660            .into_iter()
661            .map(|call| {
662                let file_id = call?.left()?;
663                let ExpandResult { value, err } = file_id.parse_macro_expansion(self.db);
664                let root_node = value.0.syntax_node();
665                self.cache(root_node.clone(), file_id.into());
666                Some(ExpandResult { value: root_node, err: err.clone() })
667            })
668            .collect();
669        Some(res)
670    }
671
672    fn derive_macro_calls(
673        &self,
674        attr: &ast::Meta,
675    ) -> Option<Vec<Option<Either<MacroCallId, BuiltinDeriveImplId>>>> {
676        let adt = attr.parent_attr()?.syntax().parent().and_then(ast::Adt::cast)?;
677        let file_id = self.find_file(adt.syntax()).file_id;
678        let adt = InFile::new(file_id, &adt);
679        let src = InFile::new(file_id, attr.clone());
680        self.with_ctx(|ctx| {
681            let (.., res) = ctx.attr_to_derive_macro_call(adt, src)?;
682            Some(res.to_vec())
683        })
684    }
685
686    pub fn is_derive_annotated(&self, adt: InFile<&ast::Adt>) -> bool {
687        self.with_ctx(|ctx| ctx.file_of_adt_has_derives(adt))
688    }
689
690    pub fn derive_helpers_in_scope(&self, adt: &ast::Adt) -> Option<Vec<(Symbol, Symbol)>> {
691        let sa = self.analyze_no_infer(adt.syntax())?;
692        let id = sa.file_id.ast_id_map(self.db).ast_id(adt);
693        let result = sa
694            .resolver
695            .def_map()
696            .derive_helpers_in_scope(InFile::new(sa.file_id, id))?
697            .iter()
698            .map(|(name, macro_, _)| {
699                let macro_name = Macro::from(*macro_).name(self.db).symbol().clone();
700                (name.symbol().clone(), macro_name)
701            })
702            .collect();
703        Some(result)
704    }
705
706    pub fn derive_helper(&self, attr: &ast::Attr) -> Option<Vec<(Macro, MacroCallId)>> {
707        let adt = attr.syntax().ancestors().find_map(ast::Item::cast).and_then(|it| match it {
708            ast::Item::Struct(it) => Some(ast::Adt::Struct(it)),
709            ast::Item::Enum(it) => Some(ast::Adt::Enum(it)),
710            ast::Item::Union(it) => Some(ast::Adt::Union(it)),
711            _ => None,
712        })?;
713        let attr_name = attr.path().and_then(|it| it.as_single_name_ref())?.as_name();
714        let sa = self.analyze_no_infer(adt.syntax())?;
715        let id = sa.file_id.ast_id_map(self.db).ast_id(&adt);
716        let res: Vec<_> = sa
717            .resolver
718            .def_map()
719            .derive_helpers_in_scope(InFile::new(sa.file_id, id))?
720            .iter()
721            .filter(|&(name, _, _)| *name == attr_name)
722            .filter_map(|&(_, macro_, call)| Some((macro_.into(), call.left()?)))
723            .collect();
724        // FIXME: We filter our builtin derive "fake" expansions, is this correct? Should we still expose them somehow?
725        res.is_empty().not().then_some(res)
726    }
727
728    pub fn is_attr_macro_call(&self, item: InFile<&ast::Item>) -> bool {
729        self.with_ctx(|ctx| ctx.item_to_macro_call(item).is_some())
730    }
731
732    /// Expand the macro call with a different token tree, mapping the `token_to_map` down into the
733    /// expansion. `token_to_map` should be a token from the `speculative args` node.
734    pub fn speculative_expand_macro_call(
735        &self,
736        actual_macro_call: &ast::MacroCall,
737        speculative_args: &ast::TokenTree,
738        token_to_map: SyntaxToken,
739    ) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> {
740        let macro_file = self.to_def(actual_macro_call)?;
741        self.speculative_expand_raw(macro_file, speculative_args.syntax(), token_to_map)
742    }
743
744    pub fn speculative_expand_raw(
745        &self,
746        macro_file: MacroCallId,
747        speculative_args: &SyntaxNode,
748        token_to_map: SyntaxToken,
749    ) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> {
750        macro_file.expand_speculative(self.db, speculative_args, token_to_map)
751    }
752
753    /// Expand the macro call with a different item as the input, mapping the `token_to_map` down into the
754    /// expansion. `token_to_map` should be a token from the `speculative args` node.
755    pub fn speculative_expand_attr_macro(
756        &self,
757        actual_macro_call: &ast::Item,
758        speculative_args: &ast::Item,
759        token_to_map: SyntaxToken,
760    ) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> {
761        let macro_call = self.wrap_node_infile(actual_macro_call.clone());
762        let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(macro_call.as_ref()))?;
763        self.speculative_expand_raw(macro_call_id, speculative_args.syntax(), token_to_map)
764    }
765
766    pub fn speculative_expand_derive_as_pseudo_attr_macro(
767        &self,
768        actual_macro_call: &ast::Attr,
769        speculative_args: &ast::Attr,
770        token_to_map: SyntaxToken,
771    ) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> {
772        let attr = self.wrap_node_infile(actual_macro_call.clone());
773        let adt = actual_macro_call.syntax().parent().and_then(ast::Adt::cast)?;
774        let macro_call_id = self.with_ctx(|ctx| {
775            ctx.attr_to_derive_macro_call(
776                attr.with_value(&adt),
777                attr.with_value(attr.value.meta()?),
778            )
779            .map(|(_, it, _)| it)
780        })?;
781        self.speculative_expand_raw(macro_call_id, speculative_args.syntax(), token_to_map)
782    }
783
784    /// Checks if renaming `renamed` to `new_name` may introduce conflicts with other locals,
785    /// and returns the conflicting locals.
786    pub fn rename_conflicts<'a>(
787        &self,
788        to_be_renamed: &Local<'a>,
789        new_name: &Name,
790    ) -> Vec<Local<'a>> {
791        let (store, root_expr) = to_be_renamed.parent_infer.store_and_root_expr(self.db);
792        let resolver = to_be_renamed.parent.resolver(self.db);
793        let starting_expr = store.binding_owner(to_be_renamed.binding_id).unwrap_or(root_expr);
794        let mut visitor = RenameConflictsVisitor {
795            body: store,
796            conflicts: FxHashSet::default(),
797            db: self.db,
798            new_name: new_name.symbol().clone(),
799            old_name: to_be_renamed.name(self.db).symbol().clone(),
800            owner: to_be_renamed.parent,
801            to_be_renamed: to_be_renamed.binding_id,
802            resolver,
803        };
804        visitor.rename_conflicts(starting_expr);
805        visitor
806            .conflicts
807            .into_iter()
808            .map(|binding_id| Local {
809                parent: to_be_renamed.parent,
810                parent_infer: to_be_renamed.parent_infer,
811                binding_id,
812            })
813            .collect()
814    }
815
816    /// Retrieves all the formatting parts of the format_args! (or `asm!`) template string.
817    pub fn as_format_args_parts(
818        &self,
819        string: &ast::String,
820    ) -> Option<Vec<(TextRange, Option<Either<PathResolution<'db>, InlineAsmOperand>>)>> {
821        let string_start = string.syntax().text_range().start();
822        let token = self.wrap_token_infile(string.syntax().clone());
823        self.descend_into_macros_breakable(token, |token, _| {
824            (|| {
825                let token = token.value;
826                let string = ast::String::cast(token)?;
827                let literal =
828                    string.syntax().parent().filter(|it| it.kind() == SyntaxKind::LITERAL)?;
829                let parent = literal.parent()?;
830                if let Some(format_args) = ast::FormatArgsExpr::cast(parent.clone()) {
831                    let source_analyzer = self.analyze_no_infer(format_args.syntax())?;
832                    let format_args = self.wrap_node_infile(format_args);
833                    let res = source_analyzer
834                        .as_format_args_parts(self.db, format_args.as_ref())?
835                        .map(|(range, res)| (range + string_start, res.map(Either::Left)))
836                        .collect();
837                    Some(res)
838                } else {
839                    let asm = ast::AsmExpr::cast(parent)?;
840                    let source_analyzer = self.analyze_no_infer(asm.syntax())?;
841                    let line = asm.template().position(|it| *it.syntax() == literal)?;
842                    let asm = self.wrap_node_infile(asm);
843                    let (owner, (expr, asm_parts)) = source_analyzer.as_asm_parts(asm.as_ref())?;
844                    let res = asm_parts
845                        .get(line)?
846                        .iter()
847                        .map(|&(range, index)| {
848                            (
849                                range + string_start,
850                                Some(Either::Right(InlineAsmOperand { owner, expr, index })),
851                            )
852                        })
853                        .collect();
854                    Some(res)
855                }
856            })()
857            .map_or(ControlFlow::Continue(()), ControlFlow::Break)
858        })
859    }
860
861    /// Retrieves the formatting part of the format_args! template string at the given offset.
862    ///
863    // FIXME: Type the return type
864    /// Returns the range (pre-expansion) in the string literal corresponding to the resolution,
865    /// absolute file range (post-expansion)
866    /// of the part in the format string (post-expansion), the corresponding string token and the resolution if it
867    /// exists.
868    // FIXME: Remove this in favor of `check_for_format_args_template_with_file`
869    pub fn check_for_format_args_template(
870        &self,
871        original_token: SyntaxToken,
872        offset: TextSize,
873    ) -> Option<(
874        TextRange,
875        HirFileRange,
876        ast::String,
877        Option<Either<PathResolution<'db>, InlineAsmOperand>>,
878    )> {
879        let original_token =
880            self.wrap_token_infile(original_token).map(ast::String::cast).transpose()?;
881        self.check_for_format_args_template_with_file(original_token, offset)
882    }
883
884    /// Retrieves the formatting part of the format_args! template string at the given offset.
885    ///
886    // FIXME: Type the return type
887    /// Returns the range (pre-expansion) in the string literal corresponding to the resolution,
888    /// absolute file range (post-expansion)
889    /// of the part in the format string, the corresponding string token and the resolution if it
890    /// exists.
891    pub fn check_for_format_args_template_with_file(
892        &self,
893        original_token: InFile<ast::String>,
894        offset: TextSize,
895    ) -> Option<(
896        TextRange,
897        HirFileRange,
898        ast::String,
899        Option<Either<PathResolution<'db>, InlineAsmOperand>>,
900    )> {
901        let relative_offset =
902            offset.checked_sub(original_token.value.syntax().text_range().start())?;
903        self.descend_into_macros_breakable(
904            original_token.as_ref().map(|it| it.syntax().clone()),
905            |token, _| {
906                (|| {
907                    let token = token.map(ast::String::cast).transpose()?;
908                    self.resolve_offset_in_format_args(token.as_ref(), relative_offset).map(
909                        |(range, res)| {
910                            (
911                                range + original_token.value.syntax().text_range().start(),
912                                HirFileRange {
913                                    file_id: token.file_id,
914                                    range: range + token.value.syntax().text_range().start(),
915                                },
916                                token.value,
917                                res,
918                            )
919                        },
920                    )
921                })()
922                .map_or(ControlFlow::Continue(()), ControlFlow::Break)
923            },
924        )
925    }
926
927    fn resolve_offset_in_format_args(
928        &self,
929        InFile { value: string, file_id }: InFile<&ast::String>,
930        offset: TextSize,
931    ) -> Option<(TextRange, Option<Either<PathResolution<'db>, InlineAsmOperand>>)> {
932        debug_assert!(offset <= string.syntax().text_range().len());
933        let literal = string.syntax().parent().filter(|it| it.kind() == SyntaxKind::LITERAL)?;
934        let parent = literal.parent()?;
935        if let Some(format_args) = ast::FormatArgsExpr::cast(parent.clone()) {
936            let source_analyzer =
937                self.analyze_impl(InFile::new(file_id, format_args.syntax()), None, false)?;
938            source_analyzer
939                .resolve_offset_in_format_args(self.db, InFile::new(file_id, &format_args), offset)
940                .map(|(range, res)| (range, res.map(Either::Left)))
941        } else {
942            let asm = ast::AsmExpr::cast(parent)?;
943            let source_analyzer =
944                self.analyze_impl(InFile::new(file_id, asm.syntax()), None, false)?;
945            let line = asm.template().position(|it| *it.syntax() == literal)?;
946            source_analyzer
947                .resolve_offset_in_asm_template(InFile::new(file_id, &asm), line, offset)
948                .map(|(owner, (expr, range, index))| {
949                    (range, Some(Either::Right(InlineAsmOperand { owner, expr, index })))
950                })
951        }
952    }
953
954    pub fn debug_hir_at(&self, token: SyntaxToken) -> Option<String> {
955        self.analyze_no_infer(&token.parent()?).and_then(|it| {
956            Some(match it.body_or_sig.as_ref()? {
957                crate::source_analyzer::BodyOrSig::Body { def, body, .. } => {
958                    hir_def::expr_store::pretty::print_body_hir(
959                        self.db,
960                        body,
961                        *def,
962                        it.file_id.edition(self.db),
963                    )
964                }
965                &crate::source_analyzer::BodyOrSig::VariantFields { def, .. } => {
966                    hir_def::expr_store::pretty::print_variant_body_hir(
967                        self.db,
968                        def,
969                        it.file_id.edition(self.db),
970                    )
971                }
972                &crate::source_analyzer::BodyOrSig::Sig { def, .. } => {
973                    hir_def::expr_store::pretty::print_signature(
974                        self.db,
975                        def,
976                        it.file_id.edition(self.db),
977                    )
978                }
979            })
980        })
981    }
982
983    /// Descends the token into the include expansion, if its file is an included file.
984    pub fn descend_token_into_include_expansion(
985        &self,
986        tok: InRealFile<SyntaxToken>,
987    ) -> InFile<SyntaxToken> {
988        let Some(include) =
989            self.s2d_cache.borrow_mut().get_or_insert_include_for(self.db, tok.file_id)
990        else {
991            return tok.into();
992        };
993        let span =
994            HirFileId::from(tok.file_id).span_map(self.db).span_for_range(tok.value.text_range());
995        let Some(InMacroFile { file_id, value: mut mapped_tokens }) = self.with_ctx(|ctx| {
996            Some(
997                ctx.cache
998                    .get_or_insert_expansion(ctx.db, include)
999                    .map_range_down(span)?
1000                    .map(SmallVec::<[_; 2]>::from_iter),
1001            )
1002        }) else {
1003            return tok.into();
1004        };
1005        // We should only get one result at most
1006        mapped_tokens.pop().map_or_else(|| tok.into(), |(tok, _)| InFile::new(file_id.into(), tok))
1007    }
1008
1009    /// Maps a node down by mapping its first and last token down.
1010    pub fn descend_node_into_attributes<N: AstNode>(&self, node: N) -> SmallVec<[N; 1]> {
1011        // This might not be the correct way to do this, but it works for now
1012        let mut res = smallvec![];
1013        let tokens = (|| {
1014            // FIXME: the trivia skipping should not be necessary
1015            let first = skip_trivia_token(node.syntax().first_token()?, Direction::Next)?;
1016            let last = skip_trivia_token(node.syntax().last_token()?, Direction::Prev)?;
1017            Some((first, last))
1018        })();
1019        let (first, last) = match tokens {
1020            Some(it) => it,
1021            None => return res,
1022        };
1023        let file = self.find_file(node.syntax());
1024
1025        if first == last {
1026            // node is just the token, so descend the token
1027            self.descend_into_macros_all(
1028                InFile::new(file.file_id, first),
1029                false,
1030                &mut |InFile { value, .. }, _ctx| {
1031                    if let Some(node) = value
1032                        .parent_ancestors()
1033                        .take_while(|it| it.text_range() == value.text_range())
1034                        .find_map(N::cast)
1035                    {
1036                        res.push(node)
1037                    }
1038                },
1039            );
1040        } else {
1041            // Descend first and last token, then zip them to look for the node they belong to
1042            let mut scratch: SmallVec<[_; 1]> = smallvec![];
1043            self.descend_into_macros_all(
1044                InFile::new(file.file_id, first),
1045                false,
1046                &mut |token, _ctx| scratch.push(token),
1047            );
1048
1049            let mut scratch = scratch.into_iter();
1050            self.descend_into_macros_all(
1051                InFile::new(file.file_id, last),
1052                false,
1053                &mut |InFile { value: last, file_id: last_fid }, _ctx| {
1054                    if let Some(InFile { value: first, file_id: first_fid }) = scratch.next()
1055                        && first_fid == last_fid
1056                        && let Some(p) = first.parent()
1057                    {
1058                        let range = first.text_range().cover(last.text_range());
1059                        let node = p
1060                            .tree_top()
1061                            .covering_element(range)
1062                            .ancestors()
1063                            .take_while(|it| it.text_range() == range)
1064                            .find_map(N::cast);
1065                        if let Some(node) = node {
1066                            res.push(node);
1067                        }
1068                    }
1069                },
1070            );
1071        }
1072        res
1073    }
1074
1075    /// Returns true if the given input is within a macro call.
1076    ///
1077    /// Note that if this token itself is within the context of a macro expansion does not matter.
1078    /// That is, we strictly check if it lies inside the input of a macro call.
1079    pub fn is_inside_macro_call(&self, token @ InFile { value, .. }: InFile<&SyntaxToken>) -> bool {
1080        value.parent_ancestors().any(|ancestor| {
1081            if let Some(macro_call) = ast::MacroCall::cast(ancestor.clone())
1082                // If this is the *path* of a macro, it's not inside the call.
1083                && macro_call.path().is_none_or(|path| {
1084                    !path.syntax().text_range().contains_range(value.text_range())
1085                })
1086            {
1087                return true;
1088            }
1089
1090            let Some(item) = ast::Item::cast(ancestor) else {
1091                return false;
1092            };
1093            self.with_ctx(|ctx| {
1094                if ctx.item_to_macro_call(token.with_value(&item)).is_some() {
1095                    return true;
1096                }
1097                let adt = match item {
1098                    ast::Item::Struct(it) => it.into(),
1099                    ast::Item::Enum(it) => it.into(),
1100                    ast::Item::Union(it) => it.into(),
1101                    _ => return false,
1102                };
1103                ctx.file_of_adt_has_derives(token.with_value(&adt))
1104            })
1105        })
1106    }
1107
1108    pub fn descend_into_macros_cb(
1109        &self,
1110        token: SyntaxToken,
1111        mut cb: impl FnMut(InFile<SyntaxToken>, SyntaxContext),
1112    ) {
1113        self.descend_into_macros_all(self.wrap_token_infile(token), false, &mut |t, ctx| {
1114            cb(t, ctx)
1115        });
1116    }
1117
1118    pub fn descend_into_macros(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> {
1119        let mut res = smallvec![];
1120        self.descend_into_macros_all(
1121            self.wrap_token_infile(token.clone()),
1122            false,
1123            &mut |t, _ctx| res.push(t.value),
1124        );
1125        if res.is_empty() {
1126            res.push(token);
1127        }
1128        res
1129    }
1130
1131    pub fn descend_into_macros_no_opaque(
1132        &self,
1133        token: SyntaxToken,
1134        always_descend_into_derives: bool,
1135    ) -> SmallVec<[InFile<SyntaxToken>; 1]> {
1136        let mut res = smallvec![];
1137        let token = self.wrap_token_infile(token);
1138        self.descend_into_macros_all(token.clone(), always_descend_into_derives, &mut |t, ctx| {
1139            if !ctx.is_opaque(self.db) {
1140                // Don't descend into opaque contexts
1141                res.push(t);
1142            }
1143        });
1144        if res.is_empty() {
1145            res.push(token);
1146        }
1147        res
1148    }
1149
1150    pub fn descend_into_macros_breakable<T>(
1151        &self,
1152        token: InFile<SyntaxToken>,
1153        mut cb: impl FnMut(InFile<SyntaxToken>, SyntaxContext) -> ControlFlow<T>,
1154    ) -> Option<T> {
1155        self.descend_into_macros_impl(token, false, &mut cb)
1156    }
1157
1158    /// Descends the token into expansions, returning the tokens that matches the input
1159    /// token's [`SyntaxKind`] and text.
1160    pub fn descend_into_macros_exact(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> {
1161        let mut r = smallvec![];
1162        let text = token.text();
1163        let kind = token.kind();
1164
1165        self.descend_into_macros_cb(token.clone(), |InFile { value, file_id: _ }, ctx| {
1166            let mapped_kind = value.kind();
1167            let any_ident_match = || kind.is_any_identifier() && value.kind().is_any_identifier();
1168            let matches = (kind == mapped_kind || any_ident_match())
1169                && text == value.text()
1170                && !ctx.is_opaque(self.db);
1171            if matches {
1172                r.push(value);
1173            }
1174        });
1175        if r.is_empty() {
1176            r.push(token);
1177        }
1178        r
1179    }
1180
1181    /// Descends the token into expansions, returning the tokens that matches the input
1182    /// token's [`SyntaxKind`] and text.
1183    pub fn descend_into_macros_exact_with_file(
1184        &self,
1185        token: SyntaxToken,
1186    ) -> SmallVec<[InFile<SyntaxToken>; 1]> {
1187        let mut r = smallvec![];
1188        let text = token.text();
1189        let kind = token.kind();
1190
1191        self.descend_into_macros_cb(token.clone(), |InFile { value, file_id }, ctx| {
1192            let mapped_kind = value.kind();
1193            let any_ident_match = || kind.is_any_identifier() && value.kind().is_any_identifier();
1194            let matches = (kind == mapped_kind || any_ident_match())
1195                && text == value.text()
1196                && !ctx.is_opaque(self.db);
1197            if matches {
1198                r.push(InFile { value, file_id });
1199            }
1200        });
1201        if r.is_empty() {
1202            r.push(self.wrap_token_infile(token));
1203        }
1204        r
1205    }
1206
1207    /// Descends the token into expansions, returning the first token that matches the input
1208    /// token's [`SyntaxKind`] and text.
1209    pub fn descend_into_macros_single_exact(&self, token: SyntaxToken) -> SyntaxToken {
1210        let text = token.text();
1211        let kind = token.kind();
1212        self.descend_into_macros_breakable(
1213            self.wrap_token_infile(token.clone()),
1214            |InFile { value, file_id: _ }, _ctx| {
1215                let mapped_kind = value.kind();
1216                let any_ident_match =
1217                    || kind.is_any_identifier() && value.kind().is_any_identifier();
1218                let matches = (kind == mapped_kind || any_ident_match()) && text == value.text();
1219                if matches { ControlFlow::Break(value) } else { ControlFlow::Continue(()) }
1220            },
1221        )
1222        .unwrap_or(token)
1223    }
1224
1225    fn descend_into_macros_all(
1226        &self,
1227        token: InFile<SyntaxToken>,
1228        always_descend_into_derives: bool,
1229        f: &mut dyn FnMut(InFile<SyntaxToken>, SyntaxContext),
1230    ) {
1231        self.descend_into_macros_impl(token, always_descend_into_derives, &mut |tok, ctx| {
1232            f(tok, ctx);
1233            CONTINUE_NO_BREAKS
1234        });
1235    }
1236
1237    fn descend_into_macros_impl<T>(
1238        &self,
1239        InFile { value: token, file_id }: InFile<SyntaxToken>,
1240        always_descend_into_derives: bool,
1241        f: &mut dyn FnMut(InFile<SyntaxToken>, SyntaxContext) -> ControlFlow<T>,
1242    ) -> Option<T> {
1243        let _p = tracing::info_span!("descend_into_macros_impl").entered();
1244
1245        let db = self.db;
1246        let span = file_id.span_map(db).span_for_range(token.text_range());
1247
1248        // Process the expansion of a call, pushing all tokens with our span in the expansion back onto our stack
1249        let process_expansion_for_token =
1250            |ctx: &mut SourceToDefCtx<'_, '_>, stack: &mut Vec<_>, macro_file| {
1251                let InMacroFile { file_id, value: mapped_tokens } = ctx
1252                    .cache
1253                    .get_or_insert_expansion(ctx.db, macro_file)
1254                    .map_range_down(span)?
1255                    .map(SmallVec::<[_; 2]>::from_iter);
1256                // we have found a mapping for the token if the vec is non-empty
1257                let res = mapped_tokens.is_empty().not().then_some(());
1258                // requeue the tokens we got from mapping our current token down
1259                stack.push((HirFileId::from(file_id), mapped_tokens));
1260                res
1261            };
1262
1263        // A stack of tokens to process, along with the file they came from
1264        // These are tracked to know which macro calls we still have to look into
1265        // the tokens themselves aren't that interesting as the span that is being used to map
1266        // things down never changes.
1267        let mut stack: Vec<(_, SmallVec<[_; 2]>)> = vec![];
1268        let include = file_id
1269            .file_id()
1270            .and_then(|file_id| self.s2d_cache.borrow_mut().get_or_insert_include_for(db, file_id));
1271        match include {
1272            Some(include) => {
1273                // include! inputs are always from real files, so they only need to be handled once upfront
1274                self.with_ctx(|ctx| process_expansion_for_token(ctx, &mut stack, include))?;
1275            }
1276            None => {
1277                stack.push((file_id, smallvec![(token, span.ctx)]));
1278            }
1279        }
1280
1281        let mut m_cache = self.macro_call_cache.borrow_mut();
1282
1283        // Filters out all tokens that contain the given range (usually the macro call), any such
1284        // token is redundant as the corresponding macro call has already been processed
1285        let filter_duplicates = |tokens: &mut SmallVec<_>, range: TextRange| {
1286            tokens.retain(|(t, _): &mut (SyntaxToken, _)| !range.contains_range(t.text_range()))
1287        };
1288
1289        while let Some((expansion, ref mut tokens)) = stack.pop() {
1290            // Reverse the tokens so we prefer first tokens (to accommodate for popping from the
1291            // back)
1292            // alternatively we could pop from the front but that would shift the content on every pop
1293            tokens.reverse();
1294            while let Some((token, ctx)) = tokens.pop() {
1295                let was_not_remapped = (|| {
1296                    // First expand into attribute invocations, this is required to be handled
1297                    // upfront as any other macro call within will not semantically resolve unless
1298                    // also descended.
1299                    let res = self.with_ctx(|ctx| {
1300                        token
1301                            .parent_ancestors()
1302                            .filter_map(ast::Item::cast)
1303                            // FIXME: This might work incorrectly when we have a derive, followed by
1304                            // an attribute on an item, like:
1305                            // ```
1306                            // #[derive(Debug$0)]
1307                            // #[my_attr]
1308                            // struct MyStruct;
1309                            // ```
1310                            // here we should not consider the attribute at all, as our cursor
1311                            // technically lies outside of its expansion
1312                            .find_map(|item| {
1313                                // Don't force populate the dyn cache for items that don't have an attribute anyways
1314                                item.attrs().next()?;
1315                                ctx.item_to_macro_call(InFile::new(expansion, &item))
1316                                    .zip(Some(item))
1317                            })
1318                            .map(|(call_id, item)| {
1319                                let item_range = item.syntax().text_range();
1320                                let loc = call_id.loc(db);
1321                                let text_range = match &loc.kind {
1322                                    hir_expand::MacroCallKind::Attr {
1323                                        censored_attr_ids: attr_ids,
1324                                        ..
1325                                    } => {
1326                                        // FIXME: here, the attribute's text range is used to strip away all
1327                                        // entries from the start of the attribute "list" up the invoking
1328                                        // attribute. But in
1329                                        // ```
1330                                        // mod foo {
1331                                        //     #![inner]
1332                                        // }
1333                                        // ```
1334                                        // we don't wanna strip away stuff in the `mod foo {` range, that is
1335                                        // here if the id corresponds to an inner attribute we got strip all
1336                                        // text ranges of the outer ones, and then all of the inner ones up
1337                                        // to the invoking attribute so that the inbetween is ignored.
1338                                        // FIXME: Should cfg_attr be handled differently?
1339                                        let (attr, _) = attr_ids
1340                                            .invoc_attr()
1341                                            .find_attr_range_with_source(db, loc.krate, &item);
1342                                        let start = attr.syntax().text_range().start();
1343                                        TextRange::new(start, item_range.end())
1344                                    }
1345                                    _ => item_range,
1346                                };
1347                                filter_duplicates(tokens, text_range);
1348                                process_expansion_for_token(ctx, &mut stack, call_id)
1349                            })
1350                    });
1351
1352                    if let Some(res) = res {
1353                        return res;
1354                    }
1355
1356                    if always_descend_into_derives {
1357                        let res = self.with_ctx(|ctx| {
1358                            let (derives, adt) = token
1359                                .parent_ancestors()
1360                                .filter_map(ast::Adt::cast)
1361                                .find_map(|adt| {
1362                                    Some((
1363                                        ctx.derive_macro_calls(InFile::new(expansion, &adt))?
1364                                            .map(|(a, b, c)| (a, b, c.to_owned()))
1365                                            .collect::<SmallVec<[_; 2]>>(),
1366                                        adt,
1367                                    ))
1368                                })?;
1369                            for (_, derive_attr, derives) in derives {
1370                                // as there may be multiple derives registering the same helper
1371                                // name, we gotta make sure to call this for all of them!
1372                                // FIXME: We need to call `f` for all of them as well though!
1373                                process_expansion_for_token(ctx, &mut stack, derive_attr);
1374                                for derive in derives.into_iter().flatten() {
1375                                    let Either::Left(derive) = derive else { continue };
1376                                    process_expansion_for_token(ctx, &mut stack, derive);
1377                                }
1378                            }
1379                            // remove all tokens that are within the derives expansion
1380                            filter_duplicates(tokens, adt.syntax().text_range());
1381                            Some(())
1382                        });
1383                        // if we found derives, we can early exit. There is no way we can be in any
1384                        // macro call at this point given we are not in a token tree
1385                        if let Some(()) = res {
1386                            // Note: derives do not remap the original token. Furthermore, we want
1387                            // the original token to be before the derives in the list, because if they
1388                            // upmap to the same token and we deduplicate them (e.g. in rename), we
1389                            // want the original token to remain, not the derive.
1390                            return None;
1391                        }
1392                    }
1393                    // Then check for token trees, that means we are either in a function-like macro or
1394                    // secondary attribute inputs
1395                    let tt = token
1396                        .parent_ancestors()
1397                        .map_while(Either::<ast::TokenTree, ast::Meta>::cast)
1398                        .last()?;
1399
1400                    match tt {
1401                        // function-like macro call
1402                        Either::Left(tt) => {
1403                            let macro_call = tt.syntax().parent().and_then(ast::MacroCall::cast)?;
1404                            if tt.left_delimiter_token().map_or(false, |it| it == token) {
1405                                return None;
1406                            }
1407                            if tt.right_delimiter_token().map_or(false, |it| it == token) {
1408                                return None;
1409                            }
1410                            let mcall = InFile::new(expansion, macro_call);
1411                            let file_id = match m_cache.get(&mcall) {
1412                                Some(&it) => it,
1413                                None => {
1414                                    let it = ast::MacroCall::to_def(self, mcall.as_ref())?;
1415                                    m_cache.insert(mcall, it);
1416                                    it
1417                                }
1418                            };
1419                            let text_range = tt.syntax().text_range();
1420                            filter_duplicates(tokens, text_range);
1421
1422                            self.with_ctx(|ctx| {
1423                                process_expansion_for_token(ctx, &mut stack, file_id).or(file_id
1424                                    .eager_arg(db)
1425                                    .and_then(|arg| {
1426                                        // also descend into eager expansions
1427                                        process_expansion_for_token(ctx, &mut stack, arg)
1428                                    }))
1429                            })
1430                        }
1431                        Either::Right(_) if always_descend_into_derives => None,
1432                        // derive or derive helper
1433                        Either::Right(meta) => {
1434                            // attribute we failed expansion for earlier, this might be a derive invocation
1435                            // or derive helper attribute
1436                            let attr = meta.parent_attr()?;
1437                            let adt = match attr.syntax().parent().and_then(ast::Adt::cast) {
1438                                Some(adt) => {
1439                                    // this might be a derive on an ADT
1440                                    let res = self.with_ctx(|ctx| {
1441                                        // so try downmapping the token into the pseudo derive expansion
1442                                        // see [hir_expand::builtin_attr_macro] for how the pseudo derive expansion works
1443                                        let derive_call = ctx
1444                                            .attr_to_derive_macro_call(
1445                                                InFile::new(expansion, &adt),
1446                                                InFile::new(expansion, meta.clone()),
1447                                            )?
1448                                            .1;
1449
1450                                        // resolved to a derive
1451                                        let text_range = attr.syntax().text_range();
1452                                        // remove any other token in this macro input, all their mappings are the
1453                                        // same as this
1454                                        tokens.retain(|(t, _)| {
1455                                            !text_range.contains_range(t.text_range())
1456                                        });
1457                                        Some(process_expansion_for_token(
1458                                            ctx,
1459                                            &mut stack,
1460                                            derive_call,
1461                                        ))
1462                                    });
1463                                    if let Some(res) = res {
1464                                        return res;
1465                                    }
1466                                    Some(adt)
1467                                }
1468                                None => {
1469                                    // Otherwise this could be a derive helper on a variant or field
1470                                    attr.syntax().ancestors().find_map(ast::Item::cast).and_then(
1471                                        |it| match it {
1472                                            ast::Item::Struct(it) => Some(ast::Adt::Struct(it)),
1473                                            ast::Item::Enum(it) => Some(ast::Adt::Enum(it)),
1474                                            ast::Item::Union(it) => Some(ast::Adt::Union(it)),
1475                                            _ => None,
1476                                        },
1477                                    )
1478                                }
1479                            }?;
1480                            let attr_name =
1481                                attr.path().and_then(|it| it.as_single_name_ref())?.as_name();
1482                            // Not an attribute, nor a derive, so it's either an inert attribute or a derive helper
1483                            // Try to resolve to a derive helper and downmap
1484                            let resolver = &token
1485                                .parent()
1486                                .and_then(|parent| {
1487                                    self.analyze_impl(InFile::new(expansion, &parent), None, false)
1488                                })?
1489                                .resolver;
1490                            let id = expansion.ast_id_map(db).ast_id(&adt);
1491                            let helpers = resolver
1492                                .def_map()
1493                                .derive_helpers_in_scope(InFile::new(expansion, id))?;
1494
1495                            if !helpers.is_empty() {
1496                                let text_range = attr.syntax().text_range();
1497                                filter_duplicates(tokens, text_range);
1498                            }
1499
1500                            let mut res = None;
1501                            self.with_ctx(|ctx| {
1502                                for (.., derive) in
1503                                    helpers.iter().filter(|(helper, ..)| *helper == attr_name)
1504                                {
1505                                    let Either::Left(derive) = *derive else { continue };
1506                                    // as there may be multiple derives registering the same helper
1507                                    // name, we gotta make sure to call this for all of them!
1508                                    // FIXME: We need to call `f` for all of them as well though!
1509                                    res = res
1510                                        .or(process_expansion_for_token(ctx, &mut stack, derive));
1511                                }
1512                                res
1513                            })
1514                        }
1515                    }
1516                })()
1517                .is_none();
1518                if was_not_remapped
1519                    && let ControlFlow::Break(b) = f(InFile::new(expansion, token), ctx)
1520                {
1521                    return Some(b);
1522                }
1523            }
1524        }
1525        None
1526    }
1527
1528    // Note this return type is deliberate as [`find_nodes_at_offset_with_descend`] wants to stop
1529    // traversing the inner iterator when it finds a node.
1530    // The outer iterator is over the tokens descendants
1531    // The inner iterator is the ancestors of a descendant
1532    fn descend_node_at_offset(
1533        &self,
1534        node: &SyntaxNode,
1535        offset: TextSize,
1536    ) -> impl Iterator<Item = impl Iterator<Item = SyntaxNode> + '_> + '_ {
1537        node.token_at_offset(offset)
1538            .map(move |token| self.descend_into_macros_exact(token))
1539            .map(|descendants| {
1540                descendants.into_iter().map(move |it| self.token_ancestors_with_macros(it))
1541            })
1542            // re-order the tokens from token_at_offset by returning the ancestors with the smaller first nodes first
1543            // See algo::ancestors_at_offset, which uses the same approach
1544            .kmerge_by(|left, right| {
1545                left.clone()
1546                    .map(|node| node.text_range().len())
1547                    .lt(right.clone().map(|node| node.text_range().len()))
1548            })
1549    }
1550
1551    /// Attempts to map the node out of macro expanded files returning the original file range.
1552    /// If upmapping is not possible, this will fall back to the range of the macro call of the
1553    /// macro file the node resides in.
1554    pub fn original_range(&self, node: &SyntaxNode) -> FileRange {
1555        let node = self.find_file(node);
1556        node.original_file_range_rooted(self.db)
1557    }
1558
1559    /// Attempts to map the node out of macro expanded files returning the original file range.
1560    pub fn original_range_opt(&self, node: &SyntaxNode) -> Option<FileRange> {
1561        let node = self.find_file(node);
1562        node.original_file_range_opt(self.db).filter(|(_, ctx)| ctx.is_root()).map(TupleExt::head)
1563    }
1564
1565    /// Attempts to map the node out of macro expanded files.
1566    /// This only works for attribute expansions, as other ones do not have nodes as input.
1567    pub fn original_ast_node<N: AstNode>(&self, node: N) -> Option<N> {
1568        self.wrap_node_infile(node).original_ast_node_rooted(self.db).map(
1569            |InRealFile { file_id, value }| {
1570                self.cache(value.syntax().tree_top(), file_id.into());
1571                value
1572            },
1573        )
1574    }
1575
1576    /// Attempts to map the node out of macro expanded files.
1577    /// This only works for attribute expansions, as other ones do not have nodes as input.
1578    pub fn original_syntax_node_rooted(&self, node: &SyntaxNode) -> Option<SyntaxNode> {
1579        let InFile { file_id, .. } = self.find_file(node);
1580        InFile::new(file_id, node).original_syntax_node_rooted(self.db).map(
1581            |InRealFile { file_id, value }| {
1582                self.cache(value.tree_top(), file_id.into());
1583                value
1584            },
1585        )
1586    }
1587
1588    pub fn diagnostics_display_range(
1589        &self,
1590        src: InFile<SyntaxNodePtr>,
1591    ) -> FileRangeWrapper<FileId> {
1592        let root = self.parse_or_expand(src.file_id);
1593        let node = src.map(|it| it.to_node(&root));
1594        let FileRange { file_id, range } = node.as_ref().original_file_range_rooted(self.db);
1595        FileRangeWrapper { file_id: file_id.file_id(self.db), range }
1596    }
1597
1598    pub fn diagnostics_display_range_for_range(
1599        &self,
1600        src: InFile<TextRange>,
1601    ) -> FileRangeWrapper<FileId> {
1602        let FileRange { file_id, range } = src.original_node_file_range_rooted(self.db);
1603        FileRangeWrapper { file_id: file_id.file_id(self.db), range }
1604    }
1605
1606    fn token_ancestors_with_macros(
1607        &self,
1608        token: SyntaxToken,
1609    ) -> impl Iterator<Item = SyntaxNode> + Clone + '_ {
1610        token.parent().into_iter().flat_map(move |parent| self.ancestors_with_macros(parent))
1611    }
1612
1613    /// Iterates the ancestors of the given node, climbing up macro expansions while doing so.
1614    // FIXME: Replace with `ancestors_with_macros_file` when all usages are updated.
1615    pub fn ancestors_with_macros(
1616        &self,
1617        node: SyntaxNode,
1618    ) -> impl Iterator<Item = SyntaxNode> + Clone + '_ {
1619        let node = self.find_file(&node);
1620        self.ancestors_with_macros_file(node.cloned()).map(|it| it.value)
1621    }
1622
1623    /// Iterates the ancestors of the given node, climbing up macro expansions while doing so.
1624    pub fn ancestors_with_macros_file(
1625        &self,
1626        node: InFile<SyntaxNode>,
1627    ) -> impl Iterator<Item = InFile<SyntaxNode>> + Clone + '_ {
1628        iter::successors(Some(node), move |&InFile { file_id, ref value }| match value.parent() {
1629            Some(parent) => Some(InFile::new(file_id, parent)),
1630            None => {
1631                let macro_file = file_id.macro_file()?;
1632
1633                self.with_ctx(|ctx| {
1634                    let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file);
1635                    expansion_info.arg().map(|node| node?.parent()).transpose()
1636                })
1637            }
1638        })
1639    }
1640
1641    pub fn ancestors_at_offset_with_macros(
1642        &self,
1643        node: &SyntaxNode,
1644        offset: TextSize,
1645    ) -> impl Iterator<Item = SyntaxNode> + '_ {
1646        node.token_at_offset(offset)
1647            .map(|token| self.token_ancestors_with_macros(token))
1648            .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len())
1649    }
1650
1651    /// Returns the `return` expressions in this function's body,
1652    /// excluding those inside closures or async blocks.
1653    pub fn fn_return_points(&self, func: Function) -> Vec<InFile<ast::ReturnExpr>> {
1654        let func_id = match func.id {
1655            AnyFunctionId::FunctionId(id) => id,
1656            _ => return vec![],
1657        };
1658        let (body, source_map) = Body::with_source_map(self.db, func_id.into());
1659
1660        fn collect_returns(
1661            sema: &SemanticsImpl<'_>,
1662            body: &Body,
1663            source_map: &hir_def::expr_store::ExpressionStoreSourceMap,
1664            expr_id: ExprId,
1665            acc: &mut Vec<InFile<ast::ReturnExpr>>,
1666        ) {
1667            match &body[expr_id] {
1668                Expr::Closure { .. } | Expr::Const(_) => return,
1669                Expr::Return { .. } => {
1670                    if let Ok(source) = source_map.expr_syntax(expr_id)
1671                        && let Some(ret_expr) = source.value.cast::<ast::ReturnExpr>()
1672                    {
1673                        let root = sema.parse_or_expand(source.file_id);
1674                        acc.push(InFile::new(source.file_id, ret_expr.to_node(&root)));
1675                    }
1676                }
1677                _ => {}
1678            }
1679            body.walk_child_exprs(expr_id, |child| {
1680                collect_returns(sema, body, source_map, child, acc);
1681            });
1682        }
1683
1684        let mut returns = vec![];
1685        collect_returns(self, body, source_map, body.root_expr(), &mut returns);
1686        returns
1687    }
1688
1689    pub fn resolve_lifetime_param(&self, lifetime: &ast::Lifetime) -> Option<LifetimeParam> {
1690        let text = lifetime.text();
1691        let lifetime_param = lifetime.syntax().ancestors().find_map(|syn| {
1692            let gpl = ast::AnyHasGenericParams::cast(syn)?.generic_param_list()?;
1693            gpl.lifetime_params()
1694                .find(|tp| tp.lifetime().as_ref().map(|lt| lt.text()).as_ref() == Some(&text))
1695        })?;
1696        let src = self.wrap_node_infile(lifetime_param);
1697        ToDef::to_def(self, src.as_ref())
1698    }
1699
1700    pub fn resolve_label(&self, label: &ast::Lifetime) -> Option<Label> {
1701        let src = self.wrap_node_infile(label.clone());
1702        let (parent, label_id) = self.with_ctx(|ctx| ctx.label_ref_to_def(src.as_ref()))?;
1703        Some(Label { parent, label_id })
1704    }
1705
1706    pub fn resolve_type(&self, ty: &ast::Type) -> Option<Type<'db>> {
1707        let analyze = self.analyze(ty.syntax())?;
1708        analyze.type_of_type(self.db, ty)
1709    }
1710
1711    pub fn resolve_trait(&self, path: &ast::Path) -> Option<Trait> {
1712        let parent_ty = path.syntax().parent().and_then(ast::Type::cast)?;
1713        let analyze = self.analyze(path.syntax())?;
1714        let ty = analyze.store_sm()?.node_type(InFile::new(analyze.file_id, &parent_ty))?;
1715        let path = match &analyze.store()?.types[ty] {
1716            hir_def::type_ref::TypeRef::Path(path) => path,
1717            _ => return None,
1718        };
1719        match analyze.resolver.resolve_path_in_type_ns_fully(self.db, path)? {
1720            TypeNs::TraitId(trait_id) => Some(trait_id.into()),
1721            _ => None,
1722        }
1723    }
1724
1725    pub fn expr_adjustments(&self, expr: &ast::Expr) -> Option<Vec<Adjustment<'db>>> {
1726        let mutability = |m| match m {
1727            hir_ty::next_solver::Mutability::Not => Mutability::Shared,
1728            hir_ty::next_solver::Mutability::Mut => Mutability::Mut,
1729        };
1730
1731        let analyzer = self.analyze(expr.syntax())?;
1732
1733        let (mut source_ty, _) = analyzer.type_of_expr(self.db, expr)?;
1734
1735        analyzer.expr_adjustments(expr).map(|it| {
1736            it.iter()
1737                .map(|adjust| {
1738                    let target = analyzer.ty(adjust.target.as_ref());
1739                    let kind = match adjust.kind {
1740                        hir_ty::Adjust::NeverToAny => Adjust::NeverToAny,
1741                        hir_ty::Adjust::Deref(Some(hir_ty::OverloadedDeref(m))) => {
1742                            // FIXME: Should we handle unknown mutability better?
1743                            Adjust::Deref(Some(OverloadedDeref(mutability(m))))
1744                        }
1745                        hir_ty::Adjust::Deref(None) => Adjust::Deref(None),
1746                        hir_ty::Adjust::Borrow(hir_ty::AutoBorrow::RawPtr(m)) => {
1747                            Adjust::Borrow(AutoBorrow::RawPtr(mutability(m)))
1748                        }
1749                        hir_ty::Adjust::Borrow(hir_ty::AutoBorrow::Ref(m)) => {
1750                            // FIXME: Handle lifetimes here
1751                            Adjust::Borrow(AutoBorrow::Ref(mutability(m.into())))
1752                        }
1753                        hir_ty::Adjust::Pointer(pc) => Adjust::Pointer(pc),
1754                    };
1755
1756                    // Update `source_ty` for the next adjustment
1757                    let source = mem::replace(&mut source_ty, target.clone());
1758
1759                    Adjustment { source, target, kind }
1760                })
1761                .collect()
1762        })
1763    }
1764
1765    pub fn expr_is_diverging(&self, expr: &ast::Expr) -> bool {
1766        (|| self.analyze(expr.syntax())?.expr_is_diverging(self.db, expr))().unwrap_or(false)
1767    }
1768
1769    pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<TypeInfo<'db>> {
1770        self.analyze(expr.syntax())?
1771            .type_of_expr(self.db, expr)
1772            .map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced })
1773    }
1774
1775    pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<TypeInfo<'db>> {
1776        self.analyze(pat.syntax())?
1777            .type_of_pat(self.db, pat)
1778            .map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced })
1779    }
1780
1781    /// It also includes the changes that binding mode makes in the type. For example in
1782    /// `let ref x @ Some(_) = None` the result of `type_of_pat` is `Option<T>` but the result
1783    /// of this function is `&mut Option<T>`
1784    pub fn type_of_binding_in_pat(&self, pat: &ast::IdentPat) -> Option<Type<'db>> {
1785        self.analyze(pat.syntax())?.type_of_binding_in_pat(self.db, pat)
1786    }
1787
1788    pub fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type<'db>> {
1789        self.analyze(param.syntax())?.type_of_self(self.db, param)
1790    }
1791
1792    pub fn pattern_adjustments(&self, pat: &ast::Pat) -> SmallVec<[Type<'db>; 1]> {
1793        self.analyze(pat.syntax())
1794            .and_then(|it| it.pattern_adjustments(self.db, pat))
1795            .unwrap_or_default()
1796    }
1797
1798    pub fn binding_mode_of_pat(&self, pat: &ast::IdentPat) -> Option<BindingMode> {
1799        self.analyze(pat.syntax())?.binding_mode_of_pat(self.db, pat)
1800    }
1801
1802    pub fn resolve_expr_as_callable(&self, call: &ast::Expr) -> Option<Callable<'db>> {
1803        self.analyze(call.syntax())?.resolve_expr_as_callable(self.db, call)
1804    }
1805
1806    pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> {
1807        self.analyze(call.syntax())?.resolve_method_call(self.db, call)
1808    }
1809
1810    /// Attempts to resolve this call expression as a method call falling back to resolving it as a field.
1811    pub fn resolve_method_call_fallback(
1812        &self,
1813        call: &ast::MethodCallExpr,
1814    ) -> Option<(Either<Function, Field>, Option<GenericSubstitution<'db>>)> {
1815        self.analyze(call.syntax())?.resolve_method_call_fallback(self.db, call)
1816    }
1817
1818    /// Env is used to derive the trait environment
1819    // FIXME: better api for the trait environment
1820    pub fn resolve_trait_impl_method(
1821        &self,
1822        env: Type<'db>,
1823        trait_: Trait,
1824        func: Function,
1825        subst: impl IntoIterator<Item = Type<'db>>,
1826    ) -> Option<Function> {
1827        let AnyFunctionId::FunctionId(func) = func.id else { return Some(func) };
1828        let interner = DbInterner::new_no_crate(self.db);
1829        let mut subst = subst.into_iter();
1830        let substs = hir_ty::next_solver::GenericArgs::for_item(
1831            interner,
1832            trait_.id.into(),
1833            |_, id, _, _| {
1834                assert!(matches!(id, hir_def::GenericParamId::TypeParamId(_)), "expected a type");
1835                subst.next().expect("too few subst").ty.skip_binder().into()
1836            },
1837        );
1838        assert!(subst.next().is_none(), "too many subst");
1839        Some(match self.db.lookup_impl_method(env.param_env(self.db), func, substs).0 {
1840            Either::Left(it) => it.into(),
1841            Either::Right((impl_, method)) => {
1842                Function { id: AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } }
1843            }
1844        })
1845    }
1846
1847    fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<StructId> {
1848        self.analyze(range_pat.syntax())?.resolve_range_pat(self.db, range_pat)
1849    }
1850
1851    fn resolve_range_expr(&self, range_expr: &ast::RangeExpr) -> Option<StructId> {
1852        self.analyze(range_expr.syntax())?.resolve_range_expr(self.db, range_expr)
1853    }
1854
1855    fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<Function> {
1856        self.analyze(await_expr.syntax())?.resolve_await_to_poll(self.db, await_expr)
1857    }
1858
1859    fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option<Function> {
1860        self.analyze(prefix_expr.syntax())?.resolve_prefix_expr(self.db, prefix_expr)
1861    }
1862
1863    fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option<Function> {
1864        self.analyze(index_expr.syntax())?.resolve_index_expr(self.db, index_expr)
1865    }
1866
1867    fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option<Function> {
1868        self.analyze(bin_expr.syntax())?.resolve_bin_expr(self.db, bin_expr)
1869    }
1870
1871    fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option<Function> {
1872        self.analyze(try_expr.syntax())?.resolve_try_expr(self.db, try_expr)
1873    }
1874
1875    /// The type that the associated `try` block, closure or function expects.
1876    pub fn try_expr_returned_type(&self, try_expr: &ast::TryExpr) -> Option<Type<'db>> {
1877        self.ancestors_with_macros(try_expr.syntax().clone()).find_map(|parent| {
1878            if let Some(try_block) = ast::BlockExpr::cast(parent.clone())
1879                && try_block.try_block_modifier().is_some()
1880            {
1881                Some(self.type_of_expr(&try_block.into())?.original)
1882            } else if let Some(closure) = ast::ClosureExpr::cast(parent.clone()) {
1883                Some(
1884                    self.type_of_expr(&closure.into())?
1885                        .original
1886                        .as_callable(self.db)?
1887                        .return_type(),
1888                )
1889            } else if let Some(function) = ast::Fn::cast(parent) {
1890                Some(self.to_def(&function)?.ret_type(self.db))
1891            } else {
1892                None
1893            }
1894        })
1895    }
1896
1897    // This does not resolve the method call to the correct trait impl!
1898    // We should probably fix that.
1899    pub fn resolve_method_call_as_callable(
1900        &self,
1901        call: &ast::MethodCallExpr,
1902    ) -> Option<Callable<'db>> {
1903        self.analyze(call.syntax())?.resolve_method_call_as_callable(self.db, call)
1904    }
1905
1906    pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Either<Field, TupleField<'db>>> {
1907        self.analyze(field.syntax())?.resolve_field(field)
1908    }
1909
1910    pub fn resolve_field_fallback(
1911        &self,
1912        field: &ast::FieldExpr,
1913    ) -> Option<(Either<Either<Field, TupleField<'db>>, Function>, Option<GenericSubstitution<'db>>)>
1914    {
1915        self.analyze(field.syntax())?.resolve_field_fallback(self.db, field)
1916    }
1917
1918    pub fn resolve_record_field(
1919        &self,
1920        field: &ast::RecordExprField,
1921    ) -> Option<(Field, Option<Local<'db>>, Type<'db>)> {
1922        self.resolve_record_field_with_substitution(field)
1923            .map(|(field, local, ty, _)| (field, local, ty))
1924    }
1925
1926    pub fn resolve_record_field_with_substitution(
1927        &self,
1928        field: &ast::RecordExprField,
1929    ) -> Option<(Field, Option<Local<'db>>, Type<'db>, GenericSubstitution<'db>)> {
1930        self.analyze(field.syntax())?.resolve_record_field(self.db, field)
1931    }
1932
1933    pub fn resolve_record_pat_field(
1934        &self,
1935        field: &ast::RecordPatField,
1936    ) -> Option<(Field, Type<'db>)> {
1937        self.resolve_record_pat_field_with_subst(field).map(|(field, ty, _)| (field, ty))
1938    }
1939
1940    pub fn resolve_record_pat_field_with_subst(
1941        &self,
1942        field: &ast::RecordPatField,
1943    ) -> Option<(Field, Type<'db>, GenericSubstitution<'db>)> {
1944        self.analyze(field.syntax())?.resolve_record_pat_field(self.db, field)
1945    }
1946
1947    // FIXME: Remove this from https://github.com/rust-lang/rust-analyzer/pull/22449#discussion_r3299763452
1948    pub fn resolve_tuple_struct_pat_fields(
1949        &self,
1950        tuple_struct_pat: &ast::TupleStructPat,
1951    ) -> Option<Vec<(Field, Type<'db>)>> {
1952        self.analyze(tuple_struct_pat.syntax())?
1953            .resolve_tuple_struct_pat_fields(self.db, tuple_struct_pat)
1954    }
1955
1956    // FIXME: Replace this with `resolve_macro_call2`
1957    pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<Macro> {
1958        let macro_call = self.find_file(macro_call.syntax()).with_value(macro_call);
1959        self.resolve_macro_call2(macro_call)
1960    }
1961
1962    pub fn resolve_macro_call2(&self, macro_call: InFile<&ast::MacroCall>) -> Option<Macro> {
1963        self.to_def2(macro_call)
1964            .and_then(|call| self.with_ctx(|ctx| macro_call_to_macro_id(ctx, call)))
1965            .map(Into::into)
1966    }
1967
1968    pub fn is_proc_macro_call(&self, macro_call: InFile<&ast::MacroCall>) -> bool {
1969        self.resolve_macro_call2(macro_call)
1970            .is_some_and(|m| matches!(m.id, MacroId::ProcMacroId(..)))
1971    }
1972
1973    pub fn resolve_macro_call_arm(&self, macro_call: &ast::MacroCall) -> Option<u32> {
1974        self.to_def(macro_call)?.expansion_span_map(self.db).matched_arm
1975    }
1976
1977    pub fn get_unsafe_ops(&self, def: ExpressionStoreOwner) -> FxHashSet<ExprOrPatSource> {
1978        let Ok(def) = ExpressionStoreOwnerId::try_from(def) else { return Default::default() };
1979        let (body, source_map) = ExpressionStore::with_source_map(self.db, def);
1980        let mut res = FxHashSet::default();
1981        self.with_all_infers_for_store(def, &mut |infer| {
1982            for root in body.expr_roots() {
1983                unsafe_operations(self.db, infer, def, body, root, &mut |node, _| {
1984                    if let Ok(node) = source_map.expr_or_pat_syntax(node) {
1985                        res.insert(node);
1986                    }
1987                });
1988            }
1989        });
1990        res
1991    }
1992
1993    pub fn get_unsafe_ops_for_unsafe_block(&self, block: ast::BlockExpr) -> Vec<ExprOrPatSource> {
1994        always!(block.unsafe_token().is_some());
1995        let Some(sa) = self.analyze(block.syntax()) else { return vec![] };
1996        let Some((def, store, sm, Some(infer))) = sa.def() else { return vec![] };
1997        let block = self.wrap_node_infile(ast::Expr::from(block));
1998        let Some(ExprOrPatId::ExprId(block)) = sm.node_expr(block.as_ref()) else {
1999            return Vec::new();
2000        };
2001        let mut res = Vec::default();
2002        unsafe_operations(self.db, infer, def, store, block, &mut |node, _| {
2003            if let Ok(node) = sm.expr_or_pat_syntax(node) {
2004                res.push(node);
2005            }
2006        });
2007        res
2008    }
2009
2010    pub fn is_unsafe_macro_call(&self, macro_call: &ast::MacroCall) -> bool {
2011        let Some(mac) = self.resolve_macro_call(macro_call) else { return false };
2012        if mac.is_asm_like(self.db) {
2013            return true;
2014        }
2015
2016        let Some(sa) = self.analyze(macro_call.syntax()) else { return false };
2017        let macro_call = self.find_file(macro_call.syntax()).with_value(macro_call);
2018        match macro_call.map(|it| it.syntax().parent().and_then(ast::MacroExpr::cast)).transpose() {
2019            Some(it) => sa.is_unsafe_macro_call_expr(self.db, it.as_ref()),
2020            None => false,
2021        }
2022    }
2023
2024    pub fn resolve_attr_macro_call(&self, item: &ast::Item) -> Option<Macro> {
2025        let item_in_file = self.wrap_node_infile(item.clone());
2026        let id = self.with_ctx(|ctx| {
2027            let macro_call_id = ctx.item_to_macro_call(item_in_file.as_ref())?;
2028            macro_call_to_macro_id(ctx, macro_call_id)
2029        })?;
2030        Some(Macro { id })
2031    }
2032
2033    pub fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution<'db>> {
2034        self.resolve_path_with_subst(path).map(|(it, _)| it)
2035    }
2036
2037    pub fn resolve_path_per_ns(&self, path: &ast::Path) -> Option<PathResolutionPerNs<'db>> {
2038        self.analyze(path.syntax())?.resolve_hir_path_per_ns(self.db, path)
2039    }
2040
2041    pub fn resolve_path_with_subst(
2042        &self,
2043        path: &ast::Path,
2044    ) -> Option<(PathResolution<'db>, Option<GenericSubstitution<'db>>)> {
2045        self.analyze(path.syntax())?.resolve_path(self.db, path)
2046    }
2047
2048    pub fn resolve_use_type_arg(&self, name: &ast::NameRef) -> Option<TypeParam> {
2049        self.analyze(name.syntax())?.resolve_use_type_arg(name)
2050    }
2051
2052    pub fn resolve_offset_of_field(
2053        &self,
2054        name_ref: &ast::NameRef,
2055    ) -> Option<(Either<EnumVariant, Field>, GenericSubstitution<'db>)> {
2056        self.analyze_no_infer(name_ref.syntax())?.resolve_offset_of_field(self.db, name_ref)
2057    }
2058
2059    pub fn resolve_mod_path(
2060        &self,
2061        scope: &SyntaxNode,
2062        path: &ModPath,
2063    ) -> Option<impl Iterator<Item = ItemInNs>> {
2064        let analyze = self.analyze(scope)?;
2065        let items = analyze.resolver.resolve_module_path_in_items(self.db, path);
2066        Some(items.iter_items().map(|(item, _)| item.into()))
2067    }
2068
2069    fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> {
2070        self.analyze(record_lit.syntax())?.resolve_variant(record_lit)
2071    }
2072
2073    pub fn resolve_bind_pat_to_const(&self, pat: &ast::IdentPat) -> Option<ModuleDef> {
2074        self.analyze(pat.syntax())?.resolve_bind_pat_to_const(self.db, pat)
2075    }
2076
2077    pub fn record_literal_missing_fields(
2078        &self,
2079        literal: &ast::RecordExpr,
2080    ) -> Vec<(Field, Type<'db>)> {
2081        self.analyze(literal.syntax())
2082            .and_then(|it| it.record_literal_missing_fields(self.db, literal))
2083            .unwrap_or_default()
2084    }
2085
2086    pub fn record_literal_matched_fields(
2087        &self,
2088        literal: &ast::RecordExpr,
2089    ) -> Vec<(Field, Type<'db>)> {
2090        self.analyze(literal.syntax())
2091            .and_then(|it| it.record_literal_matched_fields(self.db, literal))
2092            .unwrap_or_default()
2093    }
2094
2095    pub fn record_pattern_missing_fields(
2096        &self,
2097        pattern: &ast::RecordPat,
2098    ) -> Vec<(Field, Type<'db>)> {
2099        self.analyze(pattern.syntax())
2100            .and_then(|it| it.record_pattern_missing_fields(self.db, pattern))
2101            .unwrap_or_default()
2102    }
2103
2104    pub fn record_pattern_matched_fields(
2105        &self,
2106        pattern: &ast::RecordPat,
2107    ) -> Vec<(Field, Type<'db>)> {
2108        self.analyze(pattern.syntax())
2109            .and_then(|it| it.record_pattern_matched_fields(self.db, pattern))
2110            .unwrap_or_default()
2111    }
2112
2113    fn with_ctx<F: FnOnce(&mut SourceToDefCtx<'db, '_>) -> T, T>(&self, f: F) -> T {
2114        let mut ctx = SourceToDefCtx { db: self.db, cache: &mut self.s2d_cache.borrow_mut() };
2115        f(&mut ctx)
2116    }
2117
2118    pub fn to_def<T: ToDef<'db>>(&self, src: &T) -> Option<T::Def> {
2119        let src = self.find_file(src.syntax()).with_value(src);
2120        T::to_def(self, src)
2121    }
2122
2123    pub fn to_def2<T: ToDef<'db>>(&self, src: InFile<&T>) -> Option<T::Def> {
2124        T::to_def(self, src)
2125    }
2126
2127    fn file_to_module_defs(&self, file: FileId) -> impl Iterator<Item = Module> {
2128        self.with_ctx(|ctx| ctx.file_to_def(file).to_owned()).into_iter().map(Module::from)
2129    }
2130
2131    fn hir_file_to_module_defs(&self, file: HirFileId) -> impl Iterator<Item = Module> {
2132        // FIXME: Do we need to care about inline modules for macro expansions?
2133        self.file_to_module_defs(file.original_file_respecting_includes(self.db).file_id(self.db))
2134    }
2135
2136    pub fn scope(&self, node: &SyntaxNode) -> Option<SemanticsScope<'db>> {
2137        self.analyze_no_infer(node).map(
2138            |SourceAnalyzer { file_id, resolver, infer_body, .. }| SemanticsScope {
2139                db: self.db,
2140                file_id,
2141                resolver,
2142                infer_body,
2143            },
2144        )
2145    }
2146
2147    pub fn scope_at_offset(
2148        &self,
2149        node: &SyntaxNode,
2150        offset: TextSize,
2151    ) -> Option<SemanticsScope<'db>> {
2152        self.analyze_with_offset_no_infer(node, offset).map(
2153            |SourceAnalyzer { file_id, resolver, infer_body, .. }| SemanticsScope {
2154                db: self.db,
2155                file_id,
2156                resolver,
2157                infer_body,
2158            },
2159        )
2160    }
2161
2162    /// Search for a definition's source and cache its syntax tree
2163    pub fn source<Def: HasSource>(&self, def: Def) -> Option<InFile<Def::Ast>> {
2164        // FIXME: source call should go through the parse cache
2165        let res = def.source(self.db)?;
2166        self.cache(res.value.syntax().tree_top(), res.file_id);
2167        Some(res)
2168    }
2169
2170    pub fn source_with_range<Def: HasSource>(
2171        &self,
2172        def: Def,
2173    ) -> Option<InFile<(TextRange, Option<Def::Ast>)>> {
2174        let res = def.source_with_range(self.db)?;
2175        self.parse_or_expand(res.file_id);
2176        Some(res)
2177    }
2178
2179    pub fn store_owner_for(&self, node: InFile<&SyntaxNode>) -> Option<ExpressionStoreOwner> {
2180        let container = self.with_ctx(|ctx| ctx.find_container(node))?;
2181        container.as_expression_store_owner().map(|id| id.into())
2182    }
2183
2184    fn populate_anon_const_cache_for<'a>(
2185        &self,
2186        cache: &'a mut DefAnonConstsMap<'db>,
2187        def: DefWithoutBodyWithAnonConsts,
2188    ) -> &'a ExprToAnonConst<'db> {
2189        cache.entry(def).or_insert_with(|| match def {
2190            Either::Left(def) => AnonConstId::all_from_signature(self.db, def)
2191                .map(|anon_const| (anon_const.loc(self.db).expr, anon_const))
2192                .collect(),
2193            Either::Right(def) => {
2194                let all_anon_consts =
2195                    self.db.field_types_with_diagnostics(def).defined_anon_consts().iter().copied();
2196                all_anon_consts
2197                    .map(|anon_const| (anon_const.loc(self.db).expr, anon_const))
2198                    .collect()
2199            }
2200        })
2201    }
2202
2203    fn find_anon_const_for_root_expr_in_signature(
2204        &self,
2205        def: DefWithoutBodyWithAnonConsts,
2206        root_expr: ExprId,
2207    ) -> Option<AnonConstId<'db>> {
2208        let mut cache = self.signature_anon_consts_cache.borrow_mut();
2209        let anon_consts_map = self.populate_anon_const_cache_for(&mut cache, def);
2210        anon_consts_map.get(&root_expr).copied()
2211    }
2212
2213    pub(crate) fn infer_body_for_expr_or_pat(
2214        &self,
2215        def: ExpressionStoreOwnerId,
2216        store: &ExpressionStore,
2217        node: ExprOrPatId,
2218    ) -> Option<InferBodyId<'db>> {
2219        let handle_def_without_body = |def| {
2220            let root_expr = match node {
2221                ExprOrPatId::ExprId(expr) => store.find_root_for_expr(expr),
2222                ExprOrPatId::PatId(pat) => store.find_root_for_pat(pat),
2223            };
2224            let anon_const = self.find_anon_const_for_root_expr_in_signature(def, root_expr)?;
2225            Some(anon_const.into())
2226        };
2227        match def {
2228            ExpressionStoreOwnerId::Signature(def) => handle_def_without_body(Either::Left(def)),
2229            ExpressionStoreOwnerId::Body(def) => Some(def.into()),
2230            ExpressionStoreOwnerId::VariantFields(def) => {
2231                handle_def_without_body(Either::Right(def))
2232            }
2233        }
2234    }
2235
2236    fn with_all_infers_for_store(
2237        &self,
2238        owner: ExpressionStoreOwnerId,
2239        callback: &mut dyn FnMut(&'db InferenceResult<'db>),
2240    ) {
2241        let mut handle_def_without_body = |def| {
2242            let mut cache = self.signature_anon_consts_cache.borrow_mut();
2243            let map = self.populate_anon_const_cache_for(&mut cache, def);
2244            for &anon_const in map.values() {
2245                callback(InferenceResult::of(self.db, anon_const));
2246            }
2247        };
2248        match owner {
2249            ExpressionStoreOwnerId::Signature(def) => handle_def_without_body(Either::Left(def)),
2250            ExpressionStoreOwnerId::Body(def) => {
2251                callback(InferenceResult::of(self.db, def));
2252            }
2253            ExpressionStoreOwnerId::VariantFields(def) => {
2254                handle_def_without_body(Either::Right(def))
2255            }
2256        }
2257    }
2258
2259    /// Returns none if the file of the node is not part of a crate.
2260    fn analyze(&self, node: &SyntaxNode) -> Option<SourceAnalyzer<'db>> {
2261        let node = self.find_file(node);
2262        self.analyze_impl(node, None, true)
2263    }
2264
2265    /// Returns none if the file of the node is not part of a crate.
2266    fn analyze_no_infer(&self, node: &SyntaxNode) -> Option<SourceAnalyzer<'db>> {
2267        let node = self.find_file(node);
2268        self.analyze_impl(node, None, false)
2269    }
2270
2271    fn analyze_with_offset_no_infer(
2272        &self,
2273        node: &SyntaxNode,
2274        offset: TextSize,
2275    ) -> Option<SourceAnalyzer<'db>> {
2276        let node = self.find_file(node);
2277        self.analyze_impl(node, Some(offset), false)
2278    }
2279
2280    fn analyze_impl(
2281        &self,
2282        node: InFile<&SyntaxNode>,
2283        offset: Option<TextSize>,
2284        // replace this, just make the inference result a `LazyCell`
2285        infer: bool,
2286    ) -> Option<SourceAnalyzer<'db>> {
2287        let _p = tracing::info_span!("SemanticsImpl::analyze_impl").entered();
2288
2289        let container = self.with_ctx(|ctx| ctx.find_container(node))?;
2290
2291        let resolver = match container {
2292            ChildContainer::DefWithBodyId(def) => {
2293                return Some(if infer {
2294                    SourceAnalyzer::new_for_body(self.db, def, node, offset)
2295                } else {
2296                    SourceAnalyzer::new_for_body_no_infer(self.db, def, node, offset)
2297                });
2298            }
2299            ChildContainer::VariantId(def) => {
2300                return Some(SourceAnalyzer::new_variant_body(
2301                    self.db, self, def, node, offset, infer,
2302                ));
2303            }
2304            ChildContainer::TraitId(it) => {
2305                return Some(if infer {
2306                    SourceAnalyzer::new_generic_def(self.db, self, it.into(), node, offset)
2307                } else {
2308                    SourceAnalyzer::new_generic_def_no_infer(self.db, self, it.into(), node, offset)
2309                });
2310            }
2311            ChildContainer::ImplId(it) => {
2312                return Some(if infer {
2313                    SourceAnalyzer::new_generic_def(self.db, self, it.into(), node, offset)
2314                } else {
2315                    SourceAnalyzer::new_generic_def_no_infer(self.db, self, it.into(), node, offset)
2316                });
2317            }
2318            ChildContainer::EnumId(it) => {
2319                return Some(if infer {
2320                    SourceAnalyzer::new_generic_def(self.db, self, it.into(), node, offset)
2321                } else {
2322                    SourceAnalyzer::new_generic_def_no_infer(self.db, self, it.into(), node, offset)
2323                });
2324            }
2325            ChildContainer::GenericDefId(it) => {
2326                return Some(if infer {
2327                    SourceAnalyzer::new_generic_def(self.db, self, it, node, offset)
2328                } else {
2329                    SourceAnalyzer::new_generic_def_no_infer(self.db, self, it, node, offset)
2330                });
2331            }
2332            ChildContainer::ModuleId(it) => it.resolver(self.db),
2333        };
2334        Some(SourceAnalyzer::new_for_resolver(resolver, node))
2335    }
2336
2337    fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) {
2338        SourceToDefCache::cache(
2339            &mut self.s2d_cache.borrow_mut().root_to_file_cache,
2340            root_node,
2341            file_id,
2342        );
2343    }
2344
2345    pub fn assert_contains_node(&self, node: &SyntaxNode) {
2346        self.find_file(node);
2347    }
2348
2349    fn lookup(&self, root_node: &SyntaxNode) -> Option<HirFileId> {
2350        let cache = self.s2d_cache.borrow();
2351        cache.root_to_file_cache.get(root_node).copied()
2352    }
2353
2354    fn wrap_node_infile<N: AstNode>(&self, node: N) -> InFile<N> {
2355        let InFile { file_id, .. } = self.find_file(node.syntax());
2356        InFile::new(file_id, node)
2357    }
2358
2359    fn wrap_token_infile(&self, token: SyntaxToken) -> InFile<SyntaxToken> {
2360        let InFile { file_id, .. } = self.find_file(&token.parent().unwrap());
2361        InFile::new(file_id, token)
2362    }
2363
2364    /// Wraps the node in a [`InFile`] with the file id it belongs to.
2365    fn find_file<'node>(&self, node: &'node SyntaxNode) -> InFile<&'node SyntaxNode> {
2366        let root_node = node.tree_top();
2367        let file_id = self.lookup(&root_node).unwrap_or_else(|| {
2368            panic!(
2369                "\n\nFailed to lookup {:?} in this Semantics.\n\
2370                 Make sure to only query nodes derived from this instance of Semantics.\n\
2371                 root node:   {:?}\n\
2372                 known nodes: {}\n\n",
2373                node,
2374                root_node,
2375                self.s2d_cache
2376                    .borrow()
2377                    .root_to_file_cache
2378                    .keys()
2379                    .map(|it| format!("{it:?}"))
2380                    .collect::<Vec<_>>()
2381                    .join(", ")
2382            )
2383        });
2384        InFile::new(file_id, node)
2385    }
2386
2387    /// Returns `true` if the `node` is inside an `unsafe` context.
2388    pub fn is_inside_unsafe(&self, expr: &ast::Expr) -> bool {
2389        let Some(enclosing_item) =
2390            expr.syntax().ancestors().find_map(Either::<ast::Item, ast::Variant>::cast)
2391        else {
2392            return false;
2393        };
2394
2395        let def = match &enclosing_item {
2396            Either::Left(ast::Item::Fn(it)) if it.unsafe_token().is_some() => return true,
2397            Either::Left(ast::Item::Fn(it)) => (|| match self.to_def(it)?.id {
2398                AnyFunctionId::FunctionId(id) => Some(DefWithBodyId::FunctionId(id)),
2399                AnyFunctionId::BuiltinDeriveImplMethod { .. } => None,
2400            })(),
2401            Either::Left(ast::Item::Const(it)) => {
2402                self.to_def(it).map(<_>::into).map(DefWithBodyId::ConstId)
2403            }
2404            Either::Left(ast::Item::Static(it)) => {
2405                self.to_def(it).map(<_>::into).map(DefWithBodyId::StaticId)
2406            }
2407            Either::Left(_) => None,
2408            Either::Right(it) => self.to_def(it).map(<_>::into).map(DefWithBodyId::VariantId),
2409        };
2410        let Some(def) = def else { return false };
2411        let enclosing_node = enclosing_item.as_ref().either(|i| i.syntax(), |v| v.syntax());
2412
2413        let (body, source_map) = Body::with_source_map(self.db, def);
2414
2415        let file_id = self.find_file(expr.syntax()).file_id;
2416
2417        let Some(mut parent) = expr.syntax().parent() else { return false };
2418        loop {
2419            if &parent == enclosing_node {
2420                break false;
2421            }
2422
2423            if let Some(parent) = ast::Expr::cast(parent.clone())
2424                && let Some(ExprOrPatId::ExprId(expr_id)) =
2425                    source_map.node_expr(InFile { file_id, value: &parent })
2426                && let Expr::Block { unsafe_: Unsafe::Yes, .. } = body[expr_id]
2427            {
2428                break true;
2429            }
2430
2431            let Some(parent_) = parent.parent() else { break false };
2432            parent = parent_;
2433        }
2434    }
2435
2436    pub fn impl_generated_from_derive(&self, impl_: Impl) -> Option<Adt> {
2437        let id = match impl_.id {
2438            AnyImplId::ImplId(id) => id,
2439            AnyImplId::BuiltinDeriveImplId(id) => return Some(id.loc(self.db).adt.into()),
2440        };
2441        let source = hir_def::src::HasSource::ast_ptr(id.loc(self.db), self.db);
2442        let mut file_id = source.file_id;
2443        let adt_ast_id = loop {
2444            let macro_call = file_id.macro_file()?;
2445            match macro_call.loc(self.db).kind {
2446                hir_expand::MacroCallKind::Derive { ast_id, .. } => break ast_id,
2447                hir_expand::MacroCallKind::FnLike { ast_id, .. } => file_id = ast_id.file_id,
2448                hir_expand::MacroCallKind::Attr { ast_id, .. } => file_id = ast_id.file_id,
2449            }
2450        };
2451        let adt_source = adt_ast_id.to_in_file_node(self.db);
2452        self.cache(adt_source.value.syntax().tree_top(), adt_source.file_id);
2453        ToDef::to_def(self, adt_source.as_ref())
2454    }
2455
2456    pub fn locals_used(
2457        &self,
2458        element: Either<&ast::Expr, &ast::StmtList>,
2459        text_range: TextRange,
2460    ) -> Option<FxIndexSet<Local<'db>>> {
2461        let sa = self.analyze(element.either(|e| e.syntax(), |s| s.syntax()))?;
2462        let infer_body = sa.infer_body?;
2463        let store = sa.store()?;
2464        let mut resolver = sa.resolver.clone();
2465        let def = resolver.expression_store_owner()?;
2466
2467        let is_not_generated = |path: &Path| {
2468            !path.mod_path().and_then(|path| path.as_ident()).is_some_and(Name::is_generated)
2469        };
2470
2471        let exprs = element.either(
2472            |e| vec![e.clone()],
2473            |stmts| {
2474                let mut exprs: Vec<_> = stmts
2475                    .statements()
2476                    .filter(|stmt| text_range.contains_range(stmt.syntax().text_range()))
2477                    .filter_map(|stmt| match stmt {
2478                        ast::Stmt::ExprStmt(expr_stmt) => expr_stmt.expr().map(|e| vec![e]),
2479                        ast::Stmt::Item(_) => None,
2480                        ast::Stmt::LetStmt(let_stmt) => {
2481                            let init = let_stmt.initializer();
2482                            let let_else = let_stmt
2483                                .let_else()
2484                                .and_then(|le| le.block_expr())
2485                                .map(ast::Expr::BlockExpr);
2486
2487                            match (init, let_else) {
2488                                (Some(i), Some(le)) => Some(vec![i, le]),
2489                                (Some(i), _) => Some(vec![i]),
2490                                (_, Some(le)) => Some(vec![le]),
2491                                _ => None,
2492                            }
2493                        }
2494                    })
2495                    .flatten()
2496                    .collect();
2497
2498                if let Some(tail_expr) = stmts.tail_expr()
2499                    && text_range.contains_range(tail_expr.syntax().text_range())
2500                {
2501                    exprs.push(tail_expr);
2502                }
2503                exprs
2504            },
2505        );
2506        let mut exprs: Vec<_> =
2507            exprs.into_iter().filter_map(|e| sa.expr_id(e).and_then(|e| e.as_expr())).collect();
2508
2509        let mut locals: FxIndexSet<Local<'db>> = FxIndexSet::default();
2510        let mut add_to_locals_used = |id, parent_expr| {
2511            let path = match id {
2512                ExprOrPatId::ExprId(expr_id) => {
2513                    if let Expr::Path(path) = &store[expr_id] {
2514                        Some(path)
2515                    } else {
2516                        None
2517                    }
2518                }
2519                ExprOrPatId::PatId(_) => None,
2520            };
2521
2522            if let Some(path) = path
2523                && is_not_generated(path)
2524            {
2525                let _ = resolver.update_to_inner_scope(self.db, def, parent_expr);
2526                let hygiene = store.expr_or_pat_path_hygiene(id);
2527                resolver.resolve_path_in_value_ns_fully(self.db, path, hygiene).inspect(|value| {
2528                    if let ValueNs::LocalBinding(id) = value {
2529                        locals.insert(Local {
2530                            parent: def,
2531                            parent_infer: infer_body,
2532                            binding_id: *id,
2533                        });
2534                    }
2535                });
2536            }
2537        };
2538
2539        while let Some(expr_id) = exprs.pop() {
2540            if let Expr::Assignment { target, .. } = store[expr_id] {
2541                store.walk_pats(target, &mut |id| {
2542                    add_to_locals_used(ExprOrPatId::PatId(id), expr_id)
2543                });
2544            };
2545            store.walk_child_exprs(expr_id, |id| {
2546                exprs.push(id);
2547            });
2548
2549            add_to_locals_used(ExprOrPatId::ExprId(expr_id), expr_id)
2550        }
2551
2552        Some(locals)
2553    }
2554
2555    pub fn evaluate_where_clause_at(
2556        &self,
2557        node: &SyntaxNode,
2558        offset: TextSize,
2559        where_clause: ast::WhereClause,
2560    ) -> crate::PredicateEvaluationResult {
2561        let Some(analyzer) = self.analyze_with_offset_no_infer(node, offset) else {
2562            return crate::PredicateEvaluationResult::unsupported(
2563                "predicate evaluation is only supported in files that belong to a crate",
2564            );
2565        };
2566        analyzer.evaluate_where_clause(self.db, where_clause)
2567    }
2568
2569    pub fn get_failed_obligations(&self, token: SyntaxToken) -> Option<String> {
2570        let node = token.parent()?;
2571        let node = self.find_file(&node);
2572
2573        let container = self.with_ctx(|ctx| ctx.find_container(node))?;
2574
2575        match container {
2576            ChildContainer::DefWithBodyId(def) => {
2577                thread_local! {
2578                    static RESULT: RefCell<Vec<ProofTreeData>> = const { RefCell::new(Vec::new()) };
2579                }
2580                infer_query_with_inspect(
2581                    self.db,
2582                    def,
2583                    Some(|infer_ctxt, _obligation, result, proof_tree| {
2584                        if result.is_err()
2585                            && let Some(tree) = proof_tree
2586                        {
2587                            let data =
2588                                dump_proof_tree_structured(tree, hir_ty::Span::Dummy, infer_ctxt);
2589                            RESULT.with(|ctx| ctx.borrow_mut().push(data));
2590                        }
2591                    }),
2592                    LoweringMode::Ide,
2593                );
2594                let data: Vec<ProofTreeData> =
2595                    RESULT.with(|data| data.borrow_mut().drain(..).collect());
2596                let data = serde_json::to_string_pretty(&data).unwrap_or_else(|_| "[]".to_owned());
2597                Some(data)
2598            }
2599            _ => None,
2600        }
2601    }
2602}
2603
2604// FIXME This can't be the best way to do this
2605fn macro_call_to_macro_id(
2606    ctx: &mut SourceToDefCtx<'_, '_>,
2607    macro_call_id: MacroCallId,
2608) -> Option<MacroId> {
2609    let db = ctx.db;
2610    let loc = macro_call_id.loc(db);
2611
2612    match loc.def.ast_id() {
2613        Either::Left(it) => {
2614            let node = match it.file_id {
2615                HirFileId::FileId(file_id) => {
2616                    it.to_ptr(db).to_node(&file_id.parse(db).syntax_node())
2617                }
2618                HirFileId::MacroFile(macro_file) => {
2619                    let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file);
2620                    it.to_ptr(db).to_node(&expansion_info.expanded().value)
2621                }
2622            };
2623            ctx.macro_to_def(InFile::new(it.file_id, &node))
2624        }
2625        Either::Right(it) => {
2626            let node = match it.file_id {
2627                HirFileId::FileId(file_id) => {
2628                    it.to_ptr(db).to_node(&file_id.parse(db).syntax_node())
2629                }
2630                HirFileId::MacroFile(macro_file) => {
2631                    let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file);
2632                    it.to_ptr(db).to_node(&expansion_info.expanded().value)
2633                }
2634            };
2635            ctx.proc_macro_to_def(InFile::new(it.file_id, &node))
2636        }
2637    }
2638}
2639
2640pub trait ToDef<'db>: AstNode + Clone {
2641    type Def;
2642    fn to_def(sema: &SemanticsImpl<'db>, src: InFile<&Self>) -> Option<Self::Def>;
2643}
2644
2645macro_rules! to_def_impls {
2646    ($(($def:ty, $ast:path, $meth:ident)),* ,) => {$(
2647        impl<'db> ToDef<'db> for $ast {
2648            type Def = $def;
2649            fn to_def(sema: &SemanticsImpl<'db>, src: InFile<&Self>) -> Option<Self::Def> {
2650                sema.with_ctx(|ctx| ctx.$meth(src)).map(<$def>::from)
2651            }
2652        }
2653    )*}
2654}
2655
2656to_def_impls![
2657    (crate::Module, ast::Module, module_to_def),
2658    (crate::Module, ast::SourceFile, source_file_to_def),
2659    (crate::Struct, ast::Struct, struct_to_def),
2660    (crate::Enum, ast::Enum, enum_to_def),
2661    (crate::Union, ast::Union, union_to_def),
2662    (crate::Trait, ast::Trait, trait_to_def),
2663    (crate::Impl, ast::Impl, impl_to_def),
2664    (crate::TypeAlias, ast::TypeAlias, type_alias_to_def),
2665    (crate::Const, ast::Const, const_to_def),
2666    (crate::Static, ast::Static, static_to_def),
2667    (crate::Function, ast::Fn, fn_to_def),
2668    (crate::Field, ast::RecordField, record_field_to_def),
2669    (crate::Field, ast::TupleField, tuple_field_to_def),
2670    (crate::EnumVariant, ast::Variant, enum_variant_to_def),
2671    (crate::TypeParam, ast::TypeParam, type_param_to_def),
2672    (crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def),
2673    (crate::ConstParam, ast::ConstParam, const_param_to_def),
2674    (crate::GenericParam, ast::GenericParam, generic_param_to_def),
2675    (crate::Macro, ast::Macro, macro_to_def),
2676    (crate::Local<'db>, ast::SelfParam, self_param_to_def),
2677    (crate::Label, ast::Label, label_to_def),
2678    (crate::Adt, ast::Adt, adt_to_def),
2679    (crate::ExternCrateDecl, ast::ExternCrate, extern_crate_to_def),
2680    (crate::InlineAsmOperand, ast::AsmOperandNamed, asm_operand_to_def),
2681    (crate::ExternBlock, ast::ExternBlock, extern_block_to_def),
2682    (MacroCallId, ast::MacroCall, macro_call_to_macro_call),
2683];
2684
2685impl<'db> ToDef<'db> for ast::IdentPat {
2686    type Def = crate::Local<'db>;
2687
2688    fn to_def(sema: &SemanticsImpl<'db>, src: InFile<&Self>) -> Option<Self::Def> {
2689        sema.with_ctx(|ctx| ctx.bind_pat_to_def(src, sema))
2690    }
2691}
2692
2693/// `SemanticsScope` encapsulates the notion of a scope (the set of visible
2694/// names) at a particular program point.
2695///
2696/// It is a bit tricky, as scopes do not really exist inside the compiler.
2697/// Rather, the compiler directly computes for each reference the definition it
2698/// refers to. It might transiently compute the explicit scope map while doing
2699/// so, but, generally, this is not something left after the analysis.
2700///
2701/// However, we do very much need explicit scopes for IDE purposes --
2702/// completion, at its core, lists the contents of the current scope. The notion
2703/// of scope is also useful to answer questions like "what would be the meaning
2704/// of this piece of code if we inserted it into this position?".
2705///
2706/// So `SemanticsScope` is constructed from a specific program point (a syntax
2707/// node or just a raw offset) and provides access to the set of visible names
2708/// on a somewhat best-effort basis.
2709///
2710/// Note that if you are wondering "what does this specific existing name mean?",
2711/// you'd better use the `resolve_` family of methods.
2712#[derive(Debug)]
2713pub struct SemanticsScope<'db> {
2714    pub db: &'db dyn HirDatabase,
2715    infer_body: Option<InferBodyId<'db>>,
2716    file_id: HirFileId,
2717    resolver: Resolver<'db>,
2718}
2719
2720impl<'db> SemanticsScope<'db> {
2721    pub fn file_id(&self) -> HirFileId {
2722        self.file_id
2723    }
2724
2725    pub fn module(&self) -> Module {
2726        Module { id: self.resolver.module() }
2727    }
2728
2729    pub fn krate(&self) -> Crate {
2730        Crate { id: self.resolver.krate() }
2731    }
2732
2733    // FIXME: This is a weird function, we shouldn't have this?
2734    pub fn containing_function(&self) -> Option<Function> {
2735        self.resolver.expression_store_owner().and_then(|owner| match owner {
2736            ExpressionStoreOwnerId::Body(DefWithBodyId::FunctionId(id)) => Some(id.into()),
2737            _ => None,
2738        })
2739    }
2740
2741    pub fn expression_store_owner(&self) -> Option<ExpressionStoreOwner> {
2742        self.resolver.expression_store_owner().map(Into::into)
2743    }
2744
2745    pub(crate) fn resolver(&self) -> &Resolver<'db> {
2746        &self.resolver
2747    }
2748
2749    /// Note: `VisibleTraits` should be treated as an opaque type, passed into `Type
2750    pub fn visible_traits(&self) -> VisibleTraits {
2751        let resolver = &self.resolver;
2752        VisibleTraits(resolver.traits_in_scope(self.db))
2753    }
2754
2755    /// Calls the passed closure `f` on all names in scope.
2756    pub fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef<'db>)) {
2757        let scope = self.resolver.names_in_scope(self.db);
2758        for (name, entries) in scope {
2759            for entry in entries {
2760                let def = match entry {
2761                    resolver::ScopeDef::ModuleDef(it) => ScopeDef::ModuleDef(it.into()),
2762                    resolver::ScopeDef::Unknown => ScopeDef::Unknown,
2763                    resolver::ScopeDef::ImplSelfType(it) => ScopeDef::ImplSelfType(it.into()),
2764                    resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()),
2765                    resolver::ScopeDef::GenericParam(id) => ScopeDef::GenericParam(id.into()),
2766                    resolver::ScopeDef::Local(binding_id) => {
2767                        match (self.resolver.expression_store_owner(), self.infer_body) {
2768                            (Some(parent), Some(parent_infer)) => {
2769                                ScopeDef::Local(Local { parent, parent_infer, binding_id })
2770                            }
2771                            _ => continue,
2772                        }
2773                    }
2774                    resolver::ScopeDef::Label(label_id) => {
2775                        match self.resolver.expression_store_owner() {
2776                            Some(parent) => ScopeDef::Label(Label { parent, label_id }),
2777                            None => continue,
2778                        }
2779                    }
2780                };
2781                f(name.clone(), def)
2782            }
2783        }
2784    }
2785
2786    /// Checks if a trait is in scope, either because of an import or because we're in an impl of it.
2787    pub fn can_use_trait_methods(&self, t: Trait) -> bool {
2788        self.resolver.traits_in_scope(self.db).contains(&t.id)
2789    }
2790
2791    /// Resolve a path as-if it was written at the given scope. This is
2792    /// necessary a heuristic, as it doesn't take hygiene into account.
2793    pub fn speculative_resolve(&self, ast_path: &ast::Path) -> Option<PathResolution<'db>> {
2794        let mut kind = PathKind::Plain;
2795        let mut segments = vec![];
2796        let mut first = true;
2797        for segment in ast_path.segments() {
2798            if first {
2799                first = false;
2800                if segment.coloncolon_token().is_some() {
2801                    kind = PathKind::Abs;
2802                }
2803            }
2804
2805            let Some(k) = segment.kind() else { continue };
2806            match k {
2807                ast::PathSegmentKind::Name(name_ref) => segments.push(name_ref.as_name()),
2808                ast::PathSegmentKind::Type { .. } => continue,
2809                ast::PathSegmentKind::SelfTypeKw => {
2810                    segments.push(Name::new_symbol_root(sym::Self_))
2811                }
2812                ast::PathSegmentKind::SelfKw => kind = PathKind::Super(0),
2813                ast::PathSegmentKind::SuperKw => match kind {
2814                    PathKind::Super(s) => kind = PathKind::Super(s + 1),
2815                    PathKind::Plain => kind = PathKind::Super(1),
2816                    PathKind::Crate | PathKind::Abs | PathKind::DollarCrate(_) => continue,
2817                },
2818                ast::PathSegmentKind::CrateKw => kind = PathKind::Crate,
2819            }
2820        }
2821
2822        resolve_hir_path(
2823            self.db,
2824            &self.resolver,
2825            self.infer_body,
2826            &Path::BarePath(Interned::new(ModPath::from_segments(kind, segments))),
2827            HygieneId::ROOT,
2828            None,
2829        )
2830    }
2831
2832    pub fn resolve_mod_path(&self, path: &ModPath) -> impl Iterator<Item = ItemInNs> + use<> {
2833        let items = self.resolver.resolve_module_path_in_items(self.db, path);
2834        items.iter_items().map(|(item, _)| item.into())
2835    }
2836
2837    /// Iterates over associated types that may be specified after the given path (using
2838    /// `Ty::Assoc` syntax).
2839    pub fn assoc_type_shorthand_candidates(
2840        &self,
2841        resolution: &PathResolution<'db>,
2842        mut cb: impl FnMut(TypeAlias),
2843    ) {
2844        let (Some(def), Some(resolution)) = (self.resolver.generic_def(), resolution.in_type_ns())
2845        else {
2846            return;
2847        };
2848        hir_ty::associated_type_shorthand_candidates(self.db, def, resolution, |_, id| {
2849            cb(id.into());
2850            false
2851        });
2852    }
2853
2854    pub fn generic_def(&self) -> Option<crate::GenericDef> {
2855        self.resolver.generic_def().map(|id| id.into())
2856    }
2857
2858    pub fn extern_crates(&self) -> impl Iterator<Item = (Name, Module)> + '_ {
2859        self.resolver.extern_crates_in_scope().map(|(name, id)| (name, Module { id }))
2860    }
2861
2862    pub fn extern_crate_decls(&self) -> impl Iterator<Item = Name> + '_ {
2863        self.resolver.extern_crate_decls_in_scope(self.db)
2864    }
2865
2866    pub fn has_same_self_type(&self, other: &SemanticsScope<'_>) -> bool {
2867        self.resolver.impl_def() == other.resolver.impl_def()
2868    }
2869}
2870
2871#[derive(Debug)]
2872pub struct VisibleTraits(pub FxHashSet<TraitId>);
2873
2874impl ops::Deref for VisibleTraits {
2875    type Target = FxHashSet<TraitId>;
2876
2877    fn deref(&self) -> &Self::Target {
2878        &self.0
2879    }
2880}
2881
2882struct RenameConflictsVisitor<'a> {
2883    db: &'a dyn HirDatabase,
2884    owner: ExpressionStoreOwnerId,
2885    resolver: Resolver<'a>,
2886    body: &'a ExpressionStore,
2887    to_be_renamed: BindingId,
2888    new_name: Symbol,
2889    old_name: Symbol,
2890    conflicts: FxHashSet<BindingId>,
2891}
2892
2893impl RenameConflictsVisitor<'_> {
2894    fn resolve_path(&mut self, node: ExprOrPatId, path: &Path) {
2895        if let Path::BarePath(path) = path
2896            && let Some(name) = path.as_ident()
2897        {
2898            if *name.symbol() == self.new_name {
2899                if let Some(conflicting) = self.resolver.rename_will_conflict_with_renamed(
2900                    self.db,
2901                    name,
2902                    path,
2903                    self.body.expr_or_pat_path_hygiene(node),
2904                    self.to_be_renamed,
2905                ) {
2906                    self.conflicts.insert(conflicting);
2907                }
2908            } else if *name.symbol() == self.old_name
2909                && let Some(conflicting) = self.resolver.rename_will_conflict_with_another_variable(
2910                    self.db,
2911                    name,
2912                    path,
2913                    self.body.expr_or_pat_path_hygiene(node),
2914                    &self.new_name,
2915                    self.to_be_renamed,
2916                )
2917            {
2918                self.conflicts.insert(conflicting);
2919            }
2920        }
2921    }
2922
2923    fn rename_conflicts(&mut self, expr: ExprId) {
2924        match &self.body[expr] {
2925            Expr::Path(path) => {
2926                let guard = self.resolver.update_to_inner_scope(self.db, self.owner, expr);
2927                self.resolve_path(expr.into(), path);
2928                self.resolver.reset_to_guard(guard);
2929            }
2930            _ => {}
2931        }
2932
2933        self.body.walk_child_exprs(expr, |expr| self.rename_conflicts(expr));
2934    }
2935}