]> git.proxmox.com Git - rustc.git/blame - src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
New upstream version 1.70.0+dfsg1
[rustc.git] / src / tools / rust-analyzer / crates / hir / src / source_analyzer.rs
CommitLineData
064997fb
FG
1//! Lookup hir elements using positions in the source code. This is a lossy
2//! transformation: in general, a single source might correspond to several
3//! modules, functions, etc, due to macros, cfgs and `#[path=]` attributes on
4//! modules.
5//!
6//! So, this modules should not be used during hir construction, it exists
7//! purely for "IDE needs".
8use std::{
9 iter::{self, once},
10 sync::Arc,
11};
12
353b0b11 13use either::Either;
064997fb
FG
14use hir_def::{
15 body::{
16 self,
17 scope::{ExprScopes, ScopeId},
18 Body, BodySourceMap,
19 },
20 expr::{ExprId, Pat, PatId},
9ffffee4 21 lang_item::LangItem,
064997fb
FG
22 macro_id_to_def_id,
23 path::{ModPath, Path, PathKind},
24 resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
25 type_ref::Mutability,
9c376795
FG
26 AsMacroCall, AssocItemId, ConstId, DefWithBodyId, FieldId, FunctionId, ItemContainerId,
27 LocalFieldId, Lookup, ModuleDefId, TraitId, VariantId,
064997fb
FG
28};
29use hir_expand::{
f2b60f7d
FG
30 builtin_fn_macro::BuiltinFnLikeExpander,
31 hygiene::Hygiene,
32 mod_path::path,
33 name,
34 name::{AsName, Name},
35 HirFileId, InFile,
064997fb
FG
36};
37use hir_ty::{
38 diagnostics::{
39 record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions,
40 UnsafeExpr,
41 },
9ffffee4 42 method_resolution::{self, lang_items_for_bin_op},
487cf647 43 Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, TyLoweringContext,
064997fb
FG
44};
45use itertools::Itertools;
46use smallvec::SmallVec;
47use syntax::{
48 ast::{self, AstNode},
49 SyntaxKind, SyntaxNode, TextRange, TextSize,
50};
51
52use crate::{
53 db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BindingMode, BuiltinAttr,
54 BuiltinType, Callable, Const, DeriveHelper, Field, Function, Local, Macro, ModuleDef, Static,
353b0b11 55 Struct, ToolModule, Trait, TraitAlias, Type, TypeAlias, Variant,
064997fb
FG
56};
57
58/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
59/// original source files. It should not be used inside the HIR itself.
60#[derive(Debug)]
61pub(crate) struct SourceAnalyzer {
62 pub(crate) file_id: HirFileId,
63 pub(crate) resolver: Resolver,
64 def: Option<(DefWithBodyId, Arc<Body>, Arc<BodySourceMap>)>,
65 infer: Option<Arc<InferenceResult>>,
66}
67
68impl SourceAnalyzer {
69 pub(crate) fn new_for_body(
70 db: &dyn HirDatabase,
71 def: DefWithBodyId,
72 node @ InFile { file_id, .. }: InFile<&SyntaxNode>,
73 offset: Option<TextSize>,
74 ) -> SourceAnalyzer {
75 let (body, source_map) = db.body_with_source_map(def);
76 let scopes = db.expr_scopes(def);
77 let scope = match offset {
78 None => scope_for(&scopes, &source_map, node),
79 Some(offset) => scope_for_offset(db, &scopes, &source_map, node.file_id, offset),
80 };
81 let resolver = resolver_for_scope(db.upcast(), def, scope);
82 SourceAnalyzer {
83 resolver,
84 def: Some((def, body, source_map)),
85 infer: Some(db.infer(def)),
86 file_id,
87 }
88 }
89
90 pub(crate) fn new_for_body_no_infer(
91 db: &dyn HirDatabase,
92 def: DefWithBodyId,
93 node @ InFile { file_id, .. }: InFile<&SyntaxNode>,
94 offset: Option<TextSize>,
95 ) -> SourceAnalyzer {
96 let (body, source_map) = db.body_with_source_map(def);
97 let scopes = db.expr_scopes(def);
98 let scope = match offset {
99 None => scope_for(&scopes, &source_map, node),
100 Some(offset) => scope_for_offset(db, &scopes, &source_map, node.file_id, offset),
101 };
102 let resolver = resolver_for_scope(db.upcast(), def, scope);
103 SourceAnalyzer { resolver, def: Some((def, body, source_map)), infer: None, file_id }
104 }
105
106 pub(crate) fn new_for_resolver(
107 resolver: Resolver,
108 node: InFile<&SyntaxNode>,
109 ) -> SourceAnalyzer {
110 SourceAnalyzer { resolver, def: None, infer: None, file_id: node.file_id }
111 }
112
113 fn body_source_map(&self) -> Option<&BodySourceMap> {
114 self.def.as_ref().map(|(.., source_map)| &**source_map)
115 }
116 fn body(&self) -> Option<&Body> {
117 self.def.as_ref().map(|(_, body, _)| &**body)
118 }
119
120 fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<ExprId> {
121 let src = match expr {
122 ast::Expr::MacroExpr(expr) => {
9c376795 123 self.expand_expr(db, InFile::new(self.file_id, expr.macro_call()?))?
064997fb
FG
124 }
125 _ => InFile::new(self.file_id, expr.clone()),
126 };
127 let sm = self.body_source_map()?;
128 sm.node_expr(src.as_ref())
129 }
130
131 fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> {
132 // FIXME: macros, see `expr_id`
133 let src = InFile { file_id: self.file_id, value: pat };
134 self.body_source_map()?.node_pat(src)
135 }
136
137 fn expand_expr(
138 &self,
139 db: &dyn HirDatabase,
140 expr: InFile<ast::MacroCall>,
141 ) -> Option<InFile<ast::Expr>> {
142 let macro_file = self.body_source_map()?.node_macro_file(expr.as_ref())?;
143 let expanded = db.parse_or_expand(macro_file)?;
f2b60f7d
FG
144 let res = if let Some(stmts) = ast::MacroStmts::cast(expanded.clone()) {
145 match stmts.expr()? {
146 ast::Expr::MacroExpr(mac) => {
147 self.expand_expr(db, InFile::new(macro_file, mac.macro_call()?))?
148 }
149 expr => InFile::new(macro_file, expr),
150 }
151 } else if let Some(call) = ast::MacroCall::cast(expanded.clone()) {
152 self.expand_expr(db, InFile::new(macro_file, call))?
153 } else {
154 InFile::new(macro_file, ast::Expr::cast(expanded)?)
064997fb 155 };
f2b60f7d 156
064997fb
FG
157 Some(res)
158 }
159
487cf647 160 pub(crate) fn expr_adjustments(
064997fb
FG
161 &self,
162 db: &dyn HirDatabase,
163 expr: &ast::Expr,
487cf647 164 ) -> Option<&[Adjustment]> {
064997fb
FG
165 let expr_id = self.expr_id(db, expr)?;
166 let infer = self.infer.as_ref()?;
487cf647 167 infer.expr_adjustments.get(&expr_id).map(|v| &**v)
064997fb
FG
168 }
169
170 pub(crate) fn type_of_expr(
171 &self,
172 db: &dyn HirDatabase,
173 expr: &ast::Expr,
174 ) -> Option<(Type, Option<Type>)> {
175 let expr_id = self.expr_id(db, expr)?;
176 let infer = self.infer.as_ref()?;
177 let coerced = infer
178 .expr_adjustments
179 .get(&expr_id)
180 .and_then(|adjusts| adjusts.last().map(|adjust| adjust.target.clone()));
181 let ty = infer[expr_id].clone();
182 let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
183 Some((mk_ty(ty), coerced.map(mk_ty)))
184 }
185
186 pub(crate) fn type_of_pat(
187 &self,
188 db: &dyn HirDatabase,
189 pat: &ast::Pat,
190 ) -> Option<(Type, Option<Type>)> {
191 let pat_id = self.pat_id(pat)?;
192 let infer = self.infer.as_ref()?;
193 let coerced = infer
194 .pat_adjustments
195 .get(&pat_id)
196 .and_then(|adjusts| adjusts.last().map(|adjust| adjust.clone()));
197 let ty = infer[pat_id].clone();
198 let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
199 Some((mk_ty(ty), coerced.map(mk_ty)))
200 }
201
202 pub(crate) fn type_of_self(
203 &self,
204 db: &dyn HirDatabase,
205 param: &ast::SelfParam,
206 ) -> Option<Type> {
207 let src = InFile { file_id: self.file_id, value: param };
208 let pat_id = self.body_source_map()?.node_self_param(src)?;
209 let ty = self.infer.as_ref()?[pat_id].clone();
210 Some(Type::new_with_resolver(db, &self.resolver, ty))
211 }
212
213 pub(crate) fn binding_mode_of_pat(
214 &self,
215 _db: &dyn HirDatabase,
216 pat: &ast::IdentPat,
217 ) -> Option<BindingMode> {
218 let pat_id = self.pat_id(&pat.clone().into())?;
219 let infer = self.infer.as_ref()?;
220 infer.pat_binding_modes.get(&pat_id).map(|bm| match bm {
221 hir_ty::BindingMode::Move => BindingMode::Move,
222 hir_ty::BindingMode::Ref(hir_ty::Mutability::Mut) => BindingMode::Ref(Mutability::Mut),
223 hir_ty::BindingMode::Ref(hir_ty::Mutability::Not) => {
224 BindingMode::Ref(Mutability::Shared)
225 }
226 })
227 }
228 pub(crate) fn pattern_adjustments(
229 &self,
230 db: &dyn HirDatabase,
231 pat: &ast::Pat,
232 ) -> Option<SmallVec<[Type; 1]>> {
9c376795 233 let pat_id = self.pat_id(pat)?;
064997fb
FG
234 let infer = self.infer.as_ref()?;
235 Some(
236 infer
237 .pat_adjustments
238 .get(&pat_id)?
239 .iter()
240 .map(|ty| Type::new_with_resolver(db, &self.resolver, ty.clone()))
241 .collect(),
242 )
243 }
244
245 pub(crate) fn resolve_method_call_as_callable(
246 &self,
247 db: &dyn HirDatabase,
248 call: &ast::MethodCallExpr,
249 ) -> Option<Callable> {
250 let expr_id = self.expr_id(db, &call.clone().into())?;
251 let (func, substs) = self.infer.as_ref()?.method_resolution(expr_id)?;
252 let ty = db.value_ty(func.into()).substitute(Interner, &substs);
253 let ty = Type::new_with_resolver(db, &self.resolver, ty);
254 let mut res = ty.as_callable(db)?;
255 res.is_bound_method = true;
256 Some(res)
257 }
258
259 pub(crate) fn resolve_method_call(
260 &self,
261 db: &dyn HirDatabase,
262 call: &ast::MethodCallExpr,
263 ) -> Option<FunctionId> {
264 let expr_id = self.expr_id(db, &call.clone().into())?;
265 let (f_in_trait, substs) = self.infer.as_ref()?.method_resolution(expr_id)?;
f2b60f7d 266
487cf647 267 Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs))
f2b60f7d
FG
268 }
269
353b0b11
FG
270 pub(crate) fn resolve_method_call_fallback(
271 &self,
272 db: &dyn HirDatabase,
273 call: &ast::MethodCallExpr,
274 ) -> Option<Either<FunctionId, FieldId>> {
275 let expr_id = self.expr_id(db, &call.clone().into())?;
276 let inference_result = self.infer.as_ref()?;
277 match inference_result.method_resolution(expr_id) {
278 Some((f_in_trait, substs)) => {
279 Some(Either::Left(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs)))
280 }
281 None => inference_result.field_resolution(expr_id).map(Either::Right),
282 }
283 }
284
f2b60f7d
FG
285 pub(crate) fn resolve_await_to_poll(
286 &self,
287 db: &dyn HirDatabase,
288 await_expr: &ast::AwaitExpr,
289 ) -> Option<FunctionId> {
9c376795 290 let mut ty = self.ty_of_expr(db, &await_expr.expr()?)?.clone();
f2b60f7d
FG
291
292 let into_future_trait = self
293 .resolver
294 .resolve_known_trait(db.upcast(), &path![core::future::IntoFuture])
295 .map(Trait::from);
296
297 if let Some(into_future_trait) = into_future_trait {
298 let type_ = Type::new_with_resolver(db, &self.resolver, ty.clone());
299 if type_.impls_trait(db, into_future_trait, &[]) {
300 let items = into_future_trait.items(db);
301 let into_future_type = items.into_iter().find_map(|item| match item {
302 AssocItem::TypeAlias(alias)
303 if alias.name(db) == hir_expand::name![IntoFuture] =>
304 {
305 Some(alias)
306 }
307 _ => None,
308 })?;
309 let future_trait = type_.normalize_trait_assoc_type(db, &[], into_future_type)?;
310 ty = future_trait.ty;
311 }
312 }
313
9ffffee4
FG
314 let future_trait = db.lang_item(self.resolver.krate(), LangItem::Future)?.as_trait()?;
315 let poll_fn = db.lang_item(self.resolver.krate(), LangItem::FuturePoll)?.as_function()?;
2b03887a
FG
316 // HACK: subst for `poll()` coincides with that for `Future` because `poll()` itself
317 // doesn't have any generic parameters, so we skip building another subst for `poll()`.
318 let substs = hir_ty::TyBuilder::subst_for_def(db, future_trait, None).push(ty).build();
487cf647 319 Some(self.resolve_impl_method_or_trait_def(db, poll_fn, substs))
f2b60f7d
FG
320 }
321
322 pub(crate) fn resolve_prefix_expr(
323 &self,
324 db: &dyn HirDatabase,
325 prefix_expr: &ast::PrefixExpr,
326 ) -> Option<FunctionId> {
9ffffee4
FG
327 let (lang_item, fn_name) = match prefix_expr.op_kind()? {
328 ast::UnaryOp::Deref => (LangItem::Deref, name![deref]),
329 ast::UnaryOp::Not => (LangItem::Not, name![not]),
330 ast::UnaryOp::Neg => (LangItem::Neg, name![neg]),
f2b60f7d 331 };
9c376795 332 let ty = self.ty_of_expr(db, &prefix_expr.expr()?)?;
f2b60f7d 333
9ffffee4 334 let (op_trait, op_fn) = self.lang_trait_fn(db, lang_item, &fn_name)?;
2b03887a
FG
335 // HACK: subst for all methods coincides with that for their trait because the methods
336 // don't have any generic parameters, so we skip building another subst for the methods.
337 let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
f2b60f7d 338
487cf647 339 Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))
f2b60f7d
FG
340 }
341
342 pub(crate) fn resolve_index_expr(
343 &self,
344 db: &dyn HirDatabase,
345 index_expr: &ast::IndexExpr,
346 ) -> Option<FunctionId> {
9c376795
FG
347 let base_ty = self.ty_of_expr(db, &index_expr.base()?)?;
348 let index_ty = self.ty_of_expr(db, &index_expr.index()?)?;
f2b60f7d 349
9ffffee4 350 let (op_trait, op_fn) = self.lang_trait_fn(db, LangItem::Index, &name![index])?;
2b03887a
FG
351 // HACK: subst for all methods coincides with that for their trait because the methods
352 // don't have any generic parameters, so we skip building another subst for the methods.
353 let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None)
f2b60f7d
FG
354 .push(base_ty.clone())
355 .push(index_ty.clone())
356 .build();
487cf647 357 Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))
f2b60f7d
FG
358 }
359
360 pub(crate) fn resolve_bin_expr(
361 &self,
362 db: &dyn HirDatabase,
363 binop_expr: &ast::BinExpr,
364 ) -> Option<FunctionId> {
365 let op = binop_expr.op_kind()?;
9c376795
FG
366 let lhs = self.ty_of_expr(db, &binop_expr.lhs()?)?;
367 let rhs = self.ty_of_expr(db, &binop_expr.rhs()?)?;
f2b60f7d 368
9ffffee4
FG
369 let (op_trait, op_fn) = lang_items_for_bin_op(op)
370 .and_then(|(name, lang_item)| self.lang_trait_fn(db, lang_item, &name))?;
2b03887a
FG
371 // HACK: subst for `index()` coincides with that for `Index` because `index()` itself
372 // doesn't have any generic parameters, so we skip building another subst for `index()`.
373 let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None)
374 .push(lhs.clone())
375 .push(rhs.clone())
376 .build();
f2b60f7d 377
487cf647 378 Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))
f2b60f7d
FG
379 }
380
381 pub(crate) fn resolve_try_expr(
382 &self,
383 db: &dyn HirDatabase,
384 try_expr: &ast::TryExpr,
385 ) -> Option<FunctionId> {
9c376795 386 let ty = self.ty_of_expr(db, &try_expr.expr()?)?;
f2b60f7d 387
9ffffee4 388 let op_fn = db.lang_item(self.resolver.krate(), LangItem::TryTraitBranch)?.as_function()?;
2b03887a
FG
389 let op_trait = match op_fn.lookup(db.upcast()).container {
390 ItemContainerId::TraitId(id) => id,
391 _ => return None,
392 };
393 // HACK: subst for `branch()` coincides with that for `Try` because `branch()` itself
394 // doesn't have any generic parameters, so we skip building another subst for `branch()`.
395 let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
f2b60f7d 396
487cf647 397 Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))
064997fb
FG
398 }
399
400 pub(crate) fn resolve_field(
401 &self,
402 db: &dyn HirDatabase,
403 field: &ast::FieldExpr,
404 ) -> Option<Field> {
405 let expr_id = self.expr_id(db, &field.clone().into())?;
406 self.infer.as_ref()?.field_resolution(expr_id).map(|it| it.into())
407 }
408
409 pub(crate) fn resolve_record_field(
410 &self,
411 db: &dyn HirDatabase,
412 field: &ast::RecordExprField,
413 ) -> Option<(Field, Option<Local>, Type)> {
414 let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
415 let expr = ast::Expr::from(record_expr);
416 let expr_id = self.body_source_map()?.node_expr(InFile::new(self.file_id, &expr))?;
417
418 let local_name = field.field_name()?.as_name();
419 let local = if field.name_ref().is_some() {
420 None
421 } else {
f2b60f7d 422 // Shorthand syntax, resolve to the local
064997fb
FG
423 let path = ModPath::from_segments(PathKind::Plain, once(local_name.clone()));
424 match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) {
353b0b11
FG
425 Some(ValueNs::LocalBinding(binding_id)) => {
426 Some(Local { binding_id, parent: self.resolver.body_owner()? })
064997fb
FG
427 }
428 _ => None,
429 }
430 };
431 let (_, subst) = self.infer.as_ref()?.type_of_expr.get(expr_id)?.as_adt()?;
432 let variant = self.infer.as_ref()?.variant_resolution_for_expr(expr_id)?;
433 let variant_data = variant.variant_data(db.upcast());
434 let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? };
435 let field_ty =
436 db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, subst);
437 Some((field.into(), local, Type::new_with_resolver(db, &self.resolver, field_ty)))
438 }
439
440 pub(crate) fn resolve_record_pat_field(
441 &self,
442 db: &dyn HirDatabase,
443 field: &ast::RecordPatField,
353b0b11 444 ) -> Option<(Field, Type)> {
064997fb
FG
445 let field_name = field.field_name()?.as_name();
446 let record_pat = ast::RecordPat::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
447 let pat_id = self.pat_id(&record_pat.into())?;
448 let variant = self.infer.as_ref()?.variant_resolution_for_pat(pat_id)?;
449 let variant_data = variant.variant_data(db.upcast());
450 let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? };
353b0b11
FG
451 let (_, subst) = self.infer.as_ref()?.type_of_pat.get(pat_id)?.as_adt()?;
452 let field_ty =
453 db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, subst);
454 Some((field.into(), Type::new_with_resolver(db, &self.resolver, field_ty)))
064997fb
FG
455 }
456
457 pub(crate) fn resolve_macro_call(
458 &self,
459 db: &dyn HirDatabase,
460 macro_call: InFile<&ast::MacroCall>,
461 ) -> Option<Macro> {
462 let ctx = body::LowerCtx::new(db.upcast(), macro_call.file_id);
463 let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &ctx))?;
464 self.resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(|it| it.into())
465 }
466
467 pub(crate) fn resolve_bind_pat_to_const(
468 &self,
469 db: &dyn HirDatabase,
470 pat: &ast::IdentPat,
471 ) -> Option<ModuleDef> {
472 let pat_id = self.pat_id(&pat.clone().into())?;
473 let body = self.body()?;
474 let path = match &body[pat_id] {
475 Pat::Path(path) => path,
476 _ => return None,
477 };
478 let res = resolve_hir_path(db, &self.resolver, path)?;
479 match res {
480 PathResolution::Def(def) => Some(def),
481 _ => None,
482 }
483 }
484
485 pub(crate) fn resolve_path(
486 &self,
487 db: &dyn HirDatabase,
488 path: &ast::Path,
489 ) -> Option<PathResolution> {
490 let parent = path.syntax().parent();
491 let parent = || parent.clone();
492
493 let mut prefer_value_ns = false;
494 let resolved = (|| {
487cf647 495 let infer = self.infer.as_deref()?;
064997fb
FG
496 if let Some(path_expr) = parent().and_then(ast::PathExpr::cast) {
497 let expr_id = self.expr_id(db, &path_expr.into())?;
9c376795 498 if let Some((assoc, subs)) = infer.assoc_resolutions_for_expr(expr_id) {
064997fb
FG
499 let assoc = match assoc {
500 AssocItemId::FunctionId(f_in_trait) => {
501 match infer.type_of_expr.get(expr_id) {
502 None => assoc,
503 Some(func_ty) => {
504 if let TyKind::FnDef(_fn_def, subs) = func_ty.kind(Interner) {
487cf647
FG
505 self.resolve_impl_method_or_trait_def(
506 db,
507 f_in_trait,
508 subs.clone(),
509 )
510 .into()
064997fb
FG
511 } else {
512 assoc
513 }
514 }
515 }
516 }
9c376795
FG
517 AssocItemId::ConstId(const_id) => {
518 self.resolve_impl_const_or_trait_def(db, const_id, subs).into()
519 }
9ffffee4 520 assoc => assoc,
064997fb
FG
521 };
522
523 return Some(PathResolution::Def(AssocItem::from(assoc).into()));
524 }
525 if let Some(VariantId::EnumVariantId(variant)) =
526 infer.variant_resolution_for_expr(expr_id)
527 {
528 return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
529 }
530 prefer_value_ns = true;
531 } else if let Some(path_pat) = parent().and_then(ast::PathPat::cast) {
532 let pat_id = self.pat_id(&path_pat.into())?;
9ffffee4
FG
533 if let Some((assoc, subs)) = infer.assoc_resolutions_for_pat(pat_id) {
534 let assoc = match assoc {
535 AssocItemId::ConstId(const_id) => {
536 self.resolve_impl_const_or_trait_def(db, const_id, subs).into()
537 }
538 assoc => assoc,
539 };
064997fb
FG
540 return Some(PathResolution::Def(AssocItem::from(assoc).into()));
541 }
542 if let Some(VariantId::EnumVariantId(variant)) =
487cf647 543 infer.variant_resolution_for_pat(pat_id)
064997fb
FG
544 {
545 return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
546 }
547 } else if let Some(rec_lit) = parent().and_then(ast::RecordExpr::cast) {
548 let expr_id = self.expr_id(db, &rec_lit.into())?;
549 if let Some(VariantId::EnumVariantId(variant)) =
487cf647 550 infer.variant_resolution_for_expr(expr_id)
064997fb
FG
551 {
552 return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
553 }
554 } else {
555 let record_pat = parent().and_then(ast::RecordPat::cast).map(ast::Pat::from);
556 let tuple_struct_pat =
557 || parent().and_then(ast::TupleStructPat::cast).map(ast::Pat::from);
558 if let Some(pat) = record_pat.or_else(tuple_struct_pat) {
559 let pat_id = self.pat_id(&pat)?;
487cf647 560 let variant_res_for_pat = infer.variant_resolution_for_pat(pat_id);
064997fb
FG
561 if let Some(VariantId::EnumVariantId(variant)) = variant_res_for_pat {
562 return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
563 }
564 }
565 }
566 None
567 })();
568 if let Some(_) = resolved {
569 return resolved;
570 }
571
572 // This must be a normal source file rather than macro file.
573 let hygiene = Hygiene::new(db.upcast(), self.file_id);
574 let ctx = body::LowerCtx::with_hygiene(db.upcast(), &hygiene);
575 let hir_path = Path::from_src(path.clone(), &ctx)?;
576
577 // Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are
578 // trying to resolve foo::bar.
579 if let Some(use_tree) = parent().and_then(ast::UseTree::cast) {
580 if use_tree.coloncolon_token().is_some() {
581 return resolve_hir_path_qualifier(db, &self.resolver, &hir_path);
582 }
583 }
584
585 let meta_path = path
586 .syntax()
587 .ancestors()
588 .take_while(|it| {
589 let kind = it.kind();
590 ast::Path::can_cast(kind) || ast::Meta::can_cast(kind)
591 })
592 .last()
593 .and_then(ast::Meta::cast);
594
595 // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we are
596 // trying to resolve foo::bar.
597 if path.parent_path().is_some() {
598 return match resolve_hir_path_qualifier(db, &self.resolver, &hir_path) {
599 None if meta_path.is_some() => {
600 path.first_segment().and_then(|it| it.name_ref()).and_then(|name_ref| {
601 ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text())
602 .map(PathResolution::ToolModule)
603 })
604 }
605 res => res,
606 };
607 } else if let Some(meta_path) = meta_path {
608 // Case where we are resolving the final path segment of a path in an attribute
609 // in this case we have to check for inert/builtin attributes and tools and prioritize
610 // resolution of attributes over other namespaces
611 if let Some(name_ref) = path.as_single_name_ref() {
612 let builtin =
613 BuiltinAttr::by_name(db, self.resolver.krate().into(), &name_ref.text());
614 if let Some(_) = builtin {
615 return builtin.map(PathResolution::BuiltinAttr);
616 }
617
618 if let Some(attr) = meta_path.parent_attr() {
619 let adt = if let Some(field) =
620 attr.syntax().parent().and_then(ast::RecordField::cast)
621 {
622 field.syntax().ancestors().take(4).find_map(ast::Adt::cast)
623 } else if let Some(field) =
624 attr.syntax().parent().and_then(ast::TupleField::cast)
625 {
626 field.syntax().ancestors().take(4).find_map(ast::Adt::cast)
627 } else if let Some(variant) =
628 attr.syntax().parent().and_then(ast::Variant::cast)
629 {
630 variant.syntax().ancestors().nth(2).and_then(ast::Adt::cast)
631 } else {
632 None
633 };
634 if let Some(adt) = adt {
635 let ast_id = db.ast_id_map(self.file_id).ast_id(&adt);
636 if let Some(helpers) = self
637 .resolver
638 .def_map()
639 .derive_helpers_in_scope(InFile::new(self.file_id, ast_id))
640 {
641 // FIXME: Multiple derives can have the same helper
642 let name_ref = name_ref.as_name();
643 for (macro_id, mut helpers) in
644 helpers.iter().group_by(|(_, macro_id, ..)| macro_id).into_iter()
645 {
646 if let Some(idx) = helpers.position(|(name, ..)| *name == name_ref)
647 {
648 return Some(PathResolution::DeriveHelper(DeriveHelper {
649 derive: *macro_id,
9ffffee4 650 idx: idx as u32,
064997fb
FG
651 }));
652 }
653 }
654 }
655 }
656 }
657 }
658 return match resolve_hir_path_as_macro(db, &self.resolver, &hir_path) {
659 Some(m) => Some(PathResolution::Def(ModuleDef::Macro(m))),
660 // this labels any path that starts with a tool module as the tool itself, this is technically wrong
661 // but there is no benefit in differentiating these two cases for the time being
662 None => path.first_segment().and_then(|it| it.name_ref()).and_then(|name_ref| {
663 ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text())
664 .map(PathResolution::ToolModule)
665 }),
666 };
667 }
668 if parent().map_or(false, |it| ast::Visibility::can_cast(it.kind())) {
669 resolve_hir_path_qualifier(db, &self.resolver, &hir_path)
670 } else {
671 resolve_hir_path_(db, &self.resolver, &hir_path, prefer_value_ns)
672 }
673 }
674
675 pub(crate) fn record_literal_missing_fields(
676 &self,
677 db: &dyn HirDatabase,
678 literal: &ast::RecordExpr,
679 ) -> Option<Vec<(Field, Type)>> {
680 let body = self.body()?;
681 let infer = self.infer.as_ref()?;
682
683 let expr_id = self.expr_id(db, &literal.clone().into())?;
684 let substs = infer.type_of_expr[expr_id].as_adt()?.1;
685
686 let (variant, missing_fields, _exhaustive) =
687 record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?;
688 let res = self.missing_fields(db, substs, variant, missing_fields);
689 Some(res)
690 }
691
692 pub(crate) fn record_pattern_missing_fields(
693 &self,
694 db: &dyn HirDatabase,
695 pattern: &ast::RecordPat,
696 ) -> Option<Vec<(Field, Type)>> {
697 let body = self.body()?;
698 let infer = self.infer.as_ref()?;
699
700 let pat_id = self.pat_id(&pattern.clone().into())?;
701 let substs = infer.type_of_pat[pat_id].as_adt()?.1;
702
703 let (variant, missing_fields, _exhaustive) =
704 record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?;
705 let res = self.missing_fields(db, substs, variant, missing_fields);
706 Some(res)
707 }
708
709 fn missing_fields(
710 &self,
711 db: &dyn HirDatabase,
712 substs: &Substitution,
713 variant: VariantId,
714 missing_fields: Vec<LocalFieldId>,
715 ) -> Vec<(Field, Type)> {
716 let field_types = db.field_types(variant);
717
718 missing_fields
719 .into_iter()
720 .map(|local_id| {
721 let field = FieldId { parent: variant, local_id };
722 let ty = field_types[local_id].clone().substitute(Interner, substs);
723 (field.into(), Type::new_with_resolver_inner(db, &self.resolver, ty))
724 })
725 .collect()
726 }
727
728 pub(crate) fn expand(
729 &self,
730 db: &dyn HirDatabase,
731 macro_call: InFile<&ast::MacroCall>,
732 ) -> Option<HirFileId> {
733 let krate = self.resolver.krate();
734 let macro_call_id = macro_call.as_call_id(db.upcast(), krate, |path| {
735 self.resolver
736 .resolve_path_as_macro(db.upcast(), &path)
737 .map(|it| macro_id_to_def_id(db.upcast(), it))
738 })?;
739 Some(macro_call_id.as_file()).filter(|it| it.expansion_level(db.upcast()) < 64)
740 }
741
742 pub(crate) fn resolve_variant(
743 &self,
744 db: &dyn HirDatabase,
745 record_lit: ast::RecordExpr,
746 ) -> Option<VariantId> {
747 let infer = self.infer.as_ref()?;
748 let expr_id = self.expr_id(db, &record_lit.into())?;
749 infer.variant_resolution_for_expr(expr_id)
750 }
751
752 pub(crate) fn is_unsafe_macro_call(
753 &self,
754 db: &dyn HirDatabase,
755 macro_call: InFile<&ast::MacroCall>,
756 ) -> bool {
757 // check for asm/global_asm
758 if let Some(mac) = self.resolve_macro_call(db, macro_call) {
759 let ex = match mac.id {
760 hir_def::MacroId::Macro2Id(it) => it.lookup(db.upcast()).expander,
761 hir_def::MacroId::MacroRulesId(it) => it.lookup(db.upcast()).expander,
762 _ => hir_def::MacroExpander::Declarative,
763 };
764 match ex {
765 hir_def::MacroExpander::BuiltIn(e)
766 if e == BuiltinFnLikeExpander::Asm || e == BuiltinFnLikeExpander::GlobalAsm =>
767 {
768 return true
769 }
770 _ => (),
771 }
772 }
773 let macro_expr = match macro_call
774 .map(|it| it.syntax().parent().and_then(ast::MacroExpr::cast))
775 .transpose()
776 {
777 Some(it) => it,
778 None => return false,
779 };
780
781 if let (Some((def, body, sm)), Some(infer)) = (&self.def, &self.infer) {
782 if let Some(expanded_expr) = sm.macro_expansion_expr(macro_expr.as_ref()) {
783 let mut is_unsafe = false;
784 unsafe_expressions(
785 db,
786 infer,
787 *def,
788 body,
789 expanded_expr,
790 &mut |UnsafeExpr { inside_unsafe_block, .. }| is_unsafe |= !inside_unsafe_block,
791 );
792 return is_unsafe;
793 }
794 }
795 false
796 }
797
487cf647 798 fn resolve_impl_method_or_trait_def(
064997fb
FG
799 &self,
800 db: &dyn HirDatabase,
801 func: FunctionId,
487cf647
FG
802 substs: Substitution,
803 ) -> FunctionId {
064997fb 804 let krate = self.resolver.krate();
487cf647
FG
805 let owner = match self.resolver.body_owner() {
806 Some(it) => it,
807 None => return func,
808 };
809 let env = owner.as_generic_def_id().map_or_else(
064997fb
FG
810 || Arc::new(hir_ty::TraitEnvironment::empty(krate)),
811 |d| db.trait_environment(d),
812 );
353b0b11 813 method_resolution::lookup_impl_method(db, env, func, substs).0
f2b60f7d
FG
814 }
815
9c376795
FG
816 fn resolve_impl_const_or_trait_def(
817 &self,
818 db: &dyn HirDatabase,
819 const_id: ConstId,
820 subs: Substitution,
821 ) -> ConstId {
822 let krate = self.resolver.krate();
823 let owner = match self.resolver.body_owner() {
824 Some(it) => it,
825 None => return const_id,
826 };
827 let env = owner.as_generic_def_id().map_or_else(
828 || Arc::new(hir_ty::TraitEnvironment::empty(krate)),
829 |d| db.trait_environment(d),
830 );
353b0b11 831 method_resolution::lookup_impl_const(db, env, const_id, subs).0
9c376795
FG
832 }
833
f2b60f7d
FG
834 fn lang_trait_fn(
835 &self,
836 db: &dyn HirDatabase,
9ffffee4 837 lang_trait: LangItem,
f2b60f7d 838 method_name: &Name,
2b03887a 839 ) -> Option<(TraitId, FunctionId)> {
9ffffee4 840 let trait_id = db.lang_item(self.resolver.krate(), lang_trait)?.as_trait()?;
2b03887a
FG
841 let fn_id = db.trait_data(trait_id).method_by_name(method_name)?;
842 Some((trait_id, fn_id))
f2b60f7d
FG
843 }
844
845 fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> {
9c376795 846 self.infer.as_ref()?.type_of_expr.get(self.expr_id(db, expr)?)
f2b60f7d 847 }
064997fb
FG
848}
849
850fn scope_for(
851 scopes: &ExprScopes,
852 source_map: &BodySourceMap,
853 node: InFile<&SyntaxNode>,
854) -> Option<ScopeId> {
855 node.value
856 .ancestors()
857 .filter_map(ast::Expr::cast)
858 .filter_map(|it| source_map.node_expr(InFile::new(node.file_id, &it)))
859 .find_map(|it| scopes.scope_for(it))
860}
861
862fn scope_for_offset(
863 db: &dyn HirDatabase,
864 scopes: &ExprScopes,
865 source_map: &BodySourceMap,
866 from_file: HirFileId,
867 offset: TextSize,
868) -> Option<ScopeId> {
869 scopes
870 .scope_by_expr()
871 .iter()
872 .filter_map(|(id, scope)| {
873 let InFile { file_id, value } = source_map.expr_syntax(*id).ok()?;
874 if from_file == file_id {
875 return Some((value.text_range(), scope));
876 }
877
878 // FIXME handle attribute expansion
879 let source = iter::successors(file_id.call_node(db.upcast()), |it| {
880 it.file_id.call_node(db.upcast())
881 })
882 .find(|it| it.file_id == from_file)
883 .filter(|it| it.value.kind() == SyntaxKind::MACRO_CALL)?;
884 Some((source.value.text_range(), scope))
885 })
886 .filter(|(expr_range, _scope)| expr_range.start() <= offset && offset <= expr_range.end())
887 // find containing scope
888 .min_by_key(|(expr_range, _scope)| expr_range.len())
889 .map(|(expr_range, scope)| {
890 adjust(db, scopes, source_map, expr_range, from_file, offset).unwrap_or(*scope)
891 })
892}
893
894// XXX: during completion, cursor might be outside of any particular
895// expression. Try to figure out the correct scope...
896fn adjust(
897 db: &dyn HirDatabase,
898 scopes: &ExprScopes,
899 source_map: &BodySourceMap,
900 expr_range: TextRange,
901 from_file: HirFileId,
902 offset: TextSize,
903) -> Option<ScopeId> {
904 let child_scopes = scopes
905 .scope_by_expr()
906 .iter()
907 .filter_map(|(id, scope)| {
908 let source = source_map.expr_syntax(*id).ok()?;
909 // FIXME: correctly handle macro expansion
910 if source.file_id != from_file {
911 return None;
912 }
913 let root = source.file_syntax(db.upcast());
914 let node = source.value.to_node(&root);
915 Some((node.syntax().text_range(), scope))
916 })
917 .filter(|&(range, _)| {
918 range.start() <= offset && expr_range.contains_range(range) && range != expr_range
919 });
920
921 child_scopes
922 .max_by(|&(r1, _), &(r2, _)| {
923 if r1.contains_range(r2) {
924 std::cmp::Ordering::Greater
925 } else if r2.contains_range(r1) {
926 std::cmp::Ordering::Less
927 } else {
928 r1.start().cmp(&r2.start())
929 }
930 })
931 .map(|(_ptr, scope)| *scope)
932}
933
934#[inline]
935pub(crate) fn resolve_hir_path(
936 db: &dyn HirDatabase,
937 resolver: &Resolver,
938 path: &Path,
939) -> Option<PathResolution> {
940 resolve_hir_path_(db, resolver, path, false)
941}
942
943#[inline]
944pub(crate) fn resolve_hir_path_as_macro(
945 db: &dyn HirDatabase,
946 resolver: &Resolver,
947 path: &Path,
948) -> Option<Macro> {
949 resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(Into::into)
950}
951
952fn resolve_hir_path_(
953 db: &dyn HirDatabase,
954 resolver: &Resolver,
955 path: &Path,
956 prefer_value_ns: bool,
957) -> Option<PathResolution> {
958 let types = || {
959 let (ty, unresolved) = match path.type_anchor() {
960 Some(type_ref) => {
961 let (_, res) = TyLoweringContext::new(db, resolver).lower_ty_ext(type_ref);
962 res.map(|ty_ns| (ty_ns, path.segments().first()))
963 }
964 None => {
353b0b11 965 let (ty, remaining_idx) =
064997fb 966 resolver.resolve_path_in_type_ns(db.upcast(), path.mod_path())?;
353b0b11
FG
967 match remaining_idx {
968 Some(remaining_idx) => {
969 if remaining_idx + 1 == path.segments().len() {
064997fb
FG
970 Some((ty, path.segments().last()))
971 } else {
972 None
973 }
974 }
353b0b11 975 None => Some((ty, None)),
064997fb
FG
976 }
977 }
978 }?;
979
980 // If we are in a TypeNs for a Trait, and we have an unresolved name, try to resolve it as a type
981 // within the trait's associated types.
982 if let (Some(unresolved), &TypeNs::TraitId(trait_id)) = (&unresolved, &ty) {
983 if let Some(type_alias_id) =
984 db.trait_data(trait_id).associated_type_by_name(unresolved.name)
985 {
986 return Some(PathResolution::Def(ModuleDefId::from(type_alias_id).into()));
987 }
988 }
989
990 let res = match ty {
991 TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
992 TypeNs::GenericParam(id) => PathResolution::TypeParam(id.into()),
993 TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => {
994 PathResolution::Def(Adt::from(it).into())
995 }
996 TypeNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()),
997 TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
998 TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()),
999 TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
353b0b11 1000 TypeNs::TraitAliasId(it) => PathResolution::Def(TraitAlias::from(it).into()),
064997fb
FG
1001 };
1002 match unresolved {
1003 Some(unresolved) => resolver
1004 .generic_def()
1005 .and_then(|def| {
1006 hir_ty::associated_type_shorthand_candidates(
1007 db,
1008 def,
1009 res.in_type_ns()?,
9c376795 1010 |name, id| (name == unresolved.name).then_some(id),
064997fb
FG
1011 )
1012 })
1013 .map(TypeAlias::from)
1014 .map(Into::into)
1015 .map(PathResolution::Def),
1016 None => Some(res),
1017 }
1018 };
1019
1020 let body_owner = resolver.body_owner();
1021 let values = || {
1022 resolver.resolve_path_in_value_ns_fully(db.upcast(), path.mod_path()).and_then(|val| {
1023 let res = match val {
353b0b11
FG
1024 ValueNs::LocalBinding(binding_id) => {
1025 let var = Local { parent: body_owner?, binding_id };
064997fb
FG
1026 PathResolution::Local(var)
1027 }
1028 ValueNs::FunctionId(it) => PathResolution::Def(Function::from(it).into()),
1029 ValueNs::ConstId(it) => PathResolution::Def(Const::from(it).into()),
1030 ValueNs::StaticId(it) => PathResolution::Def(Static::from(it).into()),
1031 ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()),
1032 ValueNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()),
1033 ValueNs::ImplSelf(impl_id) => PathResolution::SelfType(impl_id.into()),
1034 ValueNs::GenericParam(id) => PathResolution::ConstParam(id.into()),
1035 };
1036 Some(res)
1037 })
1038 };
1039
1040 let items = || {
1041 resolver
1042 .resolve_module_path_in_items(db.upcast(), path.mod_path())
1043 .take_types()
1044 .map(|it| PathResolution::Def(it.into()))
1045 };
1046
1047 let macros = || {
1048 resolver
1049 .resolve_path_as_macro(db.upcast(), path.mod_path())
1050 .map(|def| PathResolution::Def(ModuleDef::Macro(def.into())))
1051 };
1052
1053 if prefer_value_ns { values().or_else(types) } else { types().or_else(values) }
1054 .or_else(items)
1055 .or_else(macros)
1056}
1057
1058/// Resolves a path where we know it is a qualifier of another path.
1059///
1060/// For example, if we have:
1061/// ```
1062/// mod my {
1063/// pub mod foo {
1064/// struct Bar;
1065/// }
1066///
1067/// pub fn foo() {}
1068/// }
1069/// ```
1070/// then we know that `foo` in `my::foo::Bar` refers to the module, not the function.
1071fn resolve_hir_path_qualifier(
1072 db: &dyn HirDatabase,
1073 resolver: &Resolver,
1074 path: &Path,
1075) -> Option<PathResolution> {
1076 resolver
1077 .resolve_path_in_type_ns_fully(db.upcast(), path.mod_path())
1078 .map(|ty| match ty {
1079 TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
1080 TypeNs::GenericParam(id) => PathResolution::TypeParam(id.into()),
1081 TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => {
1082 PathResolution::Def(Adt::from(it).into())
1083 }
1084 TypeNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()),
1085 TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
1086 TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()),
1087 TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
353b0b11 1088 TypeNs::TraitAliasId(it) => PathResolution::Def(TraitAlias::from(it).into()),
064997fb
FG
1089 })
1090 .or_else(|| {
1091 resolver
1092 .resolve_module_path_in_items(db.upcast(), path.mod_path())
1093 .take_types()
1094 .map(|it| PathResolution::Def(it.into()))
1095 })
1096}