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},
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 work 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 work 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) => {
2191                let all_anon_consts =
2192                    AnonConstId::all_from_signature(self.db, def).into_iter().flatten().copied();
2193                all_anon_consts
2194                    .map(|anon_const| (anon_const.loc(self.db).expr, anon_const))
2195                    .collect()
2196            }
2197            Either::Right(def) => {
2198                let all_anon_consts =
2199                    self.db.field_types_with_diagnostics(def).defined_anon_consts().iter().copied();
2200                all_anon_consts
2201                    .map(|anon_const| (anon_const.loc(self.db).expr, anon_const))
2202                    .collect()
2203            }
2204        })
2205    }
2206
2207    fn find_anon_const_for_root_expr_in_signature(
2208        &self,
2209        def: DefWithoutBodyWithAnonConsts,
2210        root_expr: ExprId,
2211    ) -> Option<AnonConstId<'db>> {
2212        let mut cache = self.signature_anon_consts_cache.borrow_mut();
2213        let anon_consts_map = self.populate_anon_const_cache_for(&mut cache, def);
2214        anon_consts_map.get(&root_expr).copied()
2215    }
2216
2217    pub(crate) fn infer_body_for_expr_or_pat(
2218        &self,
2219        def: ExpressionStoreOwnerId,
2220        store: &ExpressionStore,
2221        node: ExprOrPatId,
2222    ) -> Option<InferBodyId<'db>> {
2223        let handle_def_without_body = |def| {
2224            let root_expr = match node {
2225                ExprOrPatId::ExprId(expr) => store.find_root_for_expr(expr),
2226                ExprOrPatId::PatId(pat) => store.find_root_for_pat(pat),
2227            };
2228            let anon_const = self.find_anon_const_for_root_expr_in_signature(def, root_expr)?;
2229            Some(anon_const.into())
2230        };
2231        match def {
2232            ExpressionStoreOwnerId::Signature(def) => handle_def_without_body(Either::Left(def)),
2233            ExpressionStoreOwnerId::Body(def) => Some(def.into()),
2234            ExpressionStoreOwnerId::VariantFields(def) => {
2235                handle_def_without_body(Either::Right(def))
2236            }
2237        }
2238    }
2239
2240    fn with_all_infers_for_store(
2241        &self,
2242        owner: ExpressionStoreOwnerId,
2243        callback: &mut dyn FnMut(&'db InferenceResult<'db>),
2244    ) {
2245        let mut handle_def_without_body = |def| {
2246            let mut cache = self.signature_anon_consts_cache.borrow_mut();
2247            let map = self.populate_anon_const_cache_for(&mut cache, def);
2248            for &anon_const in map.values() {
2249                callback(InferenceResult::of(self.db, anon_const));
2250            }
2251        };
2252        match owner {
2253            ExpressionStoreOwnerId::Signature(def) => handle_def_without_body(Either::Left(def)),
2254            ExpressionStoreOwnerId::Body(def) => {
2255                callback(InferenceResult::of(self.db, def));
2256            }
2257            ExpressionStoreOwnerId::VariantFields(def) => {
2258                handle_def_without_body(Either::Right(def))
2259            }
2260        }
2261    }
2262
2263    /// Returns none if the file of the node is not part of a crate.
2264    fn analyze(&self, node: &SyntaxNode) -> Option<SourceAnalyzer<'db>> {
2265        let node = self.find_file(node);
2266        self.analyze_impl(node, None, true)
2267    }
2268
2269    /// Returns none if the file of the node is not part of a crate.
2270    fn analyze_no_infer(&self, node: &SyntaxNode) -> Option<SourceAnalyzer<'db>> {
2271        let node = self.find_file(node);
2272        self.analyze_impl(node, None, false)
2273    }
2274
2275    fn analyze_with_offset_no_infer(
2276        &self,
2277        node: &SyntaxNode,
2278        offset: TextSize,
2279    ) -> Option<SourceAnalyzer<'db>> {
2280        let node = self.find_file(node);
2281        self.analyze_impl(node, Some(offset), false)
2282    }
2283
2284    fn analyze_impl(
2285        &self,
2286        node: InFile<&SyntaxNode>,
2287        offset: Option<TextSize>,
2288        // replace this, just make the inference result a `LazyCell`
2289        infer: bool,
2290    ) -> Option<SourceAnalyzer<'db>> {
2291        let _p = tracing::info_span!("SemanticsImpl::analyze_impl").entered();
2292
2293        let container = self.with_ctx(|ctx| ctx.find_container(node))?;
2294
2295        let resolver = match container {
2296            ChildContainer::DefWithBodyId(def) => {
2297                return Some(if infer {
2298                    SourceAnalyzer::new_for_body(self.db, def, node, offset)
2299                } else {
2300                    SourceAnalyzer::new_for_body_no_infer(self.db, def, node, offset)
2301                });
2302            }
2303            ChildContainer::VariantId(def) => {
2304                return Some(SourceAnalyzer::new_variant_body(
2305                    self.db, self, def, node, offset, infer,
2306                ));
2307            }
2308            ChildContainer::TraitId(it) => {
2309                return Some(if infer {
2310                    SourceAnalyzer::new_generic_def(self.db, self, it.into(), node, offset)
2311                } else {
2312                    SourceAnalyzer::new_generic_def_no_infer(self.db, self, it.into(), node, offset)
2313                });
2314            }
2315            ChildContainer::ImplId(it) => {
2316                return Some(if infer {
2317                    SourceAnalyzer::new_generic_def(self.db, self, it.into(), node, offset)
2318                } else {
2319                    SourceAnalyzer::new_generic_def_no_infer(self.db, self, it.into(), node, offset)
2320                });
2321            }
2322            ChildContainer::EnumId(it) => {
2323                return Some(if infer {
2324                    SourceAnalyzer::new_generic_def(self.db, self, it.into(), node, offset)
2325                } else {
2326                    SourceAnalyzer::new_generic_def_no_infer(self.db, self, it.into(), node, offset)
2327                });
2328            }
2329            ChildContainer::GenericDefId(it) => {
2330                return Some(if infer {
2331                    SourceAnalyzer::new_generic_def(self.db, self, it, node, offset)
2332                } else {
2333                    SourceAnalyzer::new_generic_def_no_infer(self.db, self, it, node, offset)
2334                });
2335            }
2336            ChildContainer::ModuleId(it) => it.resolver(self.db),
2337        };
2338        Some(SourceAnalyzer::new_for_resolver(resolver, node))
2339    }
2340
2341    fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) {
2342        SourceToDefCache::cache(
2343            &mut self.s2d_cache.borrow_mut().root_to_file_cache,
2344            root_node,
2345            file_id,
2346        );
2347    }
2348
2349    pub fn assert_contains_node(&self, node: &SyntaxNode) {
2350        self.find_file(node);
2351    }
2352
2353    fn lookup(&self, root_node: &SyntaxNode) -> Option<HirFileId> {
2354        let cache = self.s2d_cache.borrow();
2355        cache.root_to_file_cache.get(root_node).copied()
2356    }
2357
2358    fn wrap_node_infile<N: AstNode>(&self, node: N) -> InFile<N> {
2359        let InFile { file_id, .. } = self.find_file(node.syntax());
2360        InFile::new(file_id, node)
2361    }
2362
2363    fn wrap_token_infile(&self, token: SyntaxToken) -> InFile<SyntaxToken> {
2364        let InFile { file_id, .. } = self.find_file(&token.parent().unwrap());
2365        InFile::new(file_id, token)
2366    }
2367
2368    /// Wraps the node in a [`InFile`] with the file id it belongs to.
2369    fn find_file<'node>(&self, node: &'node SyntaxNode) -> InFile<&'node SyntaxNode> {
2370        let root_node = node.tree_top();
2371        let file_id = self.lookup(&root_node).unwrap_or_else(|| {
2372            panic!(
2373                "\n\nFailed to lookup {:?} in this Semantics.\n\
2374                 Make sure to only query nodes derived from this instance of Semantics.\n\
2375                 root node:   {:?}\n\
2376                 known nodes: {}\n\n",
2377                node,
2378                root_node,
2379                self.s2d_cache
2380                    .borrow()
2381                    .root_to_file_cache
2382                    .keys()
2383                    .map(|it| format!("{it:?}"))
2384                    .collect::<Vec<_>>()
2385                    .join(", ")
2386            )
2387        });
2388        InFile::new(file_id, node)
2389    }
2390
2391    /// Returns `true` if the `node` is inside an `unsafe` context.
2392    pub fn is_inside_unsafe(&self, expr: &ast::Expr) -> bool {
2393        let Some(enclosing_item) =
2394            expr.syntax().ancestors().find_map(Either::<ast::Item, ast::Variant>::cast)
2395        else {
2396            return false;
2397        };
2398
2399        let def = match &enclosing_item {
2400            Either::Left(ast::Item::Fn(it)) if it.unsafe_token().is_some() => return true,
2401            Either::Left(ast::Item::Fn(it)) => (|| match self.to_def(it)?.id {
2402                AnyFunctionId::FunctionId(id) => Some(DefWithBodyId::FunctionId(id)),
2403                AnyFunctionId::BuiltinDeriveImplMethod { .. } => None,
2404            })(),
2405            Either::Left(ast::Item::Const(it)) => {
2406                self.to_def(it).map(<_>::into).map(DefWithBodyId::ConstId)
2407            }
2408            Either::Left(ast::Item::Static(it)) => {
2409                self.to_def(it).map(<_>::into).map(DefWithBodyId::StaticId)
2410            }
2411            Either::Left(_) => None,
2412            Either::Right(it) => self.to_def(it).map(<_>::into).map(DefWithBodyId::VariantId),
2413        };
2414        let Some(def) = def else { return false };
2415        let enclosing_node = enclosing_item.as_ref().either(|i| i.syntax(), |v| v.syntax());
2416
2417        let (body, source_map) = Body::with_source_map(self.db, def);
2418
2419        let file_id = self.find_file(expr.syntax()).file_id;
2420
2421        let Some(mut parent) = expr.syntax().parent() else { return false };
2422        loop {
2423            if &parent == enclosing_node {
2424                break false;
2425            }
2426
2427            if let Some(parent) = ast::Expr::cast(parent.clone())
2428                && let Some(ExprOrPatId::ExprId(expr_id)) =
2429                    source_map.node_expr(InFile { file_id, value: &parent })
2430                && let Expr::Unsafe { .. } = body[expr_id]
2431            {
2432                break true;
2433            }
2434
2435            let Some(parent_) = parent.parent() else { break false };
2436            parent = parent_;
2437        }
2438    }
2439
2440    pub fn impl_generated_from_derive(&self, impl_: Impl) -> Option<Adt> {
2441        let id = match impl_.id {
2442            AnyImplId::ImplId(id) => id,
2443            AnyImplId::BuiltinDeriveImplId(id) => return Some(id.loc(self.db).adt.into()),
2444        };
2445        let source = hir_def::src::HasSource::ast_ptr(id.loc(self.db), self.db);
2446        let mut file_id = source.file_id;
2447        let adt_ast_id = loop {
2448            let macro_call = file_id.macro_file()?;
2449            match macro_call.loc(self.db).kind {
2450                hir_expand::MacroCallKind::Derive { ast_id, .. } => break ast_id,
2451                hir_expand::MacroCallKind::FnLike { ast_id, .. } => file_id = ast_id.file_id,
2452                hir_expand::MacroCallKind::Attr { ast_id, .. } => file_id = ast_id.file_id,
2453            }
2454        };
2455        let adt_source = adt_ast_id.to_in_file_node(self.db);
2456        self.cache(adt_source.value.syntax().tree_top(), adt_source.file_id);
2457        ToDef::to_def(self, adt_source.as_ref())
2458    }
2459
2460    pub fn locals_used(
2461        &self,
2462        element: Either<&ast::Expr, &ast::StmtList>,
2463        text_range: TextRange,
2464    ) -> Option<FxIndexSet<Local<'db>>> {
2465        let sa = self.analyze(element.either(|e| e.syntax(), |s| s.syntax()))?;
2466        let infer_body = sa.infer_body?;
2467        let store = sa.store()?;
2468        let mut resolver = sa.resolver.clone();
2469        let def = resolver.expression_store_owner()?;
2470
2471        let is_not_generated = |path: &Path| {
2472            !path.mod_path().and_then(|path| path.as_ident()).is_some_and(Name::is_generated)
2473        };
2474
2475        let exprs = element.either(
2476            |e| vec![e.clone()],
2477            |stmts| {
2478                let mut exprs: Vec<_> = stmts
2479                    .statements()
2480                    .filter(|stmt| text_range.contains_range(stmt.syntax().text_range()))
2481                    .filter_map(|stmt| match stmt {
2482                        ast::Stmt::ExprStmt(expr_stmt) => expr_stmt.expr().map(|e| vec![e]),
2483                        ast::Stmt::Item(_) => None,
2484                        ast::Stmt::LetStmt(let_stmt) => {
2485                            let init = let_stmt.initializer();
2486                            let let_else = let_stmt
2487                                .let_else()
2488                                .and_then(|le| le.block_expr())
2489                                .map(ast::Expr::BlockExpr);
2490
2491                            match (init, let_else) {
2492                                (Some(i), Some(le)) => Some(vec![i, le]),
2493                                (Some(i), _) => Some(vec![i]),
2494                                (_, Some(le)) => Some(vec![le]),
2495                                _ => None,
2496                            }
2497                        }
2498                    })
2499                    .flatten()
2500                    .collect();
2501
2502                if let Some(tail_expr) = stmts.tail_expr()
2503                    && text_range.contains_range(tail_expr.syntax().text_range())
2504                {
2505                    exprs.push(tail_expr);
2506                }
2507                exprs
2508            },
2509        );
2510        let mut exprs: Vec<_> =
2511            exprs.into_iter().filter_map(|e| sa.expr_id(e).and_then(|e| e.as_expr())).collect();
2512
2513        let mut locals: FxIndexSet<Local<'db>> = FxIndexSet::default();
2514        let mut add_to_locals_used = |id, parent_expr| {
2515            let path = match id {
2516                ExprOrPatId::ExprId(expr_id) => {
2517                    if let Expr::Path(path) = &store[expr_id] {
2518                        Some(path)
2519                    } else {
2520                        None
2521                    }
2522                }
2523                ExprOrPatId::PatId(_) => None,
2524            };
2525
2526            if let Some(path) = path
2527                && is_not_generated(path)
2528            {
2529                let _ = resolver.update_to_inner_scope(self.db, def, parent_expr);
2530                let hygiene = store.expr_or_pat_path_hygiene(id);
2531                resolver.resolve_path_in_value_ns_fully(self.db, path, hygiene).inspect(|value| {
2532                    if let ValueNs::LocalBinding(id) = value {
2533                        locals.insert(Local {
2534                            parent: def,
2535                            parent_infer: infer_body,
2536                            binding_id: *id,
2537                        });
2538                    }
2539                });
2540            }
2541        };
2542
2543        while let Some(expr_id) = exprs.pop() {
2544            if let Expr::Assignment { target, .. } = store[expr_id] {
2545                store.walk_pats(target, &mut |id| {
2546                    add_to_locals_used(ExprOrPatId::PatId(id), expr_id)
2547                });
2548            };
2549            store.walk_child_exprs(expr_id, |id| {
2550                exprs.push(id);
2551            });
2552
2553            add_to_locals_used(ExprOrPatId::ExprId(expr_id), expr_id)
2554        }
2555
2556        Some(locals)
2557    }
2558
2559    pub fn evaluate_where_clause_at(
2560        &self,
2561        node: &SyntaxNode,
2562        offset: TextSize,
2563        where_clause: ast::WhereClause,
2564    ) -> crate::PredicateEvaluationResult {
2565        let Some(analyzer) = self.analyze_with_offset_no_infer(node, offset) else {
2566            return crate::PredicateEvaluationResult::unsupported(
2567                "predicate evaluation is only supported in files that belong to a crate",
2568            );
2569        };
2570        analyzer.evaluate_where_clause(self.db, where_clause)
2571    }
2572
2573    pub fn get_failed_obligations(&self, token: SyntaxToken) -> Option<String> {
2574        let node = token.parent()?;
2575        let node = self.find_file(&node);
2576
2577        let container = self.with_ctx(|ctx| ctx.find_container(node))?;
2578
2579        match container {
2580            ChildContainer::DefWithBodyId(def) => {
2581                thread_local! {
2582                    static RESULT: RefCell<Vec<ProofTreeData>> = const { RefCell::new(Vec::new()) };
2583                }
2584                infer_query_with_inspect(
2585                    self.db,
2586                    def,
2587                    Some(|infer_ctxt, _obligation, result, proof_tree| {
2588                        if result.is_err()
2589                            && let Some(tree) = proof_tree
2590                        {
2591                            let data =
2592                                dump_proof_tree_structured(tree, hir_ty::Span::Dummy, infer_ctxt);
2593                            RESULT.with(|ctx| ctx.borrow_mut().push(data));
2594                        }
2595                    }),
2596                    LoweringMode::Ide,
2597                );
2598                let data: Vec<ProofTreeData> =
2599                    RESULT.with(|data| data.borrow_mut().drain(..).collect());
2600                let data = serde_json::to_string_pretty(&data).unwrap_or_else(|_| "[]".to_owned());
2601                Some(data)
2602            }
2603            _ => None,
2604        }
2605    }
2606}
2607
2608// FIXME This can't be the best way to do this
2609fn macro_call_to_macro_id(
2610    ctx: &mut SourceToDefCtx<'_, '_>,
2611    macro_call_id: MacroCallId,
2612) -> Option<MacroId> {
2613    let db = ctx.db;
2614    let loc = macro_call_id.loc(db);
2615
2616    match loc.def.ast_id() {
2617        Either::Left(it) => {
2618            let node = match it.file_id {
2619                HirFileId::FileId(file_id) => {
2620                    it.to_ptr(db).to_node(&file_id.parse(db).syntax_node())
2621                }
2622                HirFileId::MacroFile(macro_file) => {
2623                    let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file);
2624                    it.to_ptr(db).to_node(&expansion_info.expanded().value)
2625                }
2626            };
2627            ctx.macro_to_def(InFile::new(it.file_id, &node))
2628        }
2629        Either::Right(it) => {
2630            let node = match it.file_id {
2631                HirFileId::FileId(file_id) => {
2632                    it.to_ptr(db).to_node(&file_id.parse(db).syntax_node())
2633                }
2634                HirFileId::MacroFile(macro_file) => {
2635                    let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file);
2636                    it.to_ptr(db).to_node(&expansion_info.expanded().value)
2637                }
2638            };
2639            ctx.proc_macro_to_def(InFile::new(it.file_id, &node))
2640        }
2641    }
2642}
2643
2644pub trait ToDef<'db>: AstNode + Clone {
2645    type Def;
2646    fn to_def(sema: &SemanticsImpl<'db>, src: InFile<&Self>) -> Option<Self::Def>;
2647}
2648
2649macro_rules! to_def_impls {
2650    ($(($def:ty, $ast:path, $meth:ident)),* ,) => {$(
2651        impl<'db> ToDef<'db> for $ast {
2652            type Def = $def;
2653            fn to_def(sema: &SemanticsImpl<'db>, src: InFile<&Self>) -> Option<Self::Def> {
2654                sema.with_ctx(|ctx| ctx.$meth(src)).map(<$def>::from)
2655            }
2656        }
2657    )*}
2658}
2659
2660to_def_impls![
2661    (crate::Module, ast::Module, module_to_def),
2662    (crate::Module, ast::SourceFile, source_file_to_def),
2663    (crate::Struct, ast::Struct, struct_to_def),
2664    (crate::Enum, ast::Enum, enum_to_def),
2665    (crate::Union, ast::Union, union_to_def),
2666    (crate::Trait, ast::Trait, trait_to_def),
2667    (crate::Impl, ast::Impl, impl_to_def),
2668    (crate::TypeAlias, ast::TypeAlias, type_alias_to_def),
2669    (crate::Const, ast::Const, const_to_def),
2670    (crate::Static, ast::Static, static_to_def),
2671    (crate::Function, ast::Fn, fn_to_def),
2672    (crate::Field, ast::RecordField, record_field_to_def),
2673    (crate::Field, ast::TupleField, tuple_field_to_def),
2674    (crate::EnumVariant, ast::Variant, enum_variant_to_def),
2675    (crate::TypeParam, ast::TypeParam, type_param_to_def),
2676    (crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def),
2677    (crate::ConstParam, ast::ConstParam, const_param_to_def),
2678    (crate::GenericParam, ast::GenericParam, generic_param_to_def),
2679    (crate::Macro, ast::Macro, macro_to_def),
2680    (crate::Local<'db>, ast::SelfParam, self_param_to_def),
2681    (crate::Label, ast::Label, label_to_def),
2682    (crate::Adt, ast::Adt, adt_to_def),
2683    (crate::ExternCrateDecl, ast::ExternCrate, extern_crate_to_def),
2684    (crate::InlineAsmOperand, ast::AsmOperandNamed, asm_operand_to_def),
2685    (crate::ExternBlock, ast::ExternBlock, extern_block_to_def),
2686    (MacroCallId, ast::MacroCall, macro_call_to_macro_call),
2687];
2688
2689impl<'db> ToDef<'db> for ast::IdentPat {
2690    type Def = crate::Local<'db>;
2691
2692    fn to_def(sema: &SemanticsImpl<'db>, src: InFile<&Self>) -> Option<Self::Def> {
2693        sema.with_ctx(|ctx| ctx.bind_pat_to_def(src, sema))
2694    }
2695}
2696
2697/// `SemanticsScope` encapsulates the notion of a scope (the set of visible
2698/// names) at a particular program point.
2699///
2700/// It is a bit tricky, as scopes do not really exist inside the compiler.
2701/// Rather, the compiler directly computes for each reference the definition it
2702/// refers to. It might transiently compute the explicit scope map while doing
2703/// so, but, generally, this is not something left after the analysis.
2704///
2705/// However, we do very much need explicit scopes for IDE purposes --
2706/// completion, at its core, lists the contents of the current scope. The notion
2707/// of scope is also useful to answer questions like "what would be the meaning
2708/// of this piece of code if we inserted it into this position?".
2709///
2710/// So `SemanticsScope` is constructed from a specific program point (a syntax
2711/// node or just a raw offset) and provides access to the set of visible names
2712/// on a somewhat best-effort basis.
2713///
2714/// Note that if you are wondering "what does this specific existing name mean?",
2715/// you'd better use the `resolve_` family of methods.
2716#[derive(Debug)]
2717pub struct SemanticsScope<'db> {
2718    pub db: &'db dyn HirDatabase,
2719    infer_body: Option<InferBodyId<'db>>,
2720    file_id: HirFileId,
2721    resolver: Resolver<'db>,
2722}
2723
2724impl<'db> SemanticsScope<'db> {
2725    pub fn file_id(&self) -> HirFileId {
2726        self.file_id
2727    }
2728
2729    pub fn module(&self) -> Module {
2730        Module { id: self.resolver.module() }
2731    }
2732
2733    pub fn krate(&self) -> Crate {
2734        Crate { id: self.resolver.krate() }
2735    }
2736
2737    // FIXME: This is a weird function, we shouldn't have this?
2738    pub fn containing_function(&self) -> Option<Function> {
2739        self.resolver.expression_store_owner().and_then(|owner| match owner {
2740            ExpressionStoreOwnerId::Body(DefWithBodyId::FunctionId(id)) => Some(id.into()),
2741            _ => None,
2742        })
2743    }
2744
2745    pub fn expression_store_owner(&self) -> Option<ExpressionStoreOwner> {
2746        self.resolver.expression_store_owner().map(Into::into)
2747    }
2748
2749    pub(crate) fn resolver(&self) -> &Resolver<'db> {
2750        &self.resolver
2751    }
2752
2753    /// Note: `VisibleTraits` should be treated as an opaque type, passed into `Type
2754    pub fn visible_traits(&self) -> VisibleTraits {
2755        let resolver = &self.resolver;
2756        VisibleTraits(resolver.traits_in_scope(self.db))
2757    }
2758
2759    /// Calls the passed closure `f` on all names in scope.
2760    pub fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef<'db>)) {
2761        let scope = self.resolver.names_in_scope(self.db);
2762        for (name, entries) in scope {
2763            for entry in entries {
2764                let def = match entry {
2765                    resolver::ScopeDef::ModuleDef(it) => ScopeDef::ModuleDef(it.into()),
2766                    resolver::ScopeDef::Unknown => ScopeDef::Unknown,
2767                    resolver::ScopeDef::ImplSelfType(it) => ScopeDef::ImplSelfType(it.into()),
2768                    resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()),
2769                    resolver::ScopeDef::GenericParam(id) => ScopeDef::GenericParam(id.into()),
2770                    resolver::ScopeDef::Local(binding_id) => {
2771                        match (self.resolver.expression_store_owner(), self.infer_body) {
2772                            (Some(parent), Some(parent_infer)) => {
2773                                ScopeDef::Local(Local { parent, parent_infer, binding_id })
2774                            }
2775                            _ => continue,
2776                        }
2777                    }
2778                    resolver::ScopeDef::Label(label_id) => {
2779                        match self.resolver.expression_store_owner() {
2780                            Some(parent) => ScopeDef::Label(Label { parent, label_id }),
2781                            None => continue,
2782                        }
2783                    }
2784                };
2785                f(name.clone(), def)
2786            }
2787        }
2788    }
2789
2790    /// Checks if a trait is in scope, either because of an import or because we're in an impl of it.
2791    pub fn can_use_trait_methods(&self, t: Trait) -> bool {
2792        self.resolver.traits_in_scope(self.db).contains(&t.id)
2793    }
2794
2795    /// Resolve a path as-if it was written at the given scope. This is
2796    /// necessary a heuristic, as it doesn't take hygiene into account.
2797    pub fn speculative_resolve(&self, ast_path: &ast::Path) -> Option<PathResolution<'db>> {
2798        let mut kind = PathKind::Plain;
2799        let mut segments = vec![];
2800        let mut first = true;
2801        for segment in ast_path.segments() {
2802            if first {
2803                first = false;
2804                if segment.coloncolon_token().is_some() {
2805                    kind = PathKind::Abs;
2806                }
2807            }
2808
2809            let Some(k) = segment.kind() else { continue };
2810            match k {
2811                ast::PathSegmentKind::Name(name_ref) => segments.push(name_ref.as_name()),
2812                ast::PathSegmentKind::Type { .. } => continue,
2813                ast::PathSegmentKind::SelfTypeKw => {
2814                    segments.push(Name::new_symbol_root(sym::Self_))
2815                }
2816                ast::PathSegmentKind::SelfKw => kind = PathKind::Super(0),
2817                ast::PathSegmentKind::SuperKw => match kind {
2818                    PathKind::Super(s) => kind = PathKind::Super(s + 1),
2819                    PathKind::Plain => kind = PathKind::Super(1),
2820                    PathKind::Crate | PathKind::Abs | PathKind::DollarCrate(_) => continue,
2821                },
2822                ast::PathSegmentKind::CrateKw => kind = PathKind::Crate,
2823            }
2824        }
2825
2826        resolve_hir_path(
2827            self.db,
2828            &self.resolver,
2829            self.infer_body,
2830            &Path::BarePath(Interned::new(ModPath::from_segments(kind, segments))),
2831            HygieneId::ROOT,
2832            None,
2833        )
2834    }
2835
2836    pub fn resolve_mod_path(&self, path: &ModPath) -> impl Iterator<Item = ItemInNs> + use<> {
2837        let items = self.resolver.resolve_module_path_in_items(self.db, path);
2838        items.iter_items().map(|(item, _)| item.into())
2839    }
2840
2841    /// Iterates over associated types that may be specified after the given path (using
2842    /// `Ty::Assoc` syntax).
2843    pub fn assoc_type_shorthand_candidates(
2844        &self,
2845        resolution: &PathResolution<'db>,
2846        mut cb: impl FnMut(TypeAlias),
2847    ) {
2848        let (Some(def), Some(resolution)) = (self.resolver.generic_def(), resolution.in_type_ns())
2849        else {
2850            return;
2851        };
2852        hir_ty::associated_type_shorthand_candidates(self.db, def, resolution, |_, id| {
2853            cb(id.into());
2854            false
2855        });
2856    }
2857
2858    pub fn generic_def(&self) -> Option<crate::GenericDef> {
2859        self.resolver.generic_def().map(|id| id.into())
2860    }
2861
2862    pub fn extern_crates(&self) -> impl Iterator<Item = (Name, Module)> + '_ {
2863        self.resolver.extern_crates_in_scope().map(|(name, id)| (name, Module { id }))
2864    }
2865
2866    pub fn extern_crate_decls(&self) -> impl Iterator<Item = Name> + '_ {
2867        self.resolver.extern_crate_decls_in_scope(self.db)
2868    }
2869
2870    pub fn has_same_self_type(&self, other: &SemanticsScope<'_>) -> bool {
2871        self.resolver.impl_def() == other.resolver.impl_def()
2872    }
2873}
2874
2875#[derive(Debug)]
2876pub struct VisibleTraits(pub FxHashSet<TraitId>);
2877
2878impl ops::Deref for VisibleTraits {
2879    type Target = FxHashSet<TraitId>;
2880
2881    fn deref(&self) -> &Self::Target {
2882        &self.0
2883    }
2884}
2885
2886struct RenameConflictsVisitor<'a> {
2887    db: &'a dyn HirDatabase,
2888    owner: ExpressionStoreOwnerId,
2889    resolver: Resolver<'a>,
2890    body: &'a ExpressionStore,
2891    to_be_renamed: BindingId,
2892    new_name: Symbol,
2893    old_name: Symbol,
2894    conflicts: FxHashSet<BindingId>,
2895}
2896
2897impl RenameConflictsVisitor<'_> {
2898    fn resolve_path(&mut self, node: ExprOrPatId, path: &Path) {
2899        if let Path::BarePath(path) = path
2900            && let Some(name) = path.as_ident()
2901        {
2902            if *name.symbol() == self.new_name {
2903                if let Some(conflicting) = self.resolver.rename_will_conflict_with_renamed(
2904                    self.db,
2905                    name,
2906                    path,
2907                    self.body.expr_or_pat_path_hygiene(node),
2908                    self.to_be_renamed,
2909                ) {
2910                    self.conflicts.insert(conflicting);
2911                }
2912            } else if *name.symbol() == self.old_name
2913                && let Some(conflicting) = self.resolver.rename_will_conflict_with_another_variable(
2914                    self.db,
2915                    name,
2916                    path,
2917                    self.body.expr_or_pat_path_hygiene(node),
2918                    &self.new_name,
2919                    self.to_be_renamed,
2920                )
2921            {
2922                self.conflicts.insert(conflicting);
2923            }
2924        }
2925    }
2926
2927    fn rename_conflicts(&mut self, expr: ExprId) {
2928        match &self.body[expr] {
2929            Expr::Path(path) => {
2930                let guard = self.resolver.update_to_inner_scope(self.db, self.owner, expr);
2931                self.resolve_path(expr.into(), path);
2932                self.resolver.reset_to_guard(guard);
2933            }
2934            _ => {}
2935        }
2936
2937        self.body.walk_child_exprs(expr, |expr| self.rename_conflicts(expr));
2938    }
2939}