diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 86e5a6700b039..7d29a931f9c13 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -46,6 +46,7 @@ use tracing::{debug, instrument}; use super::explain_borrow::{BorrowExplanation, LaterUseKind}; use super::{DescribePlaceOpt, RegionName, RegionNameSource, UseSpans}; use crate::borrow_set::{BorrowData, TwoPhaseActivation}; +use crate::consumers::OutlivesConstraint; use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead; use crate::diagnostics::{CapturedMessageOpt, call_kind, find_all_local_uses}; use crate::{InitializationRequiringAction, MirBorrowckCtxt, WriteKind, borrowck_errors}; @@ -3076,40 +3077,48 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ), ( Some(name), - BorrowExplanation::MustBeValidFor { - category: - category @ (ConstraintCategory::Return(_) - | ConstraintCategory::CallArgument(_) - | ConstraintCategory::OpaqueType), - from_closure: false, - ref region_name, - span, - .. - }, - ) if borrow_spans.for_coroutine() || borrow_spans.for_closure() => self - .report_escaping_closure_capture( + BorrowExplanation::MustBeValidFor { ref best_blame, ref region_name, .. }, + ) if let OutlivesConstraint { + category: + category @ (ConstraintCategory::Return(_) + | ConstraintCategory::CallArgument(_) + | ConstraintCategory::OpaqueType), + from_closure: false, + span, + .. + } = best_blame.constraint() + && (borrow_spans.for_coroutine() || borrow_spans.for_closure()) => + { + self.report_escaping_closure_capture( borrow_spans, borrow_span, region_name, - category, - span, + *category, + *span, &format!("`{name}`"), "function", - ), + ) + } ( name, BorrowExplanation::MustBeValidFor { - category: ConstraintCategory::Assignment, - from_closure: false, + ref best_blame, region_name: RegionName { source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name), .. }, - span, .. }, - ) => self.report_escaping_data(borrow_span, &name, upvar_span, upvar_name, span), + ) if let OutlivesConstraint { + category: ConstraintCategory::Assignment, + from_closure: false, + span, + .. + } = best_blame.constraint() => + { + self.report_escaping_data(borrow_span, &name, upvar_span, upvar_name, *span) + } (Some(name), explanation) => self.report_local_value_does_not_live_long_enough( location, &name, @@ -3143,18 +3152,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { explanation: BorrowExplanation<'tcx>, ) -> Diag<'infcx> { let borrow_span = borrow_spans.var_or_use_path_span(); - if let BorrowExplanation::MustBeValidFor { - category, - span, - ref opt_place_desc, - from_closure: false, - .. - } = explanation + if let BorrowExplanation::MustBeValidFor { best_blame, opt_place_desc, .. } = &explanation + && let OutlivesConstraint { category, span, from_closure: false, .. } = + best_blame.constraint() && let Err(diag) = self.try_report_cannot_return_reference_to_local( borrow, borrow_span, - span, - category, + *span, + *category, opt_place_desc.as_ref(), ) { @@ -3356,14 +3361,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { proper_span: Span, explanation: BorrowExplanation<'tcx>, ) -> Diag<'infcx> { - if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } = - explanation + if let BorrowExplanation::MustBeValidFor { ref best_blame, .. } = explanation + && let OutlivesConstraint { category, span, from_closure: false, .. } = + best_blame.constraint() { if let Err(diag) = self.try_report_cannot_return_reference_to_local( borrow, proper_span, - span, - category, + *span, + *category, None, ) { return diag; diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 15e3cf28aac32..1b633aefc22f8 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -22,7 +22,7 @@ use super::{RegionName, UseSpans, find_use}; use crate::borrow_set::BorrowData; use crate::constraints::OutlivesConstraint; use crate::nll::ConstraintDescription; -use crate::region_infer::{BlameConstraint, Cause}; +use crate::region_infer::{BestBlame, Cause}; use crate::{MirBorrowckCtxt, WriteKind}; #[derive(Debug)] @@ -35,12 +35,9 @@ pub(crate) enum BorrowExplanation<'tcx> { should_note_order: bool, }, MustBeValidFor { - category: ConstraintCategory<'tcx>, - from_closure: bool, - span: Span, + best_blame: BestBlame<'tcx>, region_name: RegionName, opt_place_desc: Option, - path: Vec>, }, Unexplained, } @@ -376,13 +373,13 @@ impl<'tcx> BorrowExplanation<'tcx> { } } BorrowExplanation::MustBeValidFor { - category, - span, + ref best_blame, ref region_name, ref opt_place_desc, - from_closure: _, - ref path, } => { + let OutlivesConstraint { category, span, .. } = *best_blame.constraint(); + let path = best_blame.path(); + region_name.highlight_region_name(err); if let Some(desc) = opt_place_desc { @@ -403,8 +400,8 @@ impl<'tcx> BorrowExplanation<'tcx> { ); }; - cx.add_placeholder_from_predicate_note(err, &path); - cx.add_sized_or_copy_bound_info(err, category, &path); + cx.add_placeholder_from_predicate_note(err, path); + cx.add_sized_or_copy_bound_info(err, category, path); if let ConstraintCategory::Cast { is_raw_ptr_dyn_type_cast: _, @@ -689,22 +686,18 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { // Here, under NLL: no cause was found. Under polonius: no cause was found, or a // boring local was found, which we ignore like NLLs do to match its diagnostics. if let Some(region) = self.regioncx.to_error_region_vid(borrow_region_vid) { - let (blame_constraint, path) = self.regioncx.best_blame_constraint( + let best_blame = self.regioncx.best_blame_constraint( borrow_region_vid, NllRegionVariableOrigin::FreeRegion, region, ); - let BlameConstraint { category, from_closure, span, .. } = blame_constraint; if let Some(region_name) = self.give_region_a_name(region) { let opt_place_desc = self.describe_place(borrow.borrowed_place.as_ref()); BorrowExplanation::MustBeValidFor { - category, - from_closure, - span, + best_blame, region_name, opt_place_desc, - path, } } else { debug!("Could not generate a region name"); diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index a82cd5c74c330..112f3e2406943 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -28,9 +28,9 @@ use rustc_trait_selection::traits::{Obligation, ObligationCtxt}; use tracing::{debug, instrument, trace}; use super::{LIMITATION_NOTE, OutlivesSuggestionBuilder, RegionName, RegionNameSource}; -use crate::consumers::RegionInferenceContext; +use crate::consumers::{OutlivesConstraint, RegionInferenceContext}; use crate::nll::ConstraintDescription; -use crate::region_infer::{BlameConstraint, TypeTest}; +use crate::region_infer::TypeTest; use crate::session_diagnostics::{ FnMutError, FnMutReturnTypeErr, GenericDoesNotLiveLongEnough, LifetimeOutliveErr, LifetimeReturnCategoryErr, RequireStaticErr, VarHereDenote, @@ -414,9 +414,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { }; // Find the code to blame for the fact that `longer_fr` outlives `error_fr`. - let (blame_constraint, path) = - self.regioncx.best_blame_constraint(longer_fr, origin_longer, error_vid); - let cause = blame_constraint.to_obligation_cause_from_path(&path); + let best_blame = self.regioncx.best_blame_constraint(longer_fr, origin_longer, error_vid); + let cause = best_blame.to_obligation_cause(); // FIXME these methods should have better names, and also probably not be this generic. // FIXME note that we *throw away* the error element here! We probably want to @@ -447,9 +446,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ) { debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr); - let (blame_constraint, path) = - self.regioncx.best_blame_constraint(fr, fr_origin, outlived_fr); - let BlameConstraint { category, span, variance_info, .. } = blame_constraint; + let best_blame = self.regioncx.best_blame_constraint(fr, fr_origin, outlived_fr); + let OutlivesConstraint { category, span, variance_info, .. } = *best_blame.constraint(); + let path = best_blame.path(); debug!("report_region_error: category={:?} {:?} {:?}", category, span, variance_info); @@ -563,10 +562,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } } - self.add_placeholder_from_predicate_note(&mut diag, &path); - self.add_sized_or_copy_bound_info(&mut diag, category, &path); + self.add_placeholder_from_predicate_note(&mut diag, path); + self.add_sized_or_copy_bound_info(&mut diag, category, path); - for constraint in &path { + for constraint in path { if let ConstraintCategory::Cast { is_raw_ptr_dyn_type_cast: true, .. } = constraint.category { diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 505aa74b04437..effdc7dc34af1 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1285,9 +1285,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { return RegionRelationCheckResult::Error; } - let blame_constraint = self - .best_blame_constraint(longer_fr, NllRegionVariableOrigin::FreeRegion, shorter_fr) - .0; + let best_blame = self.best_blame_constraint( + longer_fr, + NllRegionVariableOrigin::FreeRegion, + shorter_fr, + ); + let OutlivesConstraint { category, span, .. } = best_blame.constraint(); // Grow `shorter_fr` until we find some non-local regions. // We will always find at least one: `'static`. We'll call @@ -1346,8 +1349,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { propagated_outlives_requirements.push(ClosureOutlivesRequirement { subject: ClosureOutlivesSubject::Region(fr_minus), outlived_free_region: fr_plus, - blame_span: blame_constraint.span, - category: blame_constraint.category, + blame_span: *span, + category: *category, }); } return RegionRelationCheckResult::Propagated; @@ -1614,7 +1617,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { from_region: RegionVid, from_region_origin: NllRegionVariableOrigin<'tcx>, to_region: RegionVid, - ) -> (BlameConstraint<'tcx>, Vec>) { + ) -> BestBlame<'tcx> { assert!(from_region != to_region, "Trying to blame a region for itself!"); let path = self.constraint_path_between_regions(from_region, to_region).unwrap(); @@ -1787,13 +1790,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!(?best_choice, ?blame_source); - let best_constraint = if let Some(next) = path.get(best_choice + 1) + let best_blame_idx = if let Some(next) = path.get(best_choice + 1) && matches!(path[best_choice].category, ConstraintCategory::Return(_)) && next.category == ConstraintCategory::OpaqueType { // The return expression is being influenced by the return type being // impl Trait, point at the return type and not the return expr. - *next + best_choice + 1 } else if path[best_choice].category == ConstraintCategory::Return(ReturnConstraint::Normal) && let Some(field) = path.iter().find_map(|p| { if let ConstraintCategory::ClosureUpvar(f) = p.category { Some(f) } else { None } @@ -1801,26 +1804,20 @@ impl<'tcx> RegionInferenceContext<'tcx> { { path[best_choice].category = ConstraintCategory::Return(ReturnConstraint::ClosureUpvar(field)); - path[best_choice] + best_choice } else { - path[best_choice] + best_choice }; assert!( !matches!( - best_constraint.category, + path[best_blame_idx].category, ConstraintCategory::OutlivesUnnameablePlaceholder(_) ), "Illegal placeholder constraint blamed; should have redirected to other region relation" ); - let blame_constraint = BlameConstraint { - category: best_constraint.category, - from_closure: best_constraint.from_closure, - span: best_constraint.span, - variance_info: best_constraint.variance_info, - }; - (blame_constraint, path) + BestBlame { path, idx: best_blame_idx } } pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { @@ -1895,21 +1892,19 @@ impl<'tcx> RegionInferenceContext<'tcx> { } #[derive(Clone, Debug)] -pub(crate) struct BlameConstraint<'tcx> { - pub category: ConstraintCategory<'tcx>, - pub from_closure: bool, - pub span: Span, - pub variance_info: ty::VarianceDiagInfo>, +pub(crate) struct BestBlame<'tcx> { + /// See docs on [`RegionInferenceContext::best_blame_constraint`] for what this is. + path: Vec>, + /// Index into `path` of the constraint most relevant to report to users. + idx: usize, } -impl<'tcx> BlameConstraint<'tcx> { - pub(crate) fn to_obligation_cause_from_path( - &self, - path: &[OutlivesConstraint<'tcx>], - ) -> ObligationCause<'tcx> { +impl<'tcx> BestBlame<'tcx> { + pub(crate) fn to_obligation_cause(&self) -> ObligationCause<'tcx> { // FIXME - determine what we should do if we encounter multiple // `ConstraintCategory::Predicate` constraints. Currently, we just pick the first one. - let cause_code = path + let cause_code = self + .path .iter() .find_map(|constraint| { if let ConstraintCategory::Predicate(predicate_span) = constraint.category { @@ -1923,6 +1918,14 @@ impl<'tcx> BlameConstraint<'tcx> { }) .unwrap_or_else(|| ObligationCauseCode::Misc); - ObligationCause::new(self.span, CRATE_DEF_ID, cause_code.clone()) + ObligationCause::new(self.constraint().span, CRATE_DEF_ID, cause_code.clone()) + } + + pub(crate) fn constraint(&self) -> &OutlivesConstraint<'tcx> { + &self.path[self.idx] + } + + pub(crate) fn path(&self) -> &[OutlivesConstraint<'tcx>] { + &self.path } } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 2fdc2897de9c9..0862588773732 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1892,13 +1892,19 @@ impl<'tcx> Pick<'tcx> { } impl<'a, 'tcx> ProbeContext<'a, 'tcx> { - fn select_trait_candidate( + fn select_trait_candidate_for_diagnostics( &self, trait_ref: ty::TraitRef<'tcx>, ) -> traits::SelectionResult<'tcx, traits::Selection<'tcx>> { let obligation = traits::Obligation::new(self.tcx, self.misc(self.span), self.param_env, trait_ref); - traits::SelectionContext::new(self).select(&obligation) + let candidate = traits::SelectionContext::new(self).select(&obligation); + if let Ok(Some(traits::ImplSource::UserDefined(impl_source_user_defined_data))) = &candidate + && self.infcx.tcx.do_not_recommend_impl(impl_source_user_defined_data.impl_def_id) + { + return Err(traits::SelectionError::Unimplemented); + } + candidate } /// Used for ambiguous method call error reporting. Uses probing that throws away the result internally, @@ -1926,7 +1932,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { xform_self_ty, self_ty, ); - match self.select_trait_candidate(trait_ref) { + match self.select_trait_candidate_for_diagnostics(trait_ref) { Ok(Some(traits::ImplSource::UserDefined(ref impl_data))) => { // If only a single impl matches, make the error message point // to that impl. @@ -2094,7 +2100,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { ocx.register_obligation(obligation); } else { result = ProbeResult::NoMatch; - if let Ok(Some(candidate)) = self.select_trait_candidate(trait_ref) { + if let Ok(Some(candidate)) = + self.select_trait_candidate_for_diagnostics(trait_ref) + { for nested_obligation in candidate.nested_obligations() { if !self.infcx.predicate_may_hold(&nested_obligation) { possibly_unsatisfied_predicates.push(( diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 6b5733e87b14c..a9ca6bfef5534 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -8,7 +8,7 @@ use std::ptr::NonNull; use rustc_data_structures::intern::Interned; use rustc_errors::{DiagArgValue, IntoDiagArg}; use rustc_hir::def_id::DefId; -use rustc_macros::{StableHash, TyDecodable, TyEncodable, extension}; +use rustc_macros::{Lift, StableHash, TyDecodable, TyEncodable, extension}; use rustc_serialize::{Decodable, Encodable}; use rustc_type_ir::WithCachedTypeInfo; use rustc_type_ir::walk::TypeWalker; @@ -715,7 +715,7 @@ impl<'tcx, T: TypeVisitable>> TypeVisitable> for &'tcx /// Stores the user-given args to reach some fully qualified path /// (e.g., `::Item` or `::Item`). #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(StableHash, TypeFoldable, TypeVisitable)] +#[derive(StableHash, TypeFoldable, TypeVisitable, Lift)] pub struct UserArgs<'tcx> { /// The args for the item as given by the user. pub args: GenericArgsRef<'tcx>, @@ -742,7 +742,7 @@ pub struct UserArgs<'tcx> { /// the self type, giving `Foo`. Finally, we unify that with /// the self type here, which contains `?A` to be `&'static u32` #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(StableHash, TypeFoldable, TypeVisitable)] +#[derive(StableHash, TypeFoldable, TypeVisitable, Lift)] pub struct UserSelfTy<'tcx> { pub impl_def_id: DefId, pub self_ty: Ty<'tcx>, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 03d13e6a81a6e..2d45b6feb59f0 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3418,6 +3418,29 @@ define_print_and_forward_display! { self.kind().print(p)?; } + ty::UserTypeKind<'tcx> { + match *self { + Self::Ty(ty) => { + write!(p, "Ty(")?; + ty.print(p)?; + } + Self::TypeOf(def_id, ty::UserArgs { args, user_self_ty }) => { + write!(p, "TypeOf(")?; + p.print_def_path(def_id, args)?; + if let Some(ty::UserSelfTy { impl_def_id, self_ty }) = user_self_ty { + write!(p, " at for ", key.disambiguated_data.as_sym(false))?; + self_ty.print(p)?; + write!(p, ">")?; + } + } + } + write!(p, ")")?; + } + GenericArg<'tcx> { match self.kind() { GenericArgKind::Lifetime(lt) => lt.print(p)?, diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 65a713602ed07..e11bc6d38495b 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -13,7 +13,7 @@ use rustc_hir::{ self as hir, BindingMode, ByRef, HirId, ItemLocalId, ItemLocalMap, ItemLocalSet, Mutability, }; use rustc_index::IndexVec; -use rustc_macros::{StableHash, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; +use rustc_macros::{Lift, StableHash, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_session::Session; use rustc_span::Span; @@ -798,7 +798,7 @@ impl<'tcx> UserType<'tcx> { /// from constants that are named via paths, like `Foo::::new` and /// so forth. #[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)] -#[derive(Eq, Hash, StableHash, TypeFoldable, TypeVisitable)] +#[derive(Eq, Hash, StableHash, TypeFoldable, TypeVisitable, Lift)] pub enum UserTypeKind<'tcx> { Ty(Ty<'tcx>), @@ -863,24 +863,12 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> { impl<'tcx> std::fmt::Display for UserType<'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if self.bounds.is_empty() { - self.kind.fmt(f) - } else { - self.kind.fmt(f)?; + self.kind.fmt(f)?; + for b in self.bounds { write!(f, " + ")?; - std::fmt::Debug::fmt(&self.bounds, f) - } - } -} - -impl<'tcx> std::fmt::Display for UserTypeKind<'tcx> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Ty(arg0) => { - ty::print::with_no_trimmed_paths!(write!(f, "Ty({})", arg0)) - } - Self::TypeOf(arg0, arg1) => write!(f, "TypeOf({:?}, {:?})", arg0, arg1), + b.fmt(f)?; } + Ok(()) } } diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 8b6a92071a7d7..5a4bf1a68dd5d 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -155,7 +155,6 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { match &stmt.kind { StatementKind::StorageDead(l) => state.kill(*l), - // If a place is assigned to in a statement, it needs storage for that statement. StatementKind::Assign((place, _)) => { state.gen_(place.local); } @@ -180,12 +179,35 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { fn apply_primary_statement_effect( &self, state: &mut Self::Domain, - _: &Statement<'tcx>, + stmt: &Statement<'tcx>, loc: Location, ) { // If we move from a place then it only stops needing storage *after* // that statement. self.check_for_move(state, loc); + + match &stmt.kind { + // If a place is assigned to in a statement, it needs storage after that statement. + // Even if the place was moved from in the rvalue (e.g. `x = x + 1` or `x = f(move x)`), + // the assignment restores a valid value into the place. + StatementKind::Assign((place, _)) => { + state.gen_(place.local); + } + StatementKind::SetDiscriminant { place, .. } => { + state.gen_(place.local); + } + + StatementKind::StorageDead(_) + | StatementKind::AscribeUserType(..) + | StatementKind::PlaceMention(..) + | StatementKind::Coverage(..) + | StatementKind::FakeRead(..) + | StatementKind::ConstEvalCounter + | StatementKind::Nop + | StatementKind::Intrinsic(..) + | StatementKind::BackwardIncompatibleDropHint { .. } + | StatementKind::StorageLive(..) => {} + } } fn apply_early_terminator_effect( diff --git a/compiler/rustc_mir_transform/src/coroutine/mod.rs b/compiler/rustc_mir_transform/src/coroutine/mod.rs index 53283680c0966..a64d23b0b939f 100644 --- a/compiler/rustc_mir_transform/src/coroutine/mod.rs +++ b/compiler/rustc_mir_transform/src/coroutine/mod.rs @@ -79,6 +79,7 @@ use rustc_span::def_id::DefId; use tracing::{debug, instrument}; use crate::deref_separator::deref_finder; +use crate::patch::MirPatch; use crate::{abort_unwinding_calls, pass_manager as pm, simplify}; pub(super) struct StateTransform; @@ -199,6 +200,8 @@ struct TransformVisitor<'tcx> { old_yield_ty: Ty<'tcx>, old_ret_ty: Ty<'tcx>, + + patch: Option>, } impl<'tcx> TransformVisitor<'tcx> { @@ -408,11 +411,51 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> { } #[tracing::instrument(level = "trace", skip(self), ret)] - fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, _location: Location) { + fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, location: Location) { // Replace an Local in the remap with a coroutine struct access if let Some(&Some((ty, variant_index, idx))) = self.remap.get(place.local) { replace_base(place, self.make_field(variant_index, idx, ty), self.tcx); } + if let Some(new_projection) = self.process_projection(&place.projection, location) { + place.projection = self.tcx.mk_place_elems(&new_projection); + } + } + + fn process_projection_elem( + &mut self, + elem: PlaceElem<'tcx>, + location: Location, + ) -> Option> { + match elem { + PlaceElem::Index(local) => { + if let Some(&Some((ty, variant, idx))) = self.remap.get(local) { + // `PlaceElem::Index` only accepts a `Local`, not an arbitrary `Place`. + // If the local in indexing was saved across a yield point and remapped to a + // coroutine struct field, we cannot inline the struct field access into + // the index projection. + // For example, an local storing the counter to track which element to drop in + // an array is one such case. + // + // Instead, we inject an assignment before this location to restore the + // saved local from the coroutine struct (`local = copy $projection`), + // and leave the `PlaceElem::Index(local)` projection unchanged. + let field = self.make_field(variant, idx, ty); + self.patch.as_mut().unwrap().add_assign( + location, + Place::from(local), + Rvalue::Use(Operand::Copy(field), WithRetag::No), + ); + } + None + } + PlaceElem::Field(..) + | PlaceElem::OpaqueCast(..) + | PlaceElem::UnwrapUnsafeBinder(..) + | PlaceElem::Deref + | PlaceElem::ConstantIndex { .. } + | PlaceElem::Subslice { .. } + | PlaceElem::Downcast(..) => None, + } } #[tracing::instrument(level = "trace", skip(self, stmt), ret)] @@ -1096,6 +1139,7 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { new_ret_local, old_ret_ty, old_yield_ty, + patch: Some(MirPatch::new(body)), }; transform.visit_body(body); @@ -1116,6 +1160,7 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { Some(Statement::new(source_info, assign)) }), ); + transform.patch.take().unwrap().apply(body); // Remove the context argument within generator bodies. if matches!(coroutine_kind, CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) { diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index e0d30f84c7e82..9a7236920d255 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -873,7 +873,7 @@ impl<'a> Parser<'a> { && let ast::AttrKind::Normal(next_attr_kind) = next_attr.kind && let Some(next_attr_args_span) = next_attr_kind.item.args.span() && let [next_segment] = &next_attr_kind.item.path.segments[..] - && segment.ident.name == sym::cfg + && next_segment.ident.name == sym::cfg { let next_expr = match snapshot.parse_expr() { Ok(next_expr) => next_expr, diff --git a/compiler/rustc_resolve/src/diagnostics/impls.rs b/compiler/rustc_resolve/src/diagnostics/impls.rs index ab8554f2652ee..b56e1263c17c8 100644 --- a/compiler/rustc_resolve/src/diagnostics/impls.rs +++ b/compiler/rustc_resolve/src/diagnostics/impls.rs @@ -2433,18 +2433,27 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Some(path) } - /// Shortens a candidate import path to use `super::` (up to 1 level) or `self::` (same module) - /// relative to the current scope, if possible. Only applies to crate-local items and - /// only when the resulting path is actually shorter than the original. fn shorten_candidate_path( &self, suggestion: &mut ImportSuggestion, current_module: Module<'ra>, + ) { + self.shorten_import_path(suggestion.did, &mut suggestion.path, current_module); + } + + /// Shortens an import path to use `super::` (up to 1 level) or `self::` (same module) + /// relative to the current scope, if possible. Only applies to crate-local items and + /// only when the resulting path is actually shorter than the original. + fn shorten_import_path( + &self, + did: Option, + path: &mut Path, + current_module: Module<'ra>, ) { const MAX_SUPER_PATH_ITEMS_IN_SUGGESTION: usize = 1; // Only shorten local items. - if suggestion.did.is_none_or(|did| !did.is_local()) { + if did.is_none_or(|did| !did.is_local()) { return; } @@ -2457,12 +2466,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // doesn't start with `Crate`, prepend it (edition 2015 paths are relative // to the crate root without an explicit `crate::` prefix). let candidate_names = { - let filtered_segments: Vec<_> = suggestion - .path - .segments - .iter() - .filter(|segment| segment.ident.name != kw::PathRoot) - .collect(); + let filtered_segments: Vec<_> = + path.segments.iter().filter(|segment| segment.ident.name != kw::PathRoot).collect(); let mut candidate_names: Vec = filtered_segments.iter().map(|segment| segment.ident.name).collect(); @@ -2511,11 +2516,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // Only apply if the result is strictly shorter than the original path. - if new_segments.len() >= suggestion.path.segments.len() { + if new_segments.len() >= path.segments.len() { return; } - suggestion.path = Path { span: suggestion.path.span, segments: new_segments }; + *path = Path { span: path.span, segments: new_segments }; } fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) { @@ -2668,17 +2673,80 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { match binding.kind { DeclKind::Import { source_decl, import, .. } => { - // Don't include `{{root}}` in suggestions - it's an internal symbol - // that should never be shown to users. - let path = import - .module_path - .iter() - .filter(|seg| seg.ident.name != kw::PathRoot) - .map(|seg| seg.ident.clone()) - .chain(std::iter::once(ident)) - .collect::>(); let through_reexport = !matches!(source_decl.kind, DeclKind::Def(_)); - sugg_paths.push((path, through_reexport)); + let uses_relative_path = import + .module_path + .first() + .is_some_and(|seg| matches!(seg.ident.name, kw::SelfLower | kw::Super)); + let res_def_id = res.opt_def_id(); + let path = if uses_relative_path { + // A path recovered from `self`/`super` is only useful if both the + // target and every module segment can be named from the failing use site. + let module_path = if let Some(ModuleOrUniformRoot::Module(module)) = + import.imported_module.get() + && module.is_local() + && let Some(module_path) = self.module_path_names(module) + && let Some(mut def_id) = module.opt_def_id() + && res_def_id.is_none_or(|def_id| { + self.is_accessible_from( + self.tcx.visibility(def_id), + parent_scope.module, + ) + }) { + // `module_path_names` tells us the resolved module's canonical path. + // Before suggesting that path from the failing use site, make sure + // every segment in it can actually be named from there. + let mut visible_from_use_site = true; + while let Some(parent) = self.tcx.opt_parent(def_id) { + if !self.is_accessible_from( + self.tcx.visibility(def_id), + parent_scope.module, + ) { + visible_from_use_site = false; + break; + } + if parent.is_top_level_module() { + break; + } + def_id = parent; + } + if visible_from_use_site { Some(module_path) } else { None } + } else { + None + }; + + module_path.map(|module_path| { + // `import.module_path` is relative to the import's module, not to the + // failing use site. + let mut path = Path { + span: ident.span, + segments: module_path + .into_iter() + .chain(std::iter::once(ident.name)) + .map(|name| { + ast::PathSegment::from_ident(Ident::with_dummy_span(name)) + }) + .collect(), + }; + self.shorten_import_path(res_def_id, &mut path, parent_scope.module); + path.segments.iter().map(|seg| seg.ident).collect() + }) + } else { + // Don't include `{{root}}` in suggestions - it's an internal symbol + // that should never be shown to users. + Some( + import + .module_path + .iter() + .filter(|seg| seg.ident.name != kw::PathRoot) + .map(|seg| seg.ident.clone()) + .chain(std::iter::once(ident)) + .collect::>(), + ) + }; + if let Some(path) = path { + sugg_paths.push((path, through_reexport)); + } } DeclKind::Def(_) => {} } diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 611bf5950d27d..8c1ebee8416e5 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -194,7 +194,7 @@ static ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("v6m", Unstable(sym::arm_target_feature), &["v6"]), ("v6t2", Unstable(sym::arm_target_feature), &["v6k", "v8m", "thumb2"]), ("v7", Unstable(sym::arm_target_feature), &["v6t2"]), - ("v8", Unstable(sym::arm_target_feature), &["v7"]), + ("v8", Unstable(sym::arm_target_feature), &["v7", "acquire-release"]), ("v8.1m.main", Unstable(sym::arm_target_feature), &["v8m.main"]), ("v8m", Unstable(sym::arm_target_feature), &["v6m"]), ("v8m.main", Unstable(sym::arm_target_feature), &["v7"]), diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 5863fd57e71e6..b6532f6064330 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -82,7 +82,7 @@ impl_zeroable_primitive!( /// /// `NonZero` is guaranteed to have the same layout and bit validity as `T` /// with the exception that the all-zero bit pattern is invalid. -/// `Option>` is guaranteed to be compatible with `T`, including in +/// `Option>` is guaranteed to be ABI-compatible with `T`, including in /// FFI. /// /// Thanks to the [null pointer optimization], `NonZero` and @@ -525,7 +525,7 @@ macro_rules! nonzero_integer { /// #[doc = concat!("`", stringify!($Ty), "` is guaranteed to have the same layout and bit validity as `", stringify!($Int), "`")] /// with the exception that `0` is not a valid instance. - #[doc = concat!("`Option<", stringify!($Ty), ">` is guaranteed to be compatible with `", stringify!($Int), "`,")] + #[doc = concat!("`Option<", stringify!($Ty), ">` is guaranteed to be ABI-compatible with `", stringify!($Int), "`,")] /// including in FFI. /// /// Thanks to the [null pointer optimization], diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index d2c2a88bbd08b..4aea78ccd94cb 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -47,7 +47,12 @@ use crate::{fmt, hash, intrinsics, mem, ptr}; /// it is your responsibility to ensure that `as_mut` is never called, and `as_ptr` /// is never used for mutation. /// -/// # Representation +/// # Layout +/// +/// `NonNull` is guaranteed to have the same layout and bit validity as `*mut T` +/// with the exception that a null pointer is invalid. +/// `Option>` is guaranteed to be ABI-compatible with `*mut T`, including in +/// FFI. /// /// Thanks to the [null pointer optimization], /// `NonNull` and `Option>` diff --git a/src/bootstrap/src/core/build_steps/clean.rs b/src/bootstrap/src/core/build_steps/clean.rs index 6dc03236053c7..fec4a79de3c75 100644 --- a/src/bootstrap/src/core/build_steps/clean.rs +++ b/src/bootstrap/src/core/build_steps/clean.rs @@ -58,8 +58,7 @@ macro_rules! clean_crate_tree { type Output = (); fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - let crates = run.builder.in_tree_crates($root_crate, None); - run.crates(crates) + run.crate_or_deps($root_crate) } fn make_run(run: RunConfig<'_>) { diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 4f96df6452d78..a1effa38387ca 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1018,16 +1018,11 @@ impl Step for Rustc { const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - let mut crates = run.builder.in_tree_crates("rustc-main", None); - for (i, krate) in crates.iter().enumerate() { + run.crate_or_deps_filtered("rustc-main", |krate| { // We can't allow `build rustc` as an alias for this Step, because that's reserved by `Assemble`. // Ideally Assemble would use `build compiler` instead, but that seems too confusing to be worth the breaking change. - if krate.name == "rustc-main" { - crates.swap_remove(i); - break; - } - } - run.crates(crates) + krate.name != "rustc-main" + }) } fn is_default_step(_builder: &Builder<'_>) -> bool { diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 0d17f0f792a01..b21a2fe77d94f 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -524,22 +524,30 @@ impl<'a> ShouldRun<'a> { ShouldRun { builder, kind, paths: BTreeSet::new(), default_to_suites_only: false } } - /// Indicates it should run if the command-line selects the given crate or - /// any of its (local) dependencies. + /// The corresponding step should run if the bootstrap command-line selects + /// the given crate or any of its (local) dependencies. /// - /// `make_run` will be called a single time with all matching command-line paths. - pub fn crate_or_deps(self, name: &str) -> Self { - let crates = self.builder.in_tree_crates(name, None); - self.crates(crates) + /// Delegates to [`Self::crate_or_deps_filtered`] with a filter that accepts all crates. + pub(crate) fn crate_or_deps(self, root_crate_name: &str) -> Self { + self.crate_or_deps_filtered(root_crate_name, |_: &Crate| true) } - /// Indicates it should run if the command-line selects any of the given crates. + /// The corresponding step should run if the bootstrap command-line selects + /// the given crate or any of its (local) dependencies, not counting any + /// crates rejected by the given filter function. /// /// `make_run` will be called a single time with all matching command-line paths. - /// - /// Prefer [`ShouldRun::crate_or_deps`] to this function where possible. - pub(crate) fn crates(mut self, crates: Vec<&Crate>) -> Self { + pub(crate) fn crate_or_deps_filtered( + mut self, + root_crate_name: &str, + crate_filter_fn: impl Fn(&Crate) -> bool, + ) -> Self { + let crates = self.builder.in_tree_crates(root_crate_name, None); for krate in crates { + if !crate_filter_fn(krate) { + continue; + } + let path = krate.local_path(self.builder); self.paths.insert(PathSet::one(path, self.kind)); } diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index f7ffc682e2bd7..f08346789e7e8 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -1735,7 +1735,9 @@ impl Build { } } } - ret.sort_unstable_by_key(|krate| krate.name.clone()); // reproducible order needed for tests + + // Sort the crates so that bootstrap unit tests can assume a deterministic order. + ret.sort_unstable_by(|a, b| Ord::cmp(&a.name, &b.name)); ret } diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 2a45b6ea4f932..8d9304dfaf316 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -699,9 +699,9 @@ dependencies = [ [[package]] name = "gen-lsp-types" -version = "0.4.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5b8ec601e62362b666a3def1fed667ee87b10a4507402618376d142a05373c6" +checksum = "4cd635c5206acd03ea024d6b5902539e5c903de3afa220fdb5c94b583af77f4f" dependencies = [ "serde", "serde_json", @@ -858,7 +858,6 @@ dependencies = [ "intern", "itertools 0.15.0", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "query-group-macro", "ra-ap-rustc_abi", "ra-ap-rustc_parse_format", "rustc-hash 2.1.2", @@ -891,7 +890,6 @@ dependencies = [ "itertools 0.15.0", "mbe", "parser", - "query-group-macro", "rustc-hash 2.1.2", "salsa", "salsa-macros", @@ -1457,7 +1455,7 @@ dependencies = [ [[package]] name = "lsp-server" -version = "0.8.0" +version = "0.9.0" dependencies = [ "anyhow", "crossbeam-channel", @@ -2573,9 +2571,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" dependencies = [ "indexmap", "itoa", diff --git a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml index 46acf3de62644..038ddecdb5d7d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml @@ -29,7 +29,6 @@ triomphe.workspace = true rustc_apfloat = "0.2.3" salsa.workspace = true salsa-macros.workspace = true -query-group.workspace = true ra-ap-rustc_parse_format.workspace = true ra-ap-rustc_abi.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-def/src/attrs.rs index 90fae16ccd0c2..27f9763f088a4 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attrs.rs @@ -17,7 +17,7 @@ use std::{convert::Infallible, iter::Peekable, ops::ControlFlow}; -use base_db::Crate; +use base_db::{Crate, SourceDatabase}; use cfg::{CfgExpr, CfgOptions}; use either::Either; use hir_expand::{ @@ -39,7 +39,6 @@ use tt::TextSize; use crate::{ AdtId, AstIdLoc, AttrDefId, FieldId, FunctionId, GenericDefId, HasModule, LifetimeParamId, LocalFieldId, MacroId, ModuleId, TypeOrConstParamId, VariantId, - db::DefDatabase, hir::generics::{GenericParams, LocalLifetimeParamId, LocalTypeOrConstParamId}, nameres::ModuleOrigin, resolver::{HasResolver, Resolver}, @@ -52,8 +51,8 @@ pub use self::docs::{Docs, IsInnerDoc}; #[inline] fn attrs_from_ast_id_loc>( - db: &dyn DefDatabase, - lookup: impl Lookup + HasModule>, + db: &dyn SourceDatabase, + lookup: impl Lookup + HasModule>, ) -> (InFile, Crate) { let loc = lookup.lookup(db); let source = loc.source(db); @@ -351,7 +350,7 @@ bitflags::bitflags! { } } -pub fn parse_extra_crate_attrs(db: &dyn DefDatabase, krate: Crate) -> Option { +pub fn parse_extra_crate_attrs(db: &dyn SourceDatabase, krate: Crate) -> Option { let crate_data = krate.data(db); let crate_attrs = &crate_data.crate_attrs; if crate_attrs.is_empty() { @@ -382,7 +381,7 @@ pub fn parse_extra_crate_attrs(db: &dyn DefDatabase, krate: Crate) -> Option (InFile, Option>, Option, Crate) { let (owner, krate) = match owner { @@ -435,7 +434,7 @@ fn attrs_source( (owner, None, None, krate) } -fn resolver_for_attr_def_id(db: &dyn DefDatabase, owner: AttrDefId) -> Resolver<'_> { +fn resolver_for_attr_def_id(db: &dyn SourceDatabase, owner: AttrDefId) -> Resolver<'_> { match owner { AttrDefId::ModuleId(id) => id.resolver(db), AttrDefId::AdtId(AdtId::StructId(id)) => id.resolver(db), @@ -458,7 +457,7 @@ fn resolver_for_attr_def_id(db: &dyn DefDatabase, owner: AttrDefId) -> Resolver< } fn collect_attrs( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, owner: AttrDefId, mut callback: impl FnMut(ast::Meta) -> ControlFlow, ) -> Option { @@ -477,7 +476,7 @@ fn collect_attrs( } fn collect_field_attrs( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, variant: VariantId, mut field_attrs: impl FnMut(&CfgOptions, InFile) -> T, ) -> ArenaMap { @@ -572,14 +571,14 @@ fn extract_cfgs(result: &mut Vec, attr: ast::Meta) -> ControlFlow AttrFlags { + pub fn query(db: &dyn SourceDatabase, owner: AttrDefId) -> AttrFlags { let mut attr_flags = AttrFlags::empty(); collect_attrs(db, owner, |attr| match_attr_flags(&mut attr_flags, attr)); attr_flags } #[inline] - pub fn query_field(db: &dyn DefDatabase, field: FieldId) -> AttrFlags { + pub fn query_field(db: &dyn SourceDatabase, field: FieldId) -> AttrFlags { return field_attr_flags(db, field.parent) .get(field.local_id) .copied() @@ -587,7 +586,7 @@ impl AttrFlags { #[salsa::tracked(returns(ref))] fn field_attr_flags( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, variant: VariantId, ) -> ArenaMap { collect_field_attrs(db, variant, |cfg_options, field| { @@ -604,7 +603,7 @@ impl AttrFlags { #[inline] pub fn query_generic_params( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, def: GenericDefId, ) -> &(ArenaMap, ArenaMap) { @@ -618,7 +617,7 @@ impl AttrFlags { #[salsa::tracked(returns(ref))] fn generic_params_attr_flags( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, def: GenericDefId, ) -> (ArenaMap, ArenaMap) { @@ -659,7 +658,7 @@ impl AttrFlags { } #[inline] - pub fn query_lifetime_param(db: &dyn DefDatabase, owner: LifetimeParamId) -> AttrFlags { + pub fn query_lifetime_param(db: &dyn SourceDatabase, owner: LifetimeParamId) -> AttrFlags { AttrFlags::query_generic_params(db, owner.parent) .0 .get(owner.local_id) @@ -667,7 +666,10 @@ impl AttrFlags { .unwrap_or_else(AttrFlags::empty) } #[inline] - pub fn query_type_or_const_param(db: &dyn DefDatabase, owner: TypeOrConstParamId) -> AttrFlags { + pub fn query_type_or_const_param( + db: &dyn SourceDatabase, + owner: TypeOrConstParamId, + ) -> AttrFlags { AttrFlags::query_generic_params(db, owner.parent) .1 .get(owner.local_id) @@ -702,12 +704,12 @@ impl AttrFlags { } #[inline] - pub fn lang_item(db: &dyn DefDatabase, owner: AttrDefId) -> Option { + pub fn lang_item(db: &dyn SourceDatabase, owner: AttrDefId) -> Option { AttrFlags::query(db, owner).lang_item_with_attrs(db, owner) } #[inline] - pub fn lang_item_with_attrs(self, db: &dyn DefDatabase, owner: AttrDefId) -> Option { + pub fn lang_item_with_attrs(self, db: &dyn SourceDatabase, owner: AttrDefId) -> Option { if !self.contains(AttrFlags::LANG_ITEM) { // Don't create the query in case this is not a lang item, this wastes memory. return None; @@ -716,7 +718,7 @@ impl AttrFlags { return lang_item(db, owner); #[salsa::tracked] - fn lang_item(db: &dyn DefDatabase, owner: AttrDefId) -> Option { + fn lang_item(db: &dyn SourceDatabase, owner: AttrDefId) -> Option { collect_attrs(db, owner, |attr| { if let ast::Meta::KeyValueMeta(attr) = attr && attr.path().is1("lang") @@ -731,7 +733,7 @@ impl AttrFlags { } #[inline] - pub fn repr(db: &dyn DefDatabase, owner: AdtId) -> Option { + pub fn repr(db: &dyn SourceDatabase, owner: AdtId) -> Option { if !AttrFlags::query(db, owner.into()).contains(AttrFlags::HAS_REPR) { // Don't create the query in case this has no repr, this wastes memory. return None; @@ -745,7 +747,7 @@ impl AttrFlags { /// Prefer [`AttrFlags::repr()`] in non-perf-sensitive places as it also has a check that /// that the ADT has repr. #[salsa::tracked] - pub fn repr_assume_has(db: &dyn DefDatabase, owner: AdtId) -> Option { + pub fn repr_assume_has(db: &dyn SourceDatabase, owner: AdtId) -> Option { let mut result = None; collect_attrs::(db, owner.into(), |attr| { let mut current = None; @@ -792,7 +794,7 @@ impl AttrFlags { /// Call this only if there are legacy const generics, to save memory. #[salsa::tracked(returns(ref))] pub(crate) fn legacy_const_generic_indices( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, owner: FunctionId, ) -> Option> { let result = collect_attrs(db, owner.into(), |attr| { @@ -811,7 +813,7 @@ impl AttrFlags { // There aren't typically many crates, so it's okay to always make this a query without a flag. #[salsa::tracked(returns(ref))] - pub fn doc_html_root_url(db: &dyn DefDatabase, krate: Crate) -> Option { + pub fn doc_html_root_url(db: &dyn SourceDatabase, krate: Crate) -> Option { let root_file_id = krate.root_file_id(db); let syntax = root_file_id.parse(db).tree(); let extra_crate_attrs = @@ -844,7 +846,7 @@ impl AttrFlags { } #[inline] - pub fn target_features(db: &dyn DefDatabase, owner: FunctionId) -> &FxHashSet { + pub fn target_features(db: &dyn SourceDatabase, owner: FunctionId) -> &FxHashSet { if !AttrFlags::query(db, owner.into()).contains(AttrFlags::HAS_TARGET_FEATURE) { return const { &FxHashSet::with_hasher(rustc_hash::FxBuildHasher) }; } @@ -852,7 +854,7 @@ impl AttrFlags { return target_features(db, owner); #[salsa::tracked(returns(ref))] - fn target_features(db: &dyn DefDatabase, owner: FunctionId) -> FxHashSet { + fn target_features(db: &dyn SourceDatabase, owner: FunctionId) -> FxHashSet { let mut result = FxHashSet::default(); collect_attrs::(db, owner.into(), |attr| { if let ast::Meta::TokenTreeMeta(attr) = attr @@ -887,7 +889,7 @@ impl AttrFlags { #[inline] pub fn rustc_layout_scalar_valid_range( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, owner: AdtId, ) -> RustcLayoutScalarValidRange { if !AttrFlags::query(db, owner.into()).contains(AttrFlags::RUSTC_LAYOUT_SCALAR_VALID_RANGE) @@ -899,7 +901,7 @@ impl AttrFlags { #[salsa::tracked] fn rustc_layout_scalar_valid_range( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, owner: AdtId, ) -> RustcLayoutScalarValidRange { let mut result = RustcLayoutScalarValidRange::default(); @@ -927,7 +929,11 @@ impl AttrFlags { } #[inline] - pub fn doc_aliases(self, db: &dyn DefDatabase, owner: Either) -> &[Symbol] { + pub fn doc_aliases( + self, + db: &dyn SourceDatabase, + owner: Either, + ) -> &[Symbol] { if !self.contains(AttrFlags::HAS_DOC_ALIASES) { return &[]; } @@ -940,7 +946,7 @@ impl AttrFlags { }; #[salsa::tracked(returns(ref))] - fn doc_aliases(db: &dyn DefDatabase, owner: AttrDefId) -> Box<[Symbol]> { + fn doc_aliases(db: &dyn SourceDatabase, owner: AttrDefId) -> Box<[Symbol]> { let mut result = Vec::new(); collect_attrs::(db, owner, |attr| extract_doc_aliases(&mut result, attr)); result.into_boxed_slice() @@ -948,7 +954,7 @@ impl AttrFlags { #[salsa::tracked(returns(ref))] fn fields_doc_aliases( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, variant: VariantId, ) -> ArenaMap> { collect_field_attrs(db, variant, |cfg_options, field| { @@ -964,7 +970,11 @@ impl AttrFlags { } #[inline] - pub fn cfgs(self, db: &dyn DefDatabase, owner: Either) -> Option<&CfgExpr> { + pub fn cfgs( + self, + db: &dyn SourceDatabase, + owner: Either, + ) -> Option<&CfgExpr> { if !self.contains(AttrFlags::HAS_CFG) { return None; } @@ -977,7 +987,7 @@ impl AttrFlags { // We LRU this query because it is only used by IDE. #[salsa::tracked(returns(ref), lru = 250)] - fn cfgs(db: &dyn DefDatabase, owner: AttrDefId) -> Option { + fn cfgs(db: &dyn SourceDatabase, owner: AttrDefId) -> Option { let mut result = Vec::new(); collect_attrs::(db, owner, |attr| extract_cfgs(&mut result, attr)); match result.len() { @@ -990,7 +1000,7 @@ impl AttrFlags { // We LRU this query because it is only used by IDE. #[salsa::tracked(returns(ref), lru = 50)] fn fields_cfgs( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, variant: VariantId, ) -> ArenaMap> { collect_field_attrs(db, variant, |cfg_options, field| { @@ -1010,14 +1020,14 @@ impl AttrFlags { } #[inline] - pub fn doc_keyword(db: &dyn DefDatabase, owner: ModuleId) -> Option { + pub fn doc_keyword(db: &dyn SourceDatabase, owner: ModuleId) -> Option { if !AttrFlags::query(db, AttrDefId::ModuleId(owner)).contains(AttrFlags::HAS_DOC_KEYWORD) { return None; } return doc_keyword(db, owner); #[salsa::tracked] - fn doc_keyword(db: &dyn DefDatabase, owner: ModuleId) -> Option { + fn doc_keyword(db: &dyn SourceDatabase, owner: ModuleId) -> Option { collect_attrs(db, AttrDefId::ModuleId(owner), |attr| { if let ast::Meta::TokenTreeMeta(attr) = attr && attr.path().is1("doc") @@ -1038,7 +1048,7 @@ impl AttrFlags { // We LRU this query because it is only used by IDE. #[salsa::tracked(returns(ref), lru = 250)] - pub fn docs(db: &dyn DefDatabase, owner: AttrDefId) -> Option> { + pub fn docs(db: &dyn SourceDatabase, owner: AttrDefId) -> Option> { let (source, outer_mod_decl, _extra_crate_attrs, krate) = attrs_source(db, owner); let inner_attrs_node = source.value.inner_attributes_node(); // Note: we don't have to pass down `_extra_crate_attrs` here, since `extract_docs` @@ -1056,13 +1066,13 @@ impl AttrFlags { } #[inline] - pub fn field_docs(db: &dyn DefDatabase, field: FieldId) -> Option<&Docs> { + pub fn field_docs(db: &dyn SourceDatabase, field: FieldId) -> Option<&Docs> { return fields_docs(db, field.parent).get(field.local_id).and_then(|it| it.as_deref()); // We LRU this query because it is only used by IDE. #[salsa::tracked(returns(ref), lru = 50)] pub fn fields_docs( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, variant: VariantId, ) -> ArenaMap>> { let krate = variant.module(db).krate(db); @@ -1081,7 +1091,7 @@ impl AttrFlags { } #[inline] - pub fn derive_info(db: &dyn DefDatabase, owner: MacroId) -> Option<&DeriveInfo> { + pub fn derive_info(db: &dyn SourceDatabase, owner: MacroId) -> Option<&DeriveInfo> { if !AttrFlags::query(db, owner.into()).contains(AttrFlags::IS_DERIVE_OR_BUILTIN_MACRO) { return None; } @@ -1089,7 +1099,7 @@ impl AttrFlags { return derive_info(db, owner).as_ref(); #[salsa::tracked(returns(ref))] - fn derive_info(db: &dyn DefDatabase, owner: MacroId) -> Option { + fn derive_info(db: &dyn SourceDatabase, owner: MacroId) -> Option { collect_attrs(db, owner.into(), |attr| { if let ast::Meta::TokenTreeMeta(attr) = attr && (attr.path().is1("proc_macro_derive") @@ -1126,7 +1136,7 @@ impl AttrFlags { } } - pub fn unstable_feature(self, db: &dyn DefDatabase, owner: AttrDefId) -> Option { + pub fn unstable_feature(self, db: &dyn SourceDatabase, owner: AttrDefId) -> Option { if !self.contains(AttrFlags::IS_UNSTABLE) { return None; } @@ -1134,7 +1144,7 @@ impl AttrFlags { return unstable_feature(db, owner); #[salsa::tracked] - fn unstable_feature(db: &dyn DefDatabase, owner: AttrDefId) -> Option { + fn unstable_feature(db: &dyn SourceDatabase, owner: AttrDefId) -> Option { collect_attrs(db, owner, |attr| { if let ast::Meta::TokenTreeMeta(attr) = attr && let path = attr.path() @@ -1163,14 +1173,14 @@ impl AttrFlags { /// Returns `None` if there is no `#[must_use]`, `Some(None)` if there is a `#[must_use]` without a message, /// and `Some(Some(message))` if there is a `#[must_use]` with a message. - pub fn must_use_message(db: &dyn DefDatabase, owner: AttrDefId) -> Option> { + pub fn must_use_message(db: &dyn SourceDatabase, owner: AttrDefId) -> Option> { if !AttrFlags::query(db, owner).contains(AttrFlags::IS_MUST_USE) { return None; } return Some(must_use_message(db, owner)); #[salsa::tracked(returns(as_deref))] - fn must_use_message(db: &dyn DefDatabase, owner: AttrDefId) -> Option> { + fn must_use_message(db: &dyn SourceDatabase, owner: AttrDefId) -> Option> { collect_attrs(db, owner, |attr| { if let ast::Meta::KeyValueMeta(attr) = attr && attr.path().is1("must_use") diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attrs/docs.rs b/src/tools/rust-analyzer/crates/hir-def/src/attrs/docs.rs index 0d01d54786a1f..bdd8ea84a0910 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attrs/docs.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attrs/docs.rs @@ -11,7 +11,7 @@ use std::{ ops::{ControlFlow, Range}, }; -use base_db::Crate; +use base_db::{Crate, SourceDatabase}; use cfg::CfgOptions; use either::Either; use hir_expand::{ @@ -27,7 +27,7 @@ use syntax::{ }; use tt::{TextRange, TextSize}; -use crate::{db::DefDatabase, macro_call_as_call_id, nameres::MacroSubNs, resolver::Resolver}; +use crate::{macro_call_as_call_id, nameres::MacroSubNs, resolver::Resolver}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct DocsSourceMapLine { @@ -323,13 +323,10 @@ impl Docs { } struct DocMacroExpander<'db> { - db: &'db dyn DefDatabase, + db: &'db dyn SourceDatabase, krate: Crate, recursion_depth: usize, recursion_limit: usize, -} - -struct DocExprSourceCtx<'db> { resolver: Resolver<'db>, file_id: HirFileId, ast_id_map: &'db AstIdMap, @@ -338,12 +335,11 @@ struct DocExprSourceCtx<'db> { fn expand_doc_expr_via_macro_pipeline<'db>( expander: &mut DocMacroExpander<'db>, - source_ctx: &DocExprSourceCtx<'db>, expr: ast::Expr, ) -> Option { match expr { ast::Expr::ParenExpr(paren_expr) => { - expand_doc_expr_via_macro_pipeline(expander, source_ctx, paren_expr.expr()?) + expand_doc_expr_via_macro_pipeline(expander, paren_expr.expr()?) } ast::Expr::Literal(literal) => match literal.kind() { ast::LiteralKind::String(string) => string.value().ok().map(Into::into), @@ -351,9 +347,7 @@ fn expand_doc_expr_via_macro_pipeline<'db>( }, ast::Expr::MacroExpr(macro_expr) => { let macro_call = macro_expr.macro_call()?; - let (expr, new_source_ctx) = expand_doc_macro_call(expander, source_ctx, macro_call)?; - // After expansion, the expr lives in the expansion file; use its source context. - expand_doc_expr_via_macro_pipeline(expander, &new_source_ctx, expr) + expand_doc_macro_call(expander, macro_call) } _ => None, } @@ -361,19 +355,18 @@ fn expand_doc_expr_via_macro_pipeline<'db>( fn expand_doc_macro_call<'db>( expander: &mut DocMacroExpander<'db>, - source_ctx: &DocExprSourceCtx<'db>, macro_call: ast::MacroCall, -) -> Option<(ast::Expr, DocExprSourceCtx<'db>)> { +) -> Option { if expander.recursion_depth >= expander.recursion_limit { return None; } let path = macro_call.path()?; let mod_path = ModPath::from_src(expander.db, path, &mut |range| { - source_ctx.span_map.span_for_range(range).ctx + expander.span_map.span_for_range(range).ctx })?; - let call_site = source_ctx.span_map.span_for_range(macro_call.syntax().text_range()); - let ast_id = AstId::new(source_ctx.file_id, source_ctx.ast_id_map.ast_id(¯o_call)); + let call_site = expander.span_map.span_for_range(macro_call.syntax().text_range()); + let ast_id = AstId::new(expander.file_id, expander.ast_id_map.ast_id(¯o_call)); let call_id = macro_call_as_call_id( expander.db, ast_id, @@ -382,34 +375,40 @@ fn expand_doc_macro_call<'db>( ExpandTo::Expr, expander.krate, |path| { - source_ctx.resolver.resolve_path_as_macro_def(expander.db, path, Some(MacroSubNs::Bang)) + expander.resolver.resolve_path_as_macro_def(expander.db, path, Some(MacroSubNs::Bang)) }, &mut |_, _| (), ) .ok()? .value?; - expander.recursion_depth += 1; - let parse = expander.db.parse_macro_expansion(call_id).value.0.clone(); - let expr = parse.cast::().map(|parse| parse.tree())?; - expander.recursion_depth -= 1; + let (parse, span_map) = &call_id.parse_macro_expansion(expander.db).value; + let expr = parse.clone().cast::().map(|parse| parse.tree())?; // Build a new source context for the expansion file so that any further // recursive expansion (e.g. a user macro expanding to `concat!(...)`) // correctly resolves AstIds and spans in the expansion. let expansion_file_id: HirFileId = call_id.into(); - let new_source_ctx = DocExprSourceCtx { - resolver: source_ctx.resolver.clone(), - file_id: expansion_file_id, - ast_id_map: expander.db.ast_id_map(expansion_file_id), - span_map: expander.db.span_map(expansion_file_id), - }; - Some((expr, new_source_ctx)) + let old_file_id = std::mem::replace(&mut expander.file_id, expansion_file_id); + let old_span_map = + std::mem::replace(&mut expander.span_map, SpanMap::ExpansionSpanMap(span_map)); + let old_ast_id_map = + std::mem::replace(&mut expander.ast_id_map, expansion_file_id.ast_id_map(expander.db)); + expander.recursion_depth += 1; + + let expansion = expand_doc_expr_via_macro_pipeline(expander, expr); + + expander.file_id = old_file_id; + expander.span_map = old_span_map; + expander.ast_id_map = old_ast_id_map; + expander.recursion_depth -= 1; + + expansion } fn extend_with_attrs<'a, 'db>( result: &mut Docs, - db: &'db dyn DefDatabase, + db: &'db dyn SourceDatabase, krate: Crate, node: &SyntaxNode, file_id: HirFileId, @@ -420,7 +419,7 @@ fn extend_with_attrs<'a, 'db>( make_resolver: &dyn Fn() -> Resolver<'db>, ) { // Lazily initialised when we first encounter a `#[doc = macro!()]`. - let mut expander: Option<(DocMacroExpander<'db>, DocExprSourceCtx<'db>)> = None; + let mut expander: Option> = None; expand_cfg_attr_with_doc_comments::<_, Infallible>( AttrDocCommentIter::from_syntax_node(node).filter(|attr| match attr { @@ -442,27 +441,23 @@ fn extend_with_attrs<'a, 'db>( { result.extend_with_doc_attr(value, indent); } else { - let (exp, ctx) = expander.get_or_insert_with(|| { + let exp = expander.get_or_insert_with(|| { let resolver = make_resolver(); let def_map = resolver.top_level_def_map(); let recursion_limit = def_map.recursion_limit() as usize; - ( - DocMacroExpander { - db, - krate, - recursion_depth: 0, - recursion_limit, - }, - DocExprSourceCtx { - resolver, - file_id, - ast_id_map: db.ast_id_map(file_id), - span_map: db.span_map(file_id), - }, - ) + DocMacroExpander { + db, + krate, + recursion_depth: 0, + recursion_limit, + resolver, + file_id, + ast_id_map: file_id.ast_id_map(db), + span_map: file_id.span_map(db), + } }); if let Some(expanded) = - expand_doc_expr_via_macro_pipeline(exp, ctx, value) + expand_doc_expr_via_macro_pipeline(exp, value) { result.extend_with_unmapped_doc_str(&expanded, indent); } @@ -478,7 +473,7 @@ fn extend_with_attrs<'a, 'db>( } pub(crate) fn extract_docs<'a, 'db>( - db: &'db dyn DefDatabase, + db: &'db dyn SourceDatabase, krate: Crate, resolver: &dyn Fn() -> Resolver<'db>, get_cfg_options: &dyn Fn() -> &'a CfgOptions, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/builtin_derive.rs b/src/tools/rust-analyzer/crates/hir-def/src/builtin_derive.rs index 946f08ec3682e..6004a33ee19b7 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/builtin_derive.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/builtin_derive.rs @@ -3,13 +3,14 @@ //! To save time and memory, builtin derives are not really expanded. Instead, we record them //! and create their impls based on lowered data, see crates/hir-ty/src/builtin_derive.rs. +use base_db::SourceDatabase; use hir_expand::{InFile, builtin::BuiltinDeriveExpander, name::Name}; use intern::{Symbol, sym}; use tt::TextRange; use crate::{ AdtId, BuiltinDeriveImplId, BuiltinDeriveImplLoc, FunctionId, HasModule, MacroId, - db::DefDatabase, lang_item::LangItems, + lang_item::LangItems, }; macro_rules! declare_enum { @@ -109,7 +110,7 @@ impl BuiltinDeriveImplTrait { impl BuiltinDeriveImplMethod { pub fn trait_method( self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, impl_: BuiltinDeriveImplId, ) -> Option { let loc = impl_.loc(db); @@ -143,7 +144,7 @@ pub(crate) fn with_derive_traits( } impl BuiltinDeriveImplLoc { - pub fn source(&self, db: &dyn DefDatabase) -> InFile { + pub fn source(&self, db: &dyn SourceDatabase) -> InFile { let (adt_ast_id, module) = match self.adt { AdtId::StructId(adt) => { let adt_loc = adt.loc(db); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs deleted file mode 100644 index d1190686fc5e4..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ /dev/null @@ -1,136 +0,0 @@ -//! Defines database & queries for name resolution. -use base_db::{Crate, SourceDatabase}; -use hir_expand::{ - EditionedFileId, HirFileId, InFile, Lookup, MacroCallId, MacroDefId, MacroDefKind, - db::ExpandDatabase, -}; -use salsa::{Durability, Setter}; -use triomphe::Arc; - -use crate::{ - AssocItemId, AttrDefId, MacroExpander, MacroId, MacroRulesLocFlags, TraitId, - attrs::AttrFlags, - item_tree::{ItemTree, file_item_tree}, - nameres::crate_def_map, - visibility::{self, Visibility}, -}; - -#[query_group::query_group] -pub trait DefDatabase: ExpandDatabase + SourceDatabase { - /// Computes an [`ItemTree`] for the given file or macro expansion. - #[salsa::invoke(file_item_tree)] - #[salsa::transparent] - fn file_item_tree(&self, file_id: HirFileId, krate: Crate) -> &ItemTree; - - /// Turns a MacroId into a MacroDefId, describing the macro's definition post name resolution. - #[salsa::invoke(macro_def)] - fn macro_def(&self, m: MacroId) -> MacroDefId; - - // region:visibilities - - #[salsa::invoke(visibility::assoc_visibility_query)] - fn assoc_visibility(&self, def: AssocItemId) -> Visibility; - - // endregion:visibilities - - #[salsa::invoke(crate::lang_item::crate_notable_traits)] - #[salsa::transparent] - fn crate_notable_traits(&self, krate: Crate) -> Option<&[TraitId]>; - - #[salsa::invoke(crate_supports_no_std)] - fn crate_supports_no_std(&self, crate_id: Crate) -> bool; - - #[salsa::invoke(include_macro_invoc)] - fn include_macro_invoc(&self, crate_id: Crate) -> Arc<[(MacroCallId, EditionedFileId)]>; -} - -/// Whether to expand procedural macros during name resolution. -/// -/// Note: this struct shouldn't be exposed to ide crates -- consider using -/// [`set_expand_proc_attr_macros`] instead, if possible. -#[salsa::input(singleton, debug)] -pub(crate) struct ExpandProcAttrMacros { - #[returns(copy)] - pub(crate) enabled: bool, -} - -pub fn set_expand_proc_attr_macros(db: &mut dyn DefDatabase, enabled: bool) { - if let Some(expand_proc_attr_macros) = ExpandProcAttrMacros::try_get(db) { - if expand_proc_attr_macros.enabled(db) != enabled { - expand_proc_attr_macros.set_enabled(db).with_durability(Durability::HIGH).to(enabled); - } - } else { - _ = ExpandProcAttrMacros::builder(enabled).durability(Durability::HIGH).new(db); - } -} - -// return: macro call id and include file id -fn include_macro_invoc( - db: &dyn DefDatabase, - krate: Crate, -) -> Arc<[(MacroCallId, EditionedFileId)]> { - crate_def_map(db, krate) - .modules - .values() - .flat_map(|m| m.scope.iter_macro_invoc()) - .filter_map(|invoc| invoc.1.loc(db).include_file_id(db, *invoc.1).map(|x| (*invoc.1, x))) - .collect() -} - -fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: Crate) -> bool { - let root_module = crate_def_map(db, crate_id).root_module_id(); - let attrs = AttrFlags::query(db, AttrDefId::ModuleId(root_module)); - attrs.contains(AttrFlags::IS_NO_STD) -} - -fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { - let kind = |expander, file_id, m| { - let in_file = InFile::new(file_id, m); - match expander { - MacroExpander::Declarative { styles } => MacroDefKind::Declarative(in_file, styles), - MacroExpander::BuiltIn(it) => MacroDefKind::BuiltIn(in_file, it), - MacroExpander::BuiltInAttr(it) => MacroDefKind::BuiltInAttr(in_file, it), - MacroExpander::BuiltInDerive(it) => MacroDefKind::BuiltInDerive(in_file, it), - MacroExpander::BuiltInEager(it) => MacroDefKind::BuiltInEager(in_file, it), - MacroExpander::UnimplementedBuiltIn => MacroDefKind::UnimplementedBuiltIn(in_file), - } - }; - - match id { - MacroId::Macro2Id(it) => { - let loc = it.lookup(db); - - MacroDefId { - krate: loc.container.krate(db), - kind: kind(loc.expander, loc.id.file_id, loc.id.value.upcast()), - local_inner: false, - allow_internal_unsafe: loc.allow_internal_unsafe, - edition: loc.edition, - } - } - MacroId::MacroRulesId(it) => { - let loc = it.lookup(db); - - MacroDefId { - krate: loc.container.krate(db), - kind: kind(loc.expander, loc.id.file_id, loc.id.value.upcast()), - local_inner: loc.flags.contains(MacroRulesLocFlags::LOCAL_INNER), - allow_internal_unsafe: loc - .flags - .contains(MacroRulesLocFlags::ALLOW_INTERNAL_UNSAFE), - edition: loc.edition, - } - } - MacroId::ProcMacroId(it) => { - let loc = it.lookup(db); - - MacroDefId { - krate: loc.container.krate(db), - kind: MacroDefKind::ProcMacro(loc.id, loc.expander, loc.kind), - local_inner: false, - allow_internal_unsafe: false, - edition: loc.edition, - } - } - } -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs index 6df95e1a787ab..6ec78235feb5e 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs @@ -14,6 +14,7 @@ use std::{ ops::{Deref, Index}, }; +use base_db::SourceDatabase; use cfg::{CfgExpr, CfgOptions}; use either::Either; use hir_expand::{InFile, MacroCallId, mod_path::ModPath, name::Name}; @@ -27,7 +28,6 @@ use tt::TextRange; use crate::{ AdtId, BlockId, ExpressionStoreOwnerId, GenericDefId, SyntheticSyntax, - db::DefDatabase, expr_store::path::{AssociatedTypeBinding, GenericArg, GenericArgs, NormalPath, Path}, hir::{ Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, InlineAsm, Label, @@ -466,7 +466,7 @@ impl ExpressionStore { ExpressionStore::EMPTY } - pub fn of(db: &dyn DefDatabase, def: ExpressionStoreOwnerId) -> &ExpressionStore { + pub fn of(db: &dyn SourceDatabase, def: ExpressionStoreOwnerId) -> &ExpressionStore { match def { ExpressionStoreOwnerId::Signature(def) => { use crate::signatures::{ @@ -494,7 +494,7 @@ impl ExpressionStore { } pub fn with_source_map( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, def: ExpressionStoreOwnerId, ) -> (&ExpressionStore, &ExpressionStoreSourceMap) { match def { @@ -589,7 +589,7 @@ impl ExpressionStore { /// Returns an iterator over all block expressions in this store that define inner items. pub fn blocks<'a>( &'a self, - db: &'a dyn DefDatabase, + db: &'a dyn SourceDatabase, ) -> impl Iterator + 'a { self.expr_only .as_ref() diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs index 5b254c57110d9..74c86ca4e89d4 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs @@ -2,6 +2,7 @@ //! consts. use std::ops; +use base_db::SourceDatabase; use hir_expand::{InFile, Lookup}; use span::Edition; use syntax::ast; @@ -9,7 +10,6 @@ use triomphe::Arc; use crate::{ DefWithBodyId, ExpressionStoreOwnerId, HasModule, - db::DefDatabase, expr_store::{ ExpressionStore, ExpressionStoreSourceMap, SelfParamPtr, lower::lower_body, pretty, }, @@ -87,7 +87,10 @@ impl ops::Deref for BodySourceMap { #[salsa::tracked] impl Body { #[salsa::tracked(lru = 512, returns(ref))] - pub fn with_source_map(db: &dyn DefDatabase, def: DefWithBodyId) -> (Arc, BodySourceMap) { + pub fn with_source_map( + db: &dyn SourceDatabase, + def: DefWithBodyId, + ) -> (Arc, BodySourceMap) { let _p = tracing::info_span!("body_with_source_map_query").entered(); let mut params = None; @@ -128,7 +131,7 @@ impl Body { } #[salsa::tracked(returns(deref))] - pub fn of(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc { + pub fn of(db: &dyn SourceDatabase, def: DefWithBodyId) -> Arc { Self::with_source_map(db, def).0.clone() } } @@ -150,7 +153,7 @@ impl Body { pub fn pretty_print( &self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, owner: DefWithBodyId, edition: Edition, ) -> String { @@ -159,7 +162,7 @@ impl Body { pub fn pretty_print_expr( &self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, owner: DefWithBodyId, expr: ExprId, edition: Edition, @@ -169,7 +172,7 @@ impl Body { pub fn pretty_print_pat( &self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, owner: ExpressionStoreOwnerId, pat: PatId, oneline: bool, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs index c79a1db8472ba..c40f244cb9357 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs @@ -2,7 +2,7 @@ use std::mem; -use base_db::Crate; +use base_db::{Crate, SourceDatabase}; use cfg::CfgOptions; use drop_bomb::DropBomb; use hir_expand::{ @@ -15,8 +15,8 @@ use syntax::{AstNode, Parse, ast}; use tt::TextRange; use crate::{ - MacroId, UnresolvedMacro, attrs::AttrFlags, db::DefDatabase, expr_store::HygieneId, - macro_call_as_call_id, nameres::DefMap, + MacroId, UnresolvedMacro, attrs::AttrFlags, expr_store::HygieneId, macro_call_as_call_id, + nameres::DefMap, }; #[derive(Debug)] @@ -31,7 +31,7 @@ pub(super) struct Expander<'db> { impl<'db> Expander<'db> { pub(super) fn new( - db: &'db dyn DefDatabase, + db: &'db dyn SourceDatabase, current_file_id: HirFileId, def_map: &'db DefMap, ) -> Expander<'db> { @@ -46,8 +46,8 @@ impl<'db> Expander<'db> { current_file_id, recursion_depth: 0, recursion_limit, - span_map: db.span_map(current_file_id), - ast_id_map: db.ast_id_map(current_file_id), + span_map: current_file_id.span_map(db), + ast_id_map: current_file_id.ast_id_map(db), } } @@ -55,7 +55,7 @@ impl<'db> Expander<'db> { self.span_map.span_for_range(range).ctx } - pub(super) fn hygiene_for_range(&self, db: &dyn DefDatabase, range: TextRange) -> HygieneId { + pub(super) fn hygiene_for_range(&self, db: &dyn SourceDatabase, range: TextRange) -> HygieneId { match self.span_map { SpanMap::ExpansionSpanMap(span_map) => { HygieneId::new(span_map.span_at(range.start()).ctx.opaque_and_semiopaque(db)) @@ -74,7 +74,7 @@ impl<'db> Expander<'db> { pub(super) fn enter_expand( &mut self, - db: &'db dyn DefDatabase, + db: &'db dyn SourceDatabase, macro_call: ast::MacroCall, krate: Crate, resolver: impl Fn(&ModPath) -> Option, @@ -111,7 +111,7 @@ impl<'db> Expander<'db> { call_site.ctx, expands_to, krate, - |path| resolver(path).map(|it| db.macro_def(it)), + |path| resolver(path).map(|it| it.definition(db)), eager_callback, ) { Ok(call_id) => call_id, @@ -127,7 +127,7 @@ impl<'db> Expander<'db> { pub(super) fn enter_expand_id( &mut self, - db: &'db dyn DefDatabase, + db: &'db dyn SourceDatabase, call_id: MacroCallId, ) -> ExpandResult, Option>)>> { self.within_limit(db, |_this| ExpandResult::ok(Some(call_id))) @@ -159,7 +159,7 @@ impl<'db> Expander<'db> { fn within_limit( &mut self, - db: &'db dyn DefDatabase, + db: &'db dyn SourceDatabase, op: F, ) -> ExpandResult, Option>)>> where @@ -184,12 +184,12 @@ impl<'db> Expander<'db> { self.recursion_depth = u32::MAX; cov_mark::hit!(your_stack_belongs_to_me); return ExpandResult::only_err(ExpandError::new( - db.macro_arg_considering_derives(call_id, &call_id.lookup(db).kind).2, + call_id.macro_arg_considering_derives(db, &call_id.lookup(db).kind).2, ExpandErrorKind::RecursionOverflow, )); } - let res = db.parse_macro_expansion(call_id); + let res = call_id.parse_macro_expansion(db); let err = err.or_else(|| res.err.clone()); ExpandResult { @@ -201,7 +201,7 @@ impl<'db> Expander<'db> { let old_span_map = std::mem::replace(&mut self.span_map, SpanMap::ExpansionSpanMap(&res.value.1)); let prev_ast_id_map = - mem::replace(&mut self.ast_id_map, db.ast_id_map(self.current_file_id)); + mem::replace(&mut self.ast_id_map, self.current_file_id.ast_id_map(db)); let mark = Mark { file_id: old_file_id, span_map: old_span_map, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs index f2523390cde27..0a1c23c2cc361 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs @@ -8,7 +8,7 @@ mod path; use std::{cell::OnceCell, mem}; -use base_db::FxIndexSet; +use base_db::{FxIndexSet, SourceDatabase}; use cfg::CfgOptions; use either::Either; use hir_expand::{ @@ -38,7 +38,6 @@ use crate::{ AdtId, BlockId, BlockLoc, ConstId, DefWithBodyId, FunctionId, GenericDefId, ImplId, ItemContainerId, MacroId, ModuleDefId, ModuleId, TraitId, TypeAliasId, UnresolvedMacro, attrs::AttrFlags, - db::DefDatabase, expr_store::{ Body, BodySourceMap, ExprPtr, ExprRoot, ExpressionStore, ExpressionStoreBuilder, ExpressionStoreDiagnostics, ExpressionStoreSourceMap, HygieneId, LabelPtr, LifetimePtr, @@ -68,7 +67,7 @@ use crate::{ pub use self::path::hir_segment_to_ast_segment; pub(super) fn lower_body( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, owner: DefWithBodyId, current_file_id: HirFileId, module: ModuleId, @@ -200,7 +199,7 @@ pub(super) fn lower_body( } pub(crate) fn lower_type_ref( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, module: ModuleId, type_ref: InFile>, ) -> (ExpressionStore, ExpressionStoreSourceMap, TypeRefId) { @@ -212,7 +211,7 @@ pub(crate) fn lower_type_ref( } pub fn lower_generic_params( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, module: ModuleId, def: GenericDefId, file_id: HirFileId, @@ -228,7 +227,7 @@ pub fn lower_generic_params( } pub(crate) fn lower_impl( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, module: ModuleId, impl_syntax: InFile, impl_id: ImplId, @@ -256,7 +255,7 @@ pub(crate) fn lower_impl( } pub(crate) fn lower_trait( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, module: ModuleId, trait_syntax: InFile, trait_id: TraitId, @@ -278,7 +277,7 @@ pub(crate) fn lower_trait( } pub(crate) fn lower_type_alias( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, module: ModuleId, alias: InFile, type_alias_id: TypeAliasId, @@ -313,7 +312,7 @@ pub(crate) fn lower_type_alias( } pub(crate) fn lower_function( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, module: ModuleId, fn_: InFile, function_id: FunctionId, @@ -438,7 +437,7 @@ pub(crate) fn lower_function( } pub struct ExprCollector<'db> { - db: &'db dyn DefDatabase, + db: &'db dyn SourceDatabase, cfg_options: &'db CfgOptions, expander: Expander<'db>, def_map: &'db DefMap, @@ -554,7 +553,7 @@ impl BindingList { impl<'db> ExprCollector<'db> { pub fn new( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, module: ModuleId, current_file_id: HirFileId, ) -> ExprCollector<'_> { @@ -2432,7 +2431,7 @@ impl<'db> ExprCollector<'db> { expansion.statements().for_each(|stmt| this.collect_stmt(statements, stmt)); expansion.expr().and_then(|expr| match expr { ast::Expr::MacroExpr(mac) => this.collect_macro_as_stmt(statements, mac), - expr => Some(this.collect_expr(expr)), + expr => this.maybe_collect_expr(expr), }) } None => None, @@ -2469,8 +2468,7 @@ impl<'db> ExprCollector<'db> { if let Some(expr) = self.collect_macro_as_stmt(statements, mac) { statements.push(Statement::Expr { expr, has_semi }) } - } else { - let expr = self.collect_expr_opt(expr); + } else if let Some(expr) = expr.and_then(|expr| self.maybe_collect_expr(expr)) { statements.push(Statement::Expr { expr, has_semi }); } } @@ -2516,7 +2514,7 @@ impl<'db> ExprCollector<'db> { statements.push(Statement::Item(Item::Other)); return; }; - let macro_id = self.db.macro_def(macro_id); + let macro_id = macro_id.definition(self.db); statements.push(Statement::Item(Item::MacroDef(Box::new(macro_id)))); self.label_ribs.push(LabelRib::new(RibKind::MacroDef(Box::new(macro_id)))); } @@ -2732,7 +2730,7 @@ impl<'db> ExprCollector<'db> { pats.push(self.collect_pat(first, binding_list)); binding_list.reject_new = true; for rest in it { - for (_, it) in binding_list.is_used.iter_mut() { + for it in binding_list.is_used.values_mut() { *it = false; } pats.push(self.collect_pat(rest, binding_list)); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs index 24ad23dbac0a2..0058ddc1e4a44 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs @@ -54,9 +54,9 @@ pub enum LineFormat { Indentation, } -fn item_name(db: &dyn DefDatabase, id: Id, default: &str) -> String +fn item_name(db: &dyn SourceDatabase, id: Id, default: &str) -> String where - Id: Lookup, + Id: Lookup, Loc: HasSource, Loc::Value: ast::HasName, { @@ -66,7 +66,7 @@ where } pub fn print_body_hir( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, body: &Body, owner: DefWithBodyId, edition: Edition, @@ -114,7 +114,11 @@ pub fn print_body_hir( p.buf } -pub fn print_variant_body_hir(db: &dyn DefDatabase, owner: VariantId, edition: Edition) -> String { +pub fn print_variant_body_hir( + db: &dyn SourceDatabase, + owner: VariantId, + edition: Edition, +) -> String { let header = match owner { VariantId::StructId(it) => format!("struct {}", item_name(db, it, "")), VariantId::EnumVariantId(it) => format!( @@ -166,7 +170,7 @@ pub fn print_variant_body_hir(db: &dyn DefDatabase, owner: VariantId, edition: E p.buf } -pub fn print_signature(db: &dyn DefDatabase, owner: GenericDefId, edition: Edition) -> String { +pub fn print_signature(db: &dyn SourceDatabase, owner: GenericDefId, edition: Edition) -> String { match owner { GenericDefId::AdtId(id) => match id { AdtId::StructId(id) => { @@ -193,7 +197,7 @@ pub fn print_signature(db: &dyn DefDatabase, owner: GenericDefId, edition: Editi } pub fn print_path( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, store: &ExpressionStore, path: &Path, edition: Edition, @@ -211,7 +215,7 @@ pub fn print_path( } pub fn print_struct( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, id: StructId, StructSignature { name, generic_params, store, flags, shape }: &StructSignature, edition: Edition, @@ -259,7 +263,7 @@ pub fn print_struct( } pub fn print_function( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, id: FunctionId, signature @ FunctionSignature { name, @@ -321,7 +325,11 @@ pub fn print_function( p.buf } -fn print_where_clauses(db: &dyn DefDatabase, generic_params: &GenericParams, p: &mut Printer<'_>) { +fn print_where_clauses( + db: &dyn SourceDatabase, + generic_params: &GenericParams, + p: &mut Printer<'_>, +) { if !generic_params.where_predicates.is_empty() { w!(p, "\nwhere\n"); p.indented(|p| { @@ -360,7 +368,11 @@ fn print_where_clauses(db: &dyn DefDatabase, generic_params: &GenericParams, p: } } -fn print_generic_params(db: &dyn DefDatabase, generic_params: &GenericParams, p: &mut Printer<'_>) { +fn print_generic_params( + db: &dyn SourceDatabase, + generic_params: &GenericParams, + p: &mut Printer<'_>, +) { if !generic_params.is_empty() { w!(p, "<"); let mut first = true; @@ -400,7 +412,7 @@ fn print_generic_params(db: &dyn DefDatabase, generic_params: &GenericParams, p: } pub fn print_expr_hir( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, store: &ExpressionStore, _owner: ExpressionStoreOwnerId, expr: ExprId, @@ -419,7 +431,7 @@ pub fn print_expr_hir( } pub fn print_pat_hir( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, store: &ExpressionStore, _owner: ExpressionStoreOwnerId, pat: PatId, @@ -439,7 +451,7 @@ pub fn print_pat_hir( } struct Printer<'a> { - db: &'a dyn DefDatabase, + db: &'a dyn SourceDatabase, store: &'a ExpressionStore, buf: String, indent_level: usize, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs index 40f67fd266ec3..c881a961b14b5 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs @@ -1,10 +1,10 @@ //! Name resolution for expressions. +use base_db::SourceDatabase; use hir_expand::{MacroDefId, name::Name}; use la_arena::{Arena, ArenaMap, Idx, IdxRange, RawIdx}; use crate::{ BlockId, DefWithBodyId, ExpressionStoreOwnerId, GenericDefId, VariantId, - db::DefDatabase, expr_store::{Body, ExpressionStore, HygieneId, body::Param}, hir::{ Array, Binding, BindingId, Expr, ExprId, Item, LabelId, Pat, PatId, Statement, @@ -56,7 +56,7 @@ pub struct ScopeData { #[salsa::tracked] impl ExprScopes { #[salsa::tracked(returns(ref))] - pub fn body_expr_scopes(db: &dyn DefDatabase, def: DefWithBodyId) -> ExprScopes { + pub fn body_expr_scopes(db: &dyn SourceDatabase, def: DefWithBodyId) -> ExprScopes { let body = Body::of(db, def); let mut scopes = ExprScopes::new_body(body); scopes.shrink_to_fit(); @@ -64,7 +64,7 @@ impl ExprScopes { } #[salsa::tracked(returns(ref))] - pub fn sig_expr_scopes(db: &dyn DefDatabase, def: GenericDefId) -> ExprScopes { + pub fn sig_expr_scopes(db: &dyn SourceDatabase, def: GenericDefId) -> ExprScopes { let (_, store) = GenericParams::with_store(db, def); let roots = store.expr_roots(); let mut scopes = ExprScopes::new_store(store, roots); @@ -73,7 +73,7 @@ impl ExprScopes { } #[salsa::tracked(returns(ref))] - pub fn variant_scopes(db: &dyn DefDatabase, def: VariantId) -> ExprScopes { + pub fn variant_scopes(db: &dyn SourceDatabase, def: VariantId) -> ExprScopes { let fields = VariantFields::of(db, def); let roots = fields.store.expr_roots(); let mut scopes = ExprScopes::new_store(&fields.store, roots); @@ -84,7 +84,7 @@ impl ExprScopes { impl ExprScopes { #[inline] - pub fn of(db: &dyn DefDatabase, def: impl Into) -> &ExprScopes { + pub fn of(db: &dyn SourceDatabase, def: impl Into) -> &ExprScopes { match def.into() { ExpressionStoreOwnerId::Body(def) => Self::body_expr_scopes(db, def), ExpressionStoreOwnerId::Signature(def) => Self::sig_expr_scopes(db, def), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs index 21bb6698af772..c7b9edf3939fa 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs @@ -706,6 +706,51 @@ fn foo() -> i64 { } #[cfg(false)] foo!() +} + "#, + expect![[r#" + fn foo() { + { + 5 + } + }"#]], + ); + pretty_print( + r#" +fn foo() -> i64 { + #[cfg(true)] + { + 5 + } + #[cfg(false)] + { + 4 + } + #[cfg(false)] + { + 3 + } +} + "#, + expect![[r#" + fn foo() { + { + 5 + } + }"#]], + ); + pretty_print( + r#" +macro_rules! m { + () => { + { 5 } + #[cfg(false)] + { 4 } + }; +} + +fn foo() -> i64 { + m!() } "#, expect![[r#" diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs index 6aaf8a674eee9..82ddaff189975 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs @@ -2,7 +2,7 @@ use std::{cell::Cell, cmp::Ordering, iter}; -use base_db::{Crate, CrateOrigin, LangCrateOrigin}; +use base_db::{Crate, CrateOrigin, LangCrateOrigin, SourceDatabase}; use hir_expand::{ Lookup, mod_path::{ModPath, PathKind}, @@ -12,18 +12,31 @@ use intern::sym; use rustc_hash::FxHashSet; use crate::{ - FindPathConfig, ModuleDefId, ModuleId, - db::DefDatabase, + ModuleDefId, ModuleId, import_map::ImportMap, item_scope::ItemInNs, nameres::DefMap, visibility::{Visibility, VisibilityExplicitness}, }; +#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)] +pub struct FindPathConfig { + /// If true, prefer to unconditionally use imports of the `core` and `alloc` crate + /// over the std. + pub prefer_no_std: bool, + /// If true, prefer import paths containing a prelude module. + pub prefer_prelude: bool, + /// If true, prefer abs path (starting with `::`) where it is available. + pub prefer_absolute: bool, + /// If true, paths containing `#[unstable]` segments may be returned, but only if if there is no + /// stable path. This does not check, whether the item itself that is being imported is `#[unstable]`. + pub allow_unstable: bool, +} + /// Find a path that can be used to refer to a certain item. This can depend on /// *from where* you're referring to the item, hence the `from` parameter. pub fn find_path( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, item: ItemInNs, from: ModuleId, mut prefix_kind: PrefixKind, @@ -43,9 +56,11 @@ pub fn find_path( if item_module.block(db).is_some() { prefix_kind = PrefixKind::Plain; } - cfg.prefer_no_std = cfg.prefer_no_std || db.crate_supports_no_std(from.krate(db)); let from_def_map = from.def_map(db); + + cfg.prefer_no_std = cfg.prefer_no_std || from_def_map.is_no_std(); + find_path_inner( &FindPathCtx { db, @@ -98,7 +113,7 @@ impl PrefixKind { } struct FindPathCtx<'db> { - db: &'db dyn DefDatabase, + db: &'db dyn SourceDatabase, prefix: PrefixKind, cfg: FindPathConfig, ignore_local_imports: bool, @@ -252,7 +267,7 @@ fn find_path_for_module( } fn find_in_scope( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, def_map: &DefMap, from: ModuleId, item: ItemInNs, @@ -269,7 +284,7 @@ fn find_in_scope( /// Returns single-segment path (i.e. without any prefix) if `item` is found in prelude and its /// name doesn't clash in current scope. fn find_in_prelude( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, local_def_map: &DefMap, item: ItemInNs, from: ModuleId, @@ -302,7 +317,7 @@ fn find_in_prelude( } fn is_kw_kind_relative_to_from( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, def_map: &DefMap, item: ModuleId, from: ModuleId, @@ -641,8 +656,9 @@ fn find_local_import_locations( #[cfg(test)] mod tests { + use std::cell::LazyCell; + use expect_test::{Expect, expect}; - use hir_expand::db::ExpandDatabase; use itertools::Itertools; use span::Edition; use stdx::format_to; @@ -672,10 +688,10 @@ mod tests { syntax::SourceFile::parse(&format!("use {path};"), span::Edition::CURRENT); let ast_path = parsed_path_file.syntax_node().descendants().find_map(syntax::ast::Path::cast).unwrap(); - let mod_path = ModPath::from_src(&db, ast_path, &mut |range| { - db.span_map(pos.file_id.into()).span_for_range(range).ctx - }) - .unwrap(); + let span_map = LazyCell::new(|| hir_expand::HirFileId::from(pos.file_id).span_map(&db)); + let mod_path = + ModPath::from_src(&db, ast_path, &mut |range| span_map.span_for_range(range).ctx) + .unwrap(); let (def_map, local_def_map) = module.local_def_map(&db); let resolved = def_map diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs index 04ccc7bf90cf0..36ae821d748e3 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs @@ -1,6 +1,7 @@ //! Pre-type IR item generics use std::{ops, sync::LazyLock}; +use base_db::SourceDatabase; use hir_expand::name::Name; use la_arena::{Arena, Idx, RawIdx}; use stdx::impl_from; @@ -8,7 +9,6 @@ use thin_vec::ThinVec; use crate::{ AdtId, ConstParamId, GenericDefId, LifetimeParamId, TypeOrConstParamId, TypeParamId, - db::DefDatabase, expr_store::{ExpressionStore, ExpressionStoreSourceMap}, signatures::{ ConstSignature, EnumSignature, FunctionSignature, ImplSignature, StaticSignature, @@ -193,12 +193,12 @@ impl GenericParams { LazyLock::force(&EMPTY) } - pub fn of(db: &dyn DefDatabase, def: GenericDefId) -> &GenericParams { + pub fn of(db: &dyn SourceDatabase, def: GenericDefId) -> &GenericParams { Self::with_store(db, def).0 } pub fn with_store( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, def: GenericDefId, ) -> (&GenericParams, &ExpressionStore) { match def { @@ -242,7 +242,7 @@ impl GenericParams { } pub fn with_source_map( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, def: GenericDefId, ) -> (&GenericParams, &ExpressionStore, &ExpressionStoreSourceMap) { match def { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs index f8be211bf92a4..669b21c03a46f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs @@ -2,7 +2,7 @@ use std::fmt; -use base_db::Crate; +use base_db::{Crate, SourceDatabase}; use fst::{Automaton, Streamer, raw::IndexedValue}; use hir_expand::name::Name; use itertools::Itertools; @@ -14,7 +14,6 @@ use stdx::format_to; use crate::{ AdtId, AssocItemId, AttrDefId, Complete, EnumId, FxIndexMap, ModuleDefId, ModuleId, TraitId, attrs::AttrFlags, - db::DefDatabase, item_scope::{ImportOrExternCrate, ItemInNs}, nameres::{assoc::TraitItems, crate_def_map}, visibility::Visibility, @@ -65,13 +64,13 @@ type ImportMapIndex = FxIndexMap, IsTraitAs #[salsa::tracked] impl ImportMap { #[salsa::tracked(returns(ref))] - pub fn of(db: &dyn DefDatabase, krate: Crate) -> Self { + pub fn of(db: &dyn SourceDatabase, krate: Crate) -> Self { Self::import_map_query_impl(db, krate) } } impl ImportMap { - pub fn dump(&self, db: &dyn DefDatabase) -> String { + pub fn dump(&self, db: &dyn SourceDatabase) -> String { let mut out = String::new(); for (k, v) in self.item_to_info_map.iter() { format_to!(out, "{:?} ({:?}) -> ", k, v.1); @@ -83,7 +82,7 @@ impl ImportMap { out } - fn import_map_query_impl(db: &dyn DefDatabase, krate: Crate) -> Self { + fn import_map_query_impl(db: &dyn SourceDatabase, krate: Crate) -> Self { let _p = tracing::info_span!("import_map_query").entered(); let map = Self::collect_import_map(db, krate); @@ -134,7 +133,7 @@ impl ImportMap { self.item_to_info_map.get(&item).map(|(info, _)| &**info) } - fn collect_import_map(db: &dyn DefDatabase, krate: Crate) -> ImportMapIndex { + fn collect_import_map(db: &dyn SourceDatabase, krate: Crate) -> ImportMapIndex { let _p = tracing::info_span!("collect_import_map").entered(); let def_map = crate_def_map(db, krate); @@ -238,7 +237,7 @@ impl ImportMap { } fn collect_enum_variants( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, map: &mut ImportMapIndex, enum_: EnumId, enum_import_info: &ImportInfo, @@ -265,7 +264,7 @@ impl ImportMap { } fn collect_trait_assoc_items( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, map: &mut ImportMapIndex, tr: TraitId, is_type_in_ns: bool, @@ -454,7 +453,7 @@ impl Query { /// /// This returns a list of items that could be imported from dependencies of `krate`. pub fn search_dependencies( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, krate: Crate, query: &Query, ) -> FxHashSet<(ItemInNs, Complete)> { @@ -494,7 +493,7 @@ pub fn search_dependencies( } fn search_maps( - _db: &dyn DefDatabase, + _db: &dyn SourceDatabase, import_maps: &[&ImportMap], mut stream: fst::map::Union<'_>, query: &Query, @@ -538,7 +537,7 @@ mod tests { use super::*; impl ImportMap { - fn fmt_for_test(&self, db: &dyn DefDatabase) -> String { + fn fmt_for_test(&self, db: &dyn SourceDatabase) -> String { let mut importable_paths: Vec<_> = self .item_to_info_map .iter() @@ -614,7 +613,7 @@ mod tests { } fn assoc_item_path( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, dependency_imports: &ImportMap, dependency: ItemInNs, ) -> Option { @@ -665,7 +664,7 @@ mod tests { expect.assert_eq(&actual) } - fn render_path(db: &dyn DefDatabase, info: &ImportInfo) -> String { + fn render_path(db: &dyn SourceDatabase, info: &ImportInfo) -> String { let mut module = info.container; let mut segments = vec![&info.name]; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs index fe7d1806857b1..16283a2cb372b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs @@ -3,7 +3,7 @@ use std::{fmt, sync::LazyLock}; -use base_db::Crate; +use base_db::{Crate, SourceDatabase}; use either::Either; use hir_expand::{AstId, MacroCallId, attrs::AttrId, name::Name}; use indexmap::map::Entry; @@ -19,7 +19,6 @@ use thin_vec::ThinVec; use crate::{ AdtId, BuiltinDeriveImplId, BuiltinType, ConstId, ExternBlockId, ExternCrateId, FxIndexMap, HasModule, ImplId, Lookup, MacroCallStyles, MacroId, ModuleDefId, ModuleId, TraitId, UseId, - db::DefDatabase, per_ns::{Item, MacrosItem, PerNs, TypesItem, ValuesItem}, visibility::Visibility, }; @@ -260,7 +259,7 @@ impl ItemScope { .dedup() } - pub fn fully_resolve_import(&self, db: &dyn DefDatabase, mut import: ImportId) -> PerNs { + pub fn fully_resolve_import(&self, db: &dyn SourceDatabase, mut import: ImportId) -> PerNs { let mut res = PerNs::none(); let mut scope = self; @@ -761,7 +760,7 @@ impl ItemScope { } } - pub(crate) fn dump(&self, db: &dyn DefDatabase, buf: &mut String) { + pub(crate) fn dump(&self, db: &dyn SourceDatabase, buf: &mut String) { let mut entries: Vec<_> = self.resolutions().collect(); entries.sort_by_key(|(name, _)| name.clone()); @@ -967,11 +966,11 @@ impl ItemInNs { } /// Returns the crate defining this item (or `None` if `self` is built-in). - pub fn krate(&self, db: &dyn DefDatabase) -> Option { + pub fn krate(&self, db: &dyn SourceDatabase) -> Option { self.module(db).map(|module_id| module_id.krate(db)) } - pub fn module(&self, db: &dyn DefDatabase) -> Option { + pub fn module(&self, db: &dyn SourceDatabase) -> Option { match self { ItemInNs::Types(id) | ItemInNs::Values(id) => id.module(db), ItemInNs::Macros(id) => Some(id.module(db)), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs index 4b50161c04cd0..8be44b0828866 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs @@ -44,7 +44,7 @@ use std::{ }; use ast::{AstNode, StructKind}; -use base_db::Crate; +use base_db::{Crate, SourceDatabase}; use cfg::CfgOptions; use hir_expand::{ ExpandTo, HirFileId, @@ -63,7 +63,7 @@ use syntax::{SourceFile, SyntaxKind, ast, match_ast}; use thin_vec::ThinVec; use tt::TextRange; -use crate::{BlockId, Lookup, attrs::parse_extra_crate_attrs, db::DefDatabase}; +use crate::{BlockId, Lookup, attrs::parse_extra_crate_attrs}; pub(crate) use crate::item_tree::{ attrs::*, @@ -94,7 +94,7 @@ impl fmt::Debug for RawVisibilityId { } fn lower_extra_crate_attrs<'a>( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, crate_attrs_as_src: SourceFile, file_id: span::EditionedFileId, cfg_options: &dyn Fn() -> &'a CfgOptions, @@ -120,7 +120,8 @@ fn lower_extra_crate_attrs<'a>( AttrsOrCfg::lower(db, &crate_attrs_as_src, cfg_options, span_map) } -pub(crate) fn file_item_tree(db: &dyn DefDatabase, file_id: HirFileId, krate: Crate) -> &ItemTree { +/// Computes an [`ItemTree`] for the given file or macro expansion. +pub fn file_item_tree(db: &dyn SourceDatabase, file_id: HirFileId, krate: Crate) -> &ItemTree { match file_item_tree_query(db, file_id, krate) { Some(item_tree) => item_tree, None => { @@ -139,14 +140,14 @@ pub(crate) fn file_item_tree(db: &dyn DefDatabase, file_id: HirFileId, krate: Cr #[salsa_macros::tracked(returns(ref))] fn file_item_tree_query( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, file_id: HirFileId, krate: Crate, ) -> Option> { let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered(); let ctx = lower::Ctx::new(db, file_id, krate); - let syntax = db.parse_or_expand(file_id); + let syntax = file_id.parse_or_expand(db); let mut item_tree = match_ast! { match syntax { ast::SourceFile(file) => { @@ -198,7 +199,7 @@ fn file_item_tree_query( #[salsa_macros::tracked(returns(ref))] pub(crate) fn block_item_tree_query( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, block: BlockId, krate: Crate, ) -> ItemTree { @@ -266,7 +267,7 @@ impl ItemTree { ItemTreeDataStats { traits, impls, mods, macro_calls, macro_rules } } - pub fn pretty_print(&self, db: &dyn DefDatabase, edition: Edition) -> String { + pub fn pretty_print(&self, db: &dyn SourceDatabase, edition: Edition) -> String { pretty::print_item_tree(db, self, edition) } @@ -344,7 +345,11 @@ impl TreeId { Self { file, block } } - pub(crate) fn item_tree<'db>(&self, db: &'db dyn DefDatabase, krate: Crate) -> &'db ItemTree { + pub(crate) fn item_tree<'db>( + &self, + db: &'db dyn SourceDatabase, + krate: Crate, + ) -> &'db ItemTree { match self.block { Some(block) => block_item_tree_query(db, block, krate), None => file_item_tree(db, self.file, krate), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/attrs.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/attrs.rs index 867d813e3f2b9..9671cebb05b72 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/attrs.rs @@ -10,6 +10,7 @@ use std::{ ops::{self, ControlFlow}, }; +use base_db::SourceDatabase; use cfg::{CfgExpr, CfgOptions}; use either::Either; use hir_expand::{ @@ -22,7 +23,7 @@ use syntax::{AstNode, ast}; use syntax_bridge::DocCommentDesugarMode; use tt::token_to_literal; -use crate::{db::DefDatabase, item_tree::lower::Ctx}; +use crate::item_tree::lower::Ctx; #[derive(Debug, PartialEq, Eq)] pub(crate) enum AttrsOrCfg { @@ -42,7 +43,7 @@ impl Default for AttrsOrCfg { impl AttrsOrCfg { pub(crate) fn lower<'a, S>( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, owner: &dyn ast::HasAttrs, cfg_options: &dyn Fn() -> &'a CfgOptions, span_map: S, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs index 91c2e60fd7c4c..6f916c83ef17c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs @@ -2,7 +2,7 @@ use std::cell::OnceCell; -use base_db::{Crate, FxIndexSet}; +use base_db::{Crate, FxIndexSet, SourceDatabase}; use cfg::CfgOptions; use hir_expand::{HirFileId, mod_path::PathKind, name::AsName, span_map::SpanMap}; use la_arena::Arena; @@ -12,19 +12,15 @@ use syntax::{ ast::{self, HasModuleItem, HasName}, }; -use crate::{ - db::DefDatabase, - item_tree::{ - BigModItem, Const, Enum, ExternBlock, ExternCrate, FieldsShape, Function, Impl, - ImportAlias, Interned, ItemTree, ItemTreeAstId, Macro2, MacroCall, MacroRules, Mod, - ModItemId, ModKind, ModPath, RawVisibility, RawVisibilityId, SmallModItem, Static, Struct, - StructKind, Trait, TypeAlias, Union, Use, UseTree, UseTreeKind, VisibilityExplicitness, - attrs::AttrsOrCfg, - }, +use crate::item_tree::{ + BigModItem, Const, Enum, ExternBlock, ExternCrate, FieldsShape, Function, Impl, ImportAlias, + Interned, ItemTree, ItemTreeAstId, Macro2, MacroCall, MacroRules, Mod, ModItemId, ModKind, + ModPath, RawVisibility, RawVisibilityId, SmallModItem, Static, Struct, StructKind, Trait, + TypeAlias, Union, Use, UseTree, UseTreeKind, VisibilityExplicitness, attrs::AttrsOrCfg, }; pub(super) struct Ctx<'db> { - pub(super) db: &'db dyn DefDatabase, + pub(super) db: &'db dyn SourceDatabase, tree: ItemTree, source_ast_id_map: &'db AstIdMap, span_map: OnceCell>, @@ -36,11 +32,11 @@ pub(super) struct Ctx<'db> { } impl<'db> Ctx<'db> { - pub(super) fn new(db: &'db dyn DefDatabase, file: HirFileId, krate: Crate) -> Self { + pub(super) fn new(db: &'db dyn SourceDatabase, file: HirFileId, krate: Crate) -> Self { Self { db, tree: ItemTree::default(), - source_ast_id_map: db.ast_id_map(file), + source_ast_id_map: file.ast_id_map(db), file, cfg_options: OnceCell::new(), span_map: OnceCell::new(), @@ -56,7 +52,7 @@ impl<'db> Ctx<'db> { } pub(super) fn span_map(&self) -> SpanMap<'_> { - *self.span_map.get_or_init(|| self.db.span_map(self.file)) + *self.span_map.get_or_init(|| self.file.span_map(self.db)) } pub(super) fn lower_module_items(mut self, item_owner: &dyn HasModuleItem) -> ItemTree { @@ -382,7 +378,7 @@ impl<'db> Ctx<'db> { } struct UseTreeLowering<'a> { - db: &'a dyn DefDatabase, + db: &'a dyn SourceDatabase, mapping: Arena, } @@ -401,7 +397,10 @@ impl UseTreeLowering<'_> { Some(path) => { match ModPath::from_src(self.db, path, span_for_range) { Some(it) => Some(it), - None => return None, // FIXME: report errors somewhere + None => { + // FIXME: report errors somewhere + return None; + } } } }; @@ -450,7 +449,7 @@ impl UseTreeLowering<'_> { } pub(crate) fn lower_use_tree( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, tree: ast::UseTree, span_for_range: &mut dyn FnMut(::tt::TextRange) -> SyntaxContext, ) -> Option<(UseTree, Arena)> { @@ -464,7 +463,7 @@ fn private_vis() -> RawVisibility { } pub(crate) fn visibility_from_ast( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, node: Option, span_for_range: &mut dyn FnMut(::tt::TextRange) -> SyntaxContext, ) -> RawVisibility { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs index 4113a778eaafd..fc624683cabc9 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs @@ -6,14 +6,18 @@ use span::{Edition, ErasedFileAstId}; use crate::{ item_tree::{ - Const, DefDatabase, Enum, ExternBlock, ExternCrate, FieldsShape, Function, Impl, ItemTree, - Macro2, MacroCall, MacroRules, Mod, ModItemId, ModKind, RawVisibilityId, Static, Struct, - Trait, TypeAlias, Union, Use, UseTree, UseTreeKind, attrs::AttrsOrCfg, + Const, Enum, ExternBlock, ExternCrate, FieldsShape, Function, Impl, ItemTree, Macro2, + MacroCall, MacroRules, Mod, ModItemId, ModKind, RawVisibilityId, SourceDatabase, Static, + Struct, Trait, TypeAlias, Union, Use, UseTree, UseTreeKind, attrs::AttrsOrCfg, }, visibility::RawVisibility, }; -pub(super) fn print_item_tree(db: &dyn DefDatabase, tree: &ItemTree, edition: Edition) -> String { +pub(super) fn print_item_tree( + db: &dyn SourceDatabase, + tree: &ItemTree, + edition: Edition, +) -> String { let mut p = Printer { db, tree, buf: String::new(), indent_level: 0, needs_indent: true, edition }; @@ -45,7 +49,7 @@ macro_rules! wln { } struct Printer<'a> { - db: &'a dyn DefDatabase, + db: &'a dyn SourceDatabase, tree: &'a ItemTree, buf: String, indent_level: usize, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs index b71b25a1a51d4..b863a0d969fa7 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs @@ -2,11 +2,11 @@ use expect_test::{Expect, expect}; use span::Edition; use test_fixture::WithFixture; -use crate::{db::DefDatabase, test_db::TestDB}; +use crate::test_db::TestDB; fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (db, file_id) = TestDB::with_single_file(ra_fixture); - let item_tree = db.file_item_tree(file_id.into(), db.test_crate()); + let item_tree = crate::file_item_tree(&db, file_id.into(), db.test_crate()); let pretty = item_tree.pretty_print(&db, Edition::CURRENT); expect.assert_eq(&pretty); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index 04dfdb7d16276..14e559200f01c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -2,6 +2,7 @@ //! //! This attribute to tell the compiler about semi built-in std library //! features, such as Fn family of traits. +use base_db::SourceDatabase; use hir_expand::name::Name; use intern::{Symbol, sym}; use stdx::impl_from; @@ -10,7 +11,6 @@ use crate::{ AdtId, AssocItemId, AttrDefId, ConstId, Crate, EnumId, EnumVariantId, FunctionId, ImplId, ItemContainerId, MacroId, ModuleDefId, StaticId, StructId, TraitId, TypeAliasId, UnionId, attrs::AttrFlags, - db::DefDatabase, nameres::{DefMap, assoc::TraitItems, crate_def_map, crate_local_def_map}, }; @@ -35,7 +35,7 @@ impl_from!( /// Salsa query. This will look for lang items in a specific crate. #[salsa_macros::tracked(returns(as_deref))] -pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option> { +pub fn crate_lang_items(db: &dyn SourceDatabase, krate: Crate) -> Option> { let _p = tracing::info_span!("crate_lang_items_query").entered(); let mut lang_items = LangItems::default(); @@ -113,7 +113,7 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option LangItems { +pub fn lang_items(db: &dyn SourceDatabase, start_crate: Crate) -> LangItems { let _p = tracing::info_span!("lang_items_query").entered(); let mut result = crate_lang_items(db, start_crate).cloned().unwrap_or_default(); @@ -138,7 +138,7 @@ pub fn lang_items(db: &dyn DefDatabase, start_crate: Crate) -> LangItems { } impl LangItems { - fn collect_lang_item(&mut self, db: &dyn DefDatabase, item: T) + fn collect_lang_item(&mut self, db: &dyn SourceDatabase, item: T) where T: Into + Into + Copy, { @@ -150,7 +150,7 @@ impl LangItems { } fn resolve_core_trait( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, core_def_map: &DefMap, modules: &[Symbol], name: Symbol, @@ -175,7 +175,7 @@ fn resolve_core_trait( } fn resolve_core_macro( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, core_def_map: &DefMap, modules: &[Symbol], name: Symbol, @@ -196,7 +196,7 @@ fn resolve_core_macro( } impl LangItems { - fn resolve_manually(&mut self, db: &dyn DefDatabase) { + fn resolve_manually(&mut self, db: &dyn SourceDatabase) { let parent_trait = |lang_item: &mut Option, def: Option| match def?.loc(db).container { @@ -318,7 +318,7 @@ impl LangItems { } #[salsa::tracked(returns(as_deref))] -pub(crate) fn crate_notable_traits(db: &dyn DefDatabase, krate: Crate) -> Option> { +pub fn crate_notable_traits(db: &dyn SourceDatabase, krate: Crate) -> Option> { let mut traits = Vec::new(); let crate_def_map = crate_def_map(db, krate); @@ -397,7 +397,7 @@ macro_rules! language_item_table { } } - fn fill_non_lang_core_items(&mut self, db: &dyn DefDatabase, core_def_map: &DefMap) { + fn fill_non_lang_core_items(&mut self, db: &dyn SourceDatabase, core_def_map: &DefMap) { $( self.$non_lang_trait = resolve_core_trait(db, core_def_map, &[ $(sym::$non_lang_trait_module),* ], sym::$non_lang_trait); )* $( self.$non_lang_macro_field = resolve_core_macro(db, core_def_map, &[ $(sym::$non_lang_macro_module),* ], sym::$non_lang_macro); )* } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index 2172e2412b89e..fa7cb525bbcd8 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -18,8 +18,6 @@ extern crate ra_ap_rustc_parse_format as rustc_parse_format; pub extern crate ra_ap_rustc_abi as layout; pub extern crate ra_ap_rustc_abi as rustc_abi; -pub mod db; - pub mod attrs; pub mod builtin_type; pub mod item_scope; @@ -35,9 +33,8 @@ pub mod builtin_derive; pub mod lang_item; pub mod unstable_features; -pub mod hir; -pub use self::hir::type_ref; pub mod expr_store; +pub mod hir; pub mod resolver; pub mod nameres; @@ -48,12 +45,6 @@ pub mod find_path; pub mod import_map; pub mod visibility; -use intern::{Interned, sym}; -use rustc_abi::ExternAbi; -use thin_vec::ThinVec; - -pub use crate::signatures::LocalFieldId; - #[cfg(test)] mod macro_expansion_tests; #[cfg(test)] @@ -61,31 +52,31 @@ mod test_db; use std::hash::{Hash, Hasher}; -use base_db::{Crate, impl_intern_key}; +use base_db::{Crate, SourceDatabase, impl_intern_key}; use hir_expand::{ - AstId, ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroCallStyles, - MacroDefId, MacroDefKind, + AstId, EditionedFileId, ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, + MacroCallStyles, MacroDefId, MacroDefKind, attrs::AttrId, builtin::{BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerExpander}, - db::ExpandDatabase, eager::expand_eager_macro_input, impl_intern_lookup, mod_path::ModPath, name::Name, proc_macro::{CustomProcMacroExpander, ProcMacroKind}, }; +use intern::{Interned, sym}; use nameres::DefMap; +use rustc_abi::ExternAbi; +use salsa::{Durability, Setter}; use span::{AstIdNode, Edition, FileAstId, SyntaxContext}; use stdx::impl_from; use syntax::{AstNode, ast}; - -pub use hir_expand::{Intern, Lookup, tt}; +use thin_vec::ThinVec; use crate::{ attrs::AttrFlags, builtin_derive::BuiltinDeriveImplTrait, builtin_type::BuiltinType, - db::DefDatabase, expr_store::ExpressionStoreSourceMap, hir::generics::{GenericParams, LocalLifetimeParamId, LocalTypeOrConstParamId}, nameres::{ @@ -97,20 +88,32 @@ use crate::{ signatures::{EnumVariants, InactiveEnumVariantCode, VariantFields}, }; +pub use crate::{ + find_path::FindPathConfig, hir::type_ref, item_tree::file_item_tree, + lang_item::crate_notable_traits, signatures::LocalFieldId, +}; +pub use hir_expand::{Intern, Lookup, tt}; + type FxIndexMap = indexmap::IndexMap; -/// A wrapper around three booleans -#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)] -pub struct FindPathConfig { - /// If true, prefer to unconditionally use imports of the `core` and `alloc` crate - /// over the std. - pub prefer_no_std: bool, - /// If true, prefer import paths containing a prelude module. - pub prefer_prelude: bool, - /// If true, prefer abs path (starting with `::`) where it is available. - pub prefer_absolute: bool, - /// If true, paths containing `#[unstable]` segments may be returned, but only if if there is no - /// stable path. This does not check, whether the item itself that is being imported is `#[unstable]`. - pub allow_unstable: bool, + +/// Whether to expand procedural macros during name resolution. +/// +/// Note: this struct shouldn't be exposed to ide crates -- consider using +/// [`set_expand_proc_attr_macros`] instead, if possible. +#[salsa::input(singleton, debug)] +pub(crate) struct ExpandProcAttrMacros { + #[returns(copy)] + pub(crate) enabled: bool, +} + +pub fn set_expand_proc_attr_macros(db: &mut dyn SourceDatabase, enabled: bool) { + if let Some(expand_proc_attr_macros) = ExpandProcAttrMacros::try_get(db) { + if expand_proc_attr_macros.enabled(db) != enabled { + expand_proc_attr_macros.set_enabled(db).with_durability(Durability::HIGH).to(enabled); + } + } else { + _ = ExpandProcAttrMacros::builder(enabled).durability(Durability::HIGH).new(db); + } } #[derive(Debug)] @@ -144,7 +147,7 @@ impl Hash for ItemLoc { impl HasModule for ItemLoc { #[inline] - fn module(&self, _db: &dyn DefDatabase) -> ModuleId { + fn module(&self, _db: &dyn SourceDatabase) -> ModuleId { self.container } } @@ -181,7 +184,7 @@ impl Hash for AssocItemLoc { impl HasModule for AssocItemLoc { #[inline] - fn module(&self, db: &dyn DefDatabase) -> ModuleId { + fn module(&self, db: &dyn SourceDatabase) -> ModuleId { self.container.module(db) } } @@ -222,7 +225,7 @@ impl AstIdLoc for AssocItemLoc { macro_rules! impl_intern { ($id:ident, $loc:ident) => { impl_intern_key!($id, $loc); - impl_intern_lookup!(DefDatabase, $id, $loc); + impl_intern_lookup!($id, $loc); }; } @@ -241,7 +244,7 @@ macro_rules! impl_loc { impl HasModule for $loc { #[inline] - fn module(&self, db: &dyn DefDatabase) -> ModuleId { + fn module(&self, db: &dyn SourceDatabase) -> ModuleId { self.$container.module(db) } } @@ -255,13 +258,13 @@ type StructLoc = ItemLoc; impl_intern!(StructId, StructLoc); impl StructId { - pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields { + pub fn fields(self, db: &dyn SourceDatabase) -> &VariantFields { VariantFields::of(db, self.into()) } pub fn fields_with_source_map( self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, ) -> (&VariantFields, &ExpressionStoreSourceMap) { let r = VariantFields::with_source_map(db, self.into()); (&r.0, &r.1) @@ -272,13 +275,13 @@ pub type UnionLoc = ItemLoc; impl_intern!(UnionId, UnionLoc); impl UnionId { - pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields { + pub fn fields(self, db: &dyn SourceDatabase) -> &VariantFields { VariantFields::of(db, self.into()) } pub fn fields_with_source_map( self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, ) -> (&VariantFields, &ExpressionStoreSourceMap) { let r = VariantFields::with_source_map(db, self.into()); (&r.0, &r.1) @@ -290,14 +293,14 @@ impl_intern!(EnumId, EnumLoc); impl EnumId { #[inline] - pub fn enum_variants(self, db: &dyn DefDatabase) -> &EnumVariants { + pub fn enum_variants(self, db: &dyn SourceDatabase) -> &EnumVariants { &self.enum_variants_with_diagnostics(db).0 } #[inline] pub fn enum_variants_with_diagnostics( self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, ) -> &(EnumVariants, ThinVec) { EnumVariants::of(db, self) } @@ -314,7 +317,7 @@ impl_intern!(TraitId, TraitLoc); impl TraitId { #[inline] - pub fn trait_items(self, db: &dyn DefDatabase) -> &TraitItems { + pub fn trait_items(self, db: &dyn SourceDatabase) -> &TraitItems { TraitItems::query(db, self) } } @@ -327,12 +330,15 @@ impl_intern!(ImplId, ImplLoc); impl ImplId { #[inline] - pub fn impl_items(self, db: &dyn DefDatabase) -> &ImplItems { + pub fn impl_items(self, db: &dyn SourceDatabase) -> &ImplItems { &self.impl_items_with_diagnostics(db).0 } #[inline] - pub fn impl_items_with_diagnostics(self, db: &dyn DefDatabase) -> &(ImplItems, DefDiagnostics) { + pub fn impl_items_with_diagnostics( + self, + db: &dyn SourceDatabase, + ) -> &(ImplItems, DefDiagnostics) { ImplItems::of(db, self) } } @@ -362,7 +368,7 @@ type ExternBlockLoc = ItemLoc; impl_intern!(ExternBlockId, ExternBlockLoc); impl ExternBlockId { - pub fn abi(self, db: &dyn DefDatabase) -> ExternAbi { + pub fn abi(self, db: &dyn SourceDatabase) -> ExternAbi { signatures::extern_block_abi(db, self) } } @@ -377,7 +383,7 @@ impl_intern!(EnumVariantId, EnumVariantLoc); impl_loc!(EnumVariantLoc, id: Variant, parent: EnumId); impl EnumVariantLoc { - pub fn index(&self, db: &dyn DefDatabase) -> usize { + pub fn index(&self, db: &dyn SourceDatabase) -> usize { self.parent .enum_variants(db) .variants @@ -388,17 +394,17 @@ impl EnumVariantLoc { } impl EnumVariantId { - pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields { + pub fn fields(self, db: &dyn SourceDatabase) -> &VariantFields { VariantFields::of(db, self.into()) } - pub fn index(self, db: &dyn DefDatabase) -> usize { + pub fn index(self, db: &dyn SourceDatabase) -> usize { self.loc(db).index(db) } pub fn fields_with_source_map( self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, ) -> (&VariantFields, &ExpressionStoreSourceMap) { let r = VariantFields::with_source_map(db, self.into()); (&r.0, &r.1) @@ -493,18 +499,18 @@ impl ModuleId { /// # Safety /// /// The caller must ensure that the `ModuleId` comes from the given database. - pub unsafe fn to_db<'db>(self, _db: &'db dyn DefDatabase) -> ModuleIdLt<'db> { + pub unsafe fn to_db<'db>(self, _db: &'db dyn SourceDatabase) -> ModuleIdLt<'db> { unsafe { std::mem::transmute(self) } } - pub fn def_map(self, db: &dyn DefDatabase) -> &DefMap { + pub fn def_map(self, db: &dyn SourceDatabase) -> &DefMap { match self.block(db) { Some(block) => block_def_map(db, block), None => crate_def_map(db, self.krate(db)), } } - pub(crate) fn local_def_map(self, db: &dyn DefDatabase) -> (&DefMap, &LocalDefMap) { + pub(crate) fn local_def_map(self, db: &dyn SourceDatabase) -> (&DefMap, &LocalDefMap) { match self.block(db) { Some(block) => (block_def_map(db, block), self.only_local_def_map(db)), None => { @@ -514,22 +520,22 @@ impl ModuleId { } } - pub(crate) fn only_local_def_map(self, db: &dyn DefDatabase) -> &LocalDefMap { + pub(crate) fn only_local_def_map(self, db: &dyn SourceDatabase) -> &LocalDefMap { crate_local_def_map(db, self.krate(db)).local(db) } - pub fn crate_def_map(self, db: &dyn DefDatabase) -> &DefMap { + pub fn crate_def_map(self, db: &dyn SourceDatabase) -> &DefMap { crate_def_map(db, self.krate(db)) } - pub fn name(self, db: &dyn DefDatabase) -> Option { + pub fn name(self, db: &dyn SourceDatabase) -> Option { let name = self.name_or_empty(db); if *name.symbol() == sym::__empty { None } else { Some(name) } } /// Returns the module containing `self`, either the parent `mod`, or the module (or block) containing /// the block, if `self` corresponds to a block expression. - pub fn containing_module(self, db: &dyn DefDatabase) -> Option { + pub fn containing_module(self, db: &dyn SourceDatabase) -> Option { self.containing_module_inside_def_map(db) .or_else(|| self.block(db).map(|block| block.loc(db).module)) .map(|module| { @@ -538,14 +544,14 @@ impl ModuleId { }) } - pub fn is_block_module(self, db: &dyn DefDatabase) -> bool { + pub fn is_block_module(self, db: &dyn SourceDatabase) -> bool { self.block(db).is_some() && self.containing_module_inside_def_map(db).is_none() } } impl HasModule for ModuleId { #[inline] - fn module(&self, _db: &dyn DefDatabase) -> ModuleId { + fn module(&self, _db: &dyn SourceDatabase) -> ModuleId { *self } } @@ -670,11 +676,68 @@ pub enum MacroId { impl_from!(Macro2Id, MacroRulesId, ProcMacroId for MacroId); impl MacroId { - pub fn is_attribute(self, db: &dyn DefDatabase) -> bool { + pub fn is_attribute(self, db: &dyn SourceDatabase) -> bool { matches!(self, MacroId::ProcMacroId(it) if it.lookup(db).kind == ProcMacroKind::Attr) } } +#[salsa::tracked] +impl MacroId { + /// Turns a MacroId into a MacroDefId, describing the macro's definition post name resolution. + #[salsa::tracked] + pub fn definition(self, db: &dyn SourceDatabase) -> MacroDefId { + let kind = |expander, file_id, m| { + let in_file = InFile::new(file_id, m); + match expander { + MacroExpander::Declarative { styles } => MacroDefKind::Declarative(in_file, styles), + MacroExpander::BuiltIn(it) => MacroDefKind::BuiltIn(in_file, it), + MacroExpander::BuiltInAttr(it) => MacroDefKind::BuiltInAttr(in_file, it), + MacroExpander::BuiltInDerive(it) => MacroDefKind::BuiltInDerive(in_file, it), + MacroExpander::BuiltInEager(it) => MacroDefKind::BuiltInEager(in_file, it), + MacroExpander::UnimplementedBuiltIn => MacroDefKind::UnimplementedBuiltIn(in_file), + } + }; + + match self { + MacroId::Macro2Id(it) => { + let loc = it.lookup(db); + + MacroDefId { + krate: loc.container.krate(db), + kind: kind(loc.expander, loc.id.file_id, loc.id.value.upcast()), + local_inner: false, + allow_internal_unsafe: loc.allow_internal_unsafe, + edition: loc.edition, + } + } + MacroId::MacroRulesId(it) => { + let loc = it.lookup(db); + + MacroDefId { + krate: loc.container.krate(db), + kind: kind(loc.expander, loc.id.file_id, loc.id.value.upcast()), + local_inner: loc.flags.contains(MacroRulesLocFlags::LOCAL_INNER), + allow_internal_unsafe: loc + .flags + .contains(MacroRulesLocFlags::ALLOW_INTERNAL_UNSAFE), + edition: loc.edition, + } + } + MacroId::ProcMacroId(it) => { + let loc = it.lookup(db); + + MacroDefId { + krate: loc.container.krate(db), + kind: MacroDefKind::ProcMacro(loc.id, loc.expander, loc.kind), + local_inner: false, + allow_internal_unsafe: false, + edition: loc.edition, + } + } + } + } +} + /// A generic param #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum GenericParamId { @@ -746,7 +809,7 @@ impl From for DefWithBodyId { } impl DefWithBodyId { - pub fn generic_def(self, db: &dyn DefDatabase) -> GenericDefId { + pub fn generic_def(self, db: &dyn SourceDatabase) -> GenericDefId { match self { DefWithBodyId::FunctionId(f) => f.into(), DefWithBodyId::StaticId(s) => s.into(), @@ -824,7 +887,7 @@ impl ExpressionStoreOwnerId { if let Self::Body(v) = self { Some(v) } else { None } } - pub fn generic_def(self, db: &dyn DefDatabase) -> GenericDefId { + pub fn generic_def(self, db: &dyn SourceDatabase) -> GenericDefId { match self { ExpressionStoreOwnerId::Signature(generic_def_id) => generic_def_id, ExpressionStoreOwnerId::Body(def_with_body_id) => match def_with_body_id { @@ -869,11 +932,11 @@ impl From for ExpressionStoreOwnerId { impl GenericDefId { pub fn file_id_and_params_of( self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, ) -> (HirFileId, Option) { fn file_id_and_params_of_item_loc( - db: &dyn DefDatabase, - def: impl Lookup, + db: &dyn SourceDatabase, + def: impl Lookup, ) -> (HirFileId, Option) where Loc: src::HasSource, @@ -896,7 +959,7 @@ impl GenericDefId { } } - pub fn assoc_trait_container(self, db: &dyn DefDatabase) -> Option { + pub fn assoc_trait_container(self, db: &dyn SourceDatabase) -> Option { match match self { GenericDefId::FunctionId(f) => f.lookup(db).container, GenericDefId::TypeAliasId(t) => t.lookup(db).container, @@ -908,7 +971,7 @@ impl GenericDefId { } } - pub fn from_callable(db: &dyn DefDatabase, def: CallableDefId) -> GenericDefId { + pub fn from_callable(db: &dyn SourceDatabase, def: CallableDefId) -> GenericDefId { match def { CallableDefId::FunctionId(f) => f.into(), CallableDefId::StructId(s) => s.into(), @@ -946,7 +1009,7 @@ impl From for ModuleDefId { } impl CallableDefId { - pub fn krate(self, db: &dyn DefDatabase) -> Crate { + pub fn krate(self, db: &dyn SourceDatabase) -> Crate { match self { CallableDefId::FunctionId(f) => f.krate(db), CallableDefId::StructId(s) => s.krate(db), @@ -1025,19 +1088,19 @@ impl VariantId { }) } - pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields { + pub fn fields(self, db: &dyn SourceDatabase) -> &VariantFields { VariantFields::of(db, self) } pub fn fields_with_source_map( self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, ) -> (&VariantFields, &ExpressionStoreSourceMap) { let r = VariantFields::with_source_map(db, self); (&r.0, &r.1) } - pub fn file_id(self, db: &dyn DefDatabase) -> HirFileId { + pub fn file_id(self, db: &dyn SourceDatabase) -> HirFileId { match self { VariantId::EnumVariantId(it) => it.lookup(db).id.file_id, VariantId::StructId(it) => it.lookup(db).id.file_id, @@ -1045,7 +1108,7 @@ impl VariantId { } } - pub fn adt_id(self, db: &dyn DefDatabase) -> AdtId { + pub fn adt_id(self, db: &dyn SourceDatabase) -> AdtId { match self { VariantId::EnumVariantId(it) => it.lookup(db).parent.into(), VariantId::StructId(it) => it.into(), @@ -1056,11 +1119,11 @@ impl VariantId { pub trait HasModule { /// Returns the enclosing module this thing is defined within. - fn module(&self, db: &dyn DefDatabase) -> ModuleId; + fn module(&self, db: &dyn SourceDatabase) -> ModuleId; /// Returns the crate this thing is defined within. #[inline] #[doc(alias = "crate")] - fn krate(&self, db: &dyn DefDatabase) -> Crate { + fn krate(&self, db: &dyn SourceDatabase) -> Crate { self.module(db).krate(db) } } @@ -1070,11 +1133,11 @@ pub trait HasModule { // impl HasModule for ItemId // where // N: ItemTreeNode, -// ItemId: for<'db> Lookup = dyn DefDatabase + 'db, Data = Data> + Copy, +// ItemId: for<'db> Lookup = dyn SourceDatabase + 'db, Data = Data> + Copy, // Data: ItemTreeLoc, // { // #[inline] -// fn module(&self, db: &dyn DefDatabase) -> ModuleId { +// fn module(&self, db: &dyn SourceDatabase) -> ModuleId { // self.lookup(db).container() // } // } @@ -1082,10 +1145,10 @@ pub trait HasModule { impl HasModule for ItemId where N: AstIdNode, - ItemId: Lookup> + Copy, + ItemId: Lookup> + Copy, { #[inline] - fn module(&self, db: &dyn DefDatabase) -> ModuleId { + fn module(&self, db: &dyn SourceDatabase) -> ModuleId { self.lookup(db).container } } @@ -1095,10 +1158,10 @@ where // impl HasModule for ItemId // where // N: ItemTreeModItemNode, -// ItemId: for<'db> Lookup = dyn DefDatabase + 'db, Data = AssocItemLoc> + Copy, +// ItemId: for<'db> Lookup = dyn SourceDatabase + 'db, Data = AssocItemLoc> + Copy, // { // #[inline] -// fn module(&self, db: &dyn DefDatabase) -> ModuleId { +// fn module(&self, db: &dyn SourceDatabase) -> ModuleId { // self.lookup(db).container.module(db) // } // } @@ -1106,50 +1169,50 @@ where // region: manual-assoc-has-module-impls #[inline] fn module_for_assoc_item_loc<'db>( - db: &(dyn 'db + DefDatabase), - id: impl Lookup>, + db: &(dyn 'db + SourceDatabase), + id: impl Lookup>, ) -> ModuleId { id.lookup(db).container.module(db) } impl HasModule for BuiltinDeriveImplLoc { #[inline] - fn module(&self, db: &dyn DefDatabase) -> ModuleId { + fn module(&self, db: &dyn SourceDatabase) -> ModuleId { self.adt.module(db) } } impl HasModule for BuiltinDeriveImplId { #[inline] - fn module(&self, db: &dyn DefDatabase) -> ModuleId { + fn module(&self, db: &dyn SourceDatabase) -> ModuleId { self.loc(db).module(db) } } impl HasModule for FunctionId { #[inline] - fn module(&self, db: &dyn DefDatabase) -> ModuleId { + fn module(&self, db: &dyn SourceDatabase) -> ModuleId { module_for_assoc_item_loc(db, *self) } } impl HasModule for ConstId { #[inline] - fn module(&self, db: &dyn DefDatabase) -> ModuleId { + fn module(&self, db: &dyn SourceDatabase) -> ModuleId { module_for_assoc_item_loc(db, *self) } } impl HasModule for StaticId { #[inline] - fn module(&self, db: &dyn DefDatabase) -> ModuleId { + fn module(&self, db: &dyn SourceDatabase) -> ModuleId { module_for_assoc_item_loc(db, *self) } } impl HasModule for TypeAliasId { #[inline] - fn module(&self, db: &dyn DefDatabase) -> ModuleId { + fn module(&self, db: &dyn SourceDatabase) -> ModuleId { module_for_assoc_item_loc(db, *self) } } @@ -1157,34 +1220,34 @@ impl HasModule for TypeAliasId { impl HasModule for EnumVariantId { #[inline] - fn module(&self, db: &dyn DefDatabase) -> ModuleId { + fn module(&self, db: &dyn SourceDatabase) -> ModuleId { self.lookup(db).parent.module(db) } } impl HasModule for MacroRulesId { #[inline] - fn module(&self, db: &dyn DefDatabase) -> ModuleId { + fn module(&self, db: &dyn SourceDatabase) -> ModuleId { self.lookup(db).container } } impl HasModule for Macro2Id { #[inline] - fn module(&self, db: &dyn DefDatabase) -> ModuleId { + fn module(&self, db: &dyn SourceDatabase) -> ModuleId { self.lookup(db).container } } impl HasModule for ProcMacroId { #[inline] - fn module(&self, db: &dyn DefDatabase) -> ModuleId { + fn module(&self, db: &dyn SourceDatabase) -> ModuleId { self.lookup(db).container } } impl HasModule for ItemContainerId { - fn module(&self, db: &dyn DefDatabase) -> ModuleId { + fn module(&self, db: &dyn SourceDatabase) -> ModuleId { match *self { ItemContainerId::ModuleId(it) => it, ItemContainerId::ImplId(it) => it.module(db), @@ -1195,7 +1258,7 @@ impl HasModule for ItemContainerId { } impl HasModule for AdtId { - fn module(&self, db: &dyn DefDatabase) -> ModuleId { + fn module(&self, db: &dyn SourceDatabase) -> ModuleId { match *self { AdtId::StructId(it) => it.module(db), AdtId::UnionId(it) => it.module(db), @@ -1205,7 +1268,7 @@ impl HasModule for AdtId { } impl HasModule for VariantId { - fn module(&self, db: &dyn DefDatabase) -> ModuleId { + fn module(&self, db: &dyn SourceDatabase) -> ModuleId { match *self { VariantId::EnumVariantId(it) => it.module(db), VariantId::StructId(it) => it.module(db), @@ -1215,7 +1278,7 @@ impl HasModule for VariantId { } impl HasModule for MacroId { - fn module(&self, db: &dyn DefDatabase) -> ModuleId { + fn module(&self, db: &dyn SourceDatabase) -> ModuleId { match *self { MacroId::MacroRulesId(it) => it.module(db), MacroId::Macro2Id(it) => it.module(db), @@ -1225,7 +1288,7 @@ impl HasModule for MacroId { } impl HasModule for DefWithBodyId { - fn module(&self, db: &dyn DefDatabase) -> ModuleId { + fn module(&self, db: &dyn SourceDatabase) -> ModuleId { match self { DefWithBodyId::FunctionId(it) => it.module(db), DefWithBodyId::StaticId(it) => it.module(db), @@ -1236,7 +1299,7 @@ impl HasModule for DefWithBodyId { } impl HasModule for ExpressionStoreOwnerId { - fn module(&self, db: &dyn DefDatabase) -> ModuleId { + fn module(&self, db: &dyn SourceDatabase) -> ModuleId { match self { ExpressionStoreOwnerId::Signature(def) => def.module(db), ExpressionStoreOwnerId::Body(def) => def.module(db), @@ -1246,7 +1309,7 @@ impl HasModule for ExpressionStoreOwnerId { } impl HasModule for GenericDefId { - fn module(&self, db: &dyn DefDatabase) -> ModuleId { + fn module(&self, db: &dyn SourceDatabase) -> ModuleId { match self { GenericDefId::FunctionId(it) => it.module(db), GenericDefId::AdtId(it) => it.module(db), @@ -1260,7 +1323,7 @@ impl HasModule for GenericDefId { } impl HasModule for AttrDefId { - fn module(&self, db: &dyn DefDatabase) -> ModuleId { + fn module(&self, db: &dyn SourceDatabase) -> ModuleId { match self { AttrDefId::ModuleId(it) => *it, AttrDefId::AdtId(it) => it.module(db), @@ -1283,7 +1346,7 @@ impl ModuleDefId { /// Returns the module containing `self` (or `self`, if `self` is itself a module). /// /// Returns `None` if `self` refers to a primitive type. - pub fn module(&self, db: &dyn DefDatabase) -> Option { + pub fn module(&self, db: &dyn SourceDatabase) -> Option { Some(match self { ModuleDefId::ModuleId(id) => *id, ModuleDefId::FunctionId(id) => id.module(db), @@ -1312,7 +1375,7 @@ impl AstIdWithPath { } pub fn macro_call_as_call_id( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, ast_id: AstId, path: &ModPath, call_site: SyntaxContext, @@ -1422,3 +1485,17 @@ impl Complete { } } } + +// return: macro call id and include file id +#[salsa::tracked(returns(ref))] +pub fn include_macro_invoc( + db: &dyn SourceDatabase, + krate: Crate, +) -> Box<[(MacroCallId, EditionedFileId)]> { + crate_def_map(db, krate) + .modules + .values() + .flat_map(|m| m.scope.iter_macro_invoc()) + .filter_map(|(_, &invoc)| invoc.loc(db).include_file_id(db, invoc).map(|x| (invoc, x))) + .collect() +} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs index 1d6812ad56a54..188f57f7dda7c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -16,11 +16,11 @@ mod proc_macros; use std::{any::TypeId, iter, ops::Range, sync}; +use base_db::SourceDatabase; use expect_test::Expect; use hir_expand::{ - AstId, ExpansionInfo, InFile, MacroCallId, MacroCallKind, MacroKind, + AstId, ExpansionInfo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroKind, builtin::quote::quote, - db::ExpandDatabase, proc_macro::{ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind}, span_map::SpanMap, }; @@ -43,7 +43,6 @@ use tt::{TextRange, TextSize}; use crate::{ AdtId, Lookup, ModuleDefId, - db::DefDatabase, expr_store::Body, nameres::{DefMap, ModuleSource, crate_def_map}, src::HasSource, @@ -62,7 +61,7 @@ fn check_errors(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) .modules() .flat_map(|module| module.1.scope.all_macro_calls()) .filter_map(|macro_call| { - let errors = db.parse_macro_expansion_error(macro_call)?; + let errors = macro_call.parse_macro_expansion_error(&db)?; let errors = errors.err.as_ref()?.render_to_string(&db); let macro_loc = macro_call.loc(&db); let ast_id = match macro_loc.kind { @@ -75,7 +74,7 @@ fn check_errors(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) ast_id.file_id.file_id().expect("macros inside macros are not supported"); let ast = editioned_file_id.parse(&db).syntax_node(); - let ast_id_map = db.ast_id_map(ast_id.file_id); + let ast_id_map = ast_id.file_id.ast_id_map(&db); let node = ast_id_map.get_erased(ast_id.value).to_node(&ast); Some((node.text_range(), errors)) }) @@ -120,12 +119,12 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream let mut expansions = Vec::new(); for macro_call_node in source_file.syntax().descendants().filter_map(ast::MacroCall::cast) { - let ast_id = db.ast_id_map(source.file_id).ast_id(¯o_call_node); + let ast_id = source.file_id.ast_id_map(&db).ast_id(¯o_call_node); let ast_id = InFile::new(source.file_id, ast_id); let ptr = InFile::new(source.file_id, AstPtr::new(¯o_call_node)); let macro_call_id = resolve_macro_call_id(&db, def_map, ast_id, ptr) .unwrap_or_else(|| panic!("unable to find semantic macro call {macro_call_node}")); - let expansion_result = db.parse_macro_expansion(macro_call_id); + let expansion_result = macro_call_id.parse_macro_expansion(&db); expansions.push((macro_call_node.clone(), expansion_result)); } @@ -215,7 +214,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream } let pp = pretty_print_macro_expansion( src.value, - db.span_map(src.file_id), + src.file_id.span_map(&db), show_spans, show_ctxt, ); @@ -230,7 +229,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream if let Some(macro_file) = src.file_id.macro_file() { let pp = pretty_print_macro_expansion( src.value.syntax().clone(), - db.span_map(macro_file.into()), + HirFileId::from(macro_file).span_map(&db), false, false, ); @@ -245,7 +244,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream { let pp = pretty_print_macro_expansion( src.value.syntax().clone(), - db.span_map(macro_file.into()), + HirFileId::from(macro_file).span_map(&db), false, false, ); @@ -260,7 +259,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream } fn resolve_macro_call_id( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, def_map: &DefMap, ast_id: AstId, ast_ptr: InFile>, @@ -387,7 +386,7 @@ struct IdentityWhenValidProcMacroExpander; impl ProcMacroExpander for IdentityWhenValidProcMacroExpander { fn expand( &self, - _: &dyn ExpandDatabase, + _: &dyn SourceDatabase, subtree: &TopSubtree, _: Option<&TopSubtree>, _: &base_db::Env, @@ -465,18 +464,19 @@ m!(g); ModuleSource::SourceFile(it) => it, ModuleSource::Module(_) | ModuleSource::BlockExpr(_) => panic!(), }; + let span_map = HirFileId::from(file_id).span_map(&db); let no_downmap_spans: Vec<_> = source_file .syntax() .descendants() .map(|node| { - let mut span = db.real_span_map(file_id).span_for_range(node.text_range()); + let mut span = span_map.span_for_range(node.text_range()); span.anchor.ast_id = NO_DOWNMAP_ERASED_FILE_AST_ID_MARKER; span }) .collect(); for macro_call_node in source_file.syntax().descendants().filter_map(ast::MacroCall::cast) { - let ast_id = db.ast_id_map(source.file_id).ast_id(¯o_call_node); + let ast_id = source.file_id.ast_id_map(&db).ast_id(¯o_call_node); let ast_id = InFile::new(source.file_id, ast_id); let ptr = InFile::new(source.file_id, AstPtr::new(¯o_call_node)); let macro_call_id = resolve_macro_call_id(&db, def_map, ast_id, ptr) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs index 0c7e7a3ca070f..00d069867203f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs @@ -60,7 +60,7 @@ mod tests; use std::ops::{Deref, DerefMut, Index, IndexMut}; -use base_db::Crate; +use base_db::{Crate, SourceDatabase}; use either::Either; use hir_expand::{ EditionedFileId, ErasedAstId, HirFileId, InFile, MacroCallId, mod_path::ModPath, name::Name, @@ -78,7 +78,6 @@ use tt::TextRange; use crate::{ AstId, BlockId, BlockLoc, BuiltinDeriveImplId, ExternCrateId, FunctionId, FxIndexMap, Lookup, MacroCallStyles, MacroExpander, MacroId, ModuleId, ModuleIdLt, ProcMacroId, UseId, - db::DefDatabase, item_scope::{BuiltinShadowMode, ItemScope}, item_tree::TreeId, nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode}, @@ -343,7 +342,7 @@ impl ModuleOrigin { /// Returns a node which defines this module. /// That is, a file or a `mod foo {}` with items. - pub fn definition_source(&self, db: &dyn DefDatabase) -> InFile { + pub fn definition_source(&self, db: &dyn SourceDatabase) -> InFile { match self { &ModuleOrigin::File { definition: editioned_file_id, .. } | &ModuleOrigin::CrateRoot { definition: editioned_file_id } => { @@ -378,7 +377,7 @@ pub struct ModuleData { } #[inline] -pub fn crate_def_map(db: &dyn DefDatabase, crate_id: Crate) -> &DefMap { +pub fn crate_def_map(db: &dyn SourceDatabase, crate_id: Crate) -> &DefMap { crate_local_def_map(db, crate_id).def_map(db) } @@ -392,7 +391,7 @@ pub(crate) struct DefMapPair<'db> { } #[salsa_macros::tracked(returns(ref))] -pub(crate) fn crate_local_def_map(db: &dyn DefDatabase, crate_id: Crate) -> DefMapPair<'_> { +pub(crate) fn crate_local_def_map(db: &dyn SourceDatabase, crate_id: Crate) -> DefMapPair<'_> { let krate = crate_id.data(db); let _p = tracing::info_span!( "crate_def_map_query", @@ -426,7 +425,7 @@ pub(crate) fn crate_local_def_map(db: &dyn DefDatabase, crate_id: Crate) -> DefM } #[salsa_macros::tracked(returns(ref))] -pub fn block_def_map(db: &dyn DefDatabase, block_id: BlockId) -> DefMap { +pub fn block_def_map(db: &dyn SourceDatabase, block_id: BlockId) -> DefMap { let BlockLoc { ast_id, module } = *block_id.lookup(db); let visibility = Visibility::Module(module, VisibilityExplicitness::Implicit); @@ -458,7 +457,7 @@ impl DefMap { } fn empty( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, krate: Crate, crate_data: Arc, module_data: ModuleData, @@ -521,7 +520,7 @@ impl DefMap { /// Returns all modules in the crate that are associated with the given file. pub fn modules_for_file<'a>( &'a self, - db: &'a dyn DefDatabase, + db: &'a dyn SourceDatabase, file_id: FileId, ) -> impl Iterator + 'a { self.modules @@ -594,7 +593,7 @@ impl DefMap { } #[inline] - pub fn crate_root(&self, db: &dyn DefDatabase) -> ModuleId { + pub fn crate_root(&self, db: &dyn SourceDatabase) -> ModuleId { match self.block { Some(_) => crate_def_map(db, self.krate()).root, None => self.root, @@ -634,7 +633,7 @@ impl DefMap { // FIXME: this can use some more human-readable format (ideally, an IR // even), as this should be a great debugging aid. - pub fn dump(&self, db: &dyn DefDatabase) -> String { + pub fn dump(&self, db: &dyn SourceDatabase) -> String { let mut buf = String::new(); let mut current_map = self; while let Some(block) = current_map.block { @@ -645,7 +644,13 @@ impl DefMap { go(&mut buf, db, current_map, "crate", current_map.root); return buf; - fn go(buf: &mut String, db: &dyn DefDatabase, map: &DefMap, path: &str, module: ModuleId) { + fn go( + buf: &mut String, + db: &dyn SourceDatabase, + map: &DefMap, + path: &str, + module: ModuleId, + ) { format_to!(buf, "{}\n", path); map[module].scope.dump(db, buf); @@ -676,7 +681,7 @@ impl DefMap { pub(crate) fn resolve_path( &self, local_def_map: &LocalDefMap, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, original_module: ModuleId, path: &ModPath, shadow: BuiltinShadowMode, @@ -699,7 +704,7 @@ impl DefMap { pub(crate) fn resolve_path_locally( &self, local_def_map: &LocalDefMap, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, original_module: ModuleId, path: &ModPath, shadow: BuiltinShadowMode, @@ -722,7 +727,7 @@ impl DefMap { /// `None`, iteration continues. pub(crate) fn with_ancestor_maps( &self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, local_mod: ModuleId, f: &mut dyn FnMut(&DefMap, ModuleId) -> Option, ) -> Option { @@ -758,7 +763,7 @@ impl ModuleData { } /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items. - pub fn definition_source(&self, db: &dyn DefDatabase) -> InFile { + pub fn definition_source(&self, db: &dyn SourceDatabase) -> InFile { self.origin.definition_source(db) } @@ -773,7 +778,7 @@ impl ModuleData { } } - pub fn definition_source_range(&self, db: &dyn DefDatabase) -> InFile { + pub fn definition_source_range(&self, db: &dyn SourceDatabase) -> InFile { match &self.origin { &ModuleOrigin::File { definition, .. } | &ModuleOrigin::CrateRoot { definition } => { InFile::new( @@ -791,7 +796,7 @@ impl ModuleData { /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`. /// `None` for the crate root or block. - pub fn declaration_source(&self, db: &dyn DefDatabase) -> Option> { + pub fn declaration_source(&self, db: &dyn SourceDatabase) -> Option> { let decl = self.origin.declaration()?; let value = decl.to_node(db); Some(InFile { file_id: decl.file_id, value }) @@ -799,7 +804,7 @@ impl ModuleData { /// Returns the range which declares this module, either a `mod foo;` or a `mod foo {}`. /// `None` for the crate root or block. - pub fn declaration_source_range(&self, db: &dyn DefDatabase) -> Option> { + pub fn declaration_source_range(&self, db: &dyn SourceDatabase) -> Option> { let decl = self.origin.declaration()?; Some(InFile { file_id: decl.file_id, value: decl.to_range(db) }) } @@ -831,7 +836,7 @@ pub enum MacroSubNs { Attr, } -pub(crate) fn macro_styles_from_id(db: &dyn DefDatabase, macro_id: MacroId) -> MacroCallStyles { +pub(crate) fn macro_styles_from_id(db: &dyn SourceDatabase, macro_id: MacroId) -> MacroCallStyles { let expander = match macro_id { MacroId::Macro2Id(it) => it.lookup(db).expander, MacroId::MacroRulesId(it) => it.lookup(db).expander, @@ -861,7 +866,7 @@ pub(crate) fn macro_styles_from_id(db: &dyn DefDatabase, macro_id: MacroId) -> M /// /// [rustc]: https://github.com/rust-lang/rust/blob/1.69.0/compiler/rustc_resolve/src/macros.rs#L75 fn sub_namespace_match( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, macro_id: MacroId, expected: Option, ) -> bool { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs index 7b5b39cb08cbe..9560d7855a0fd 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs @@ -2,6 +2,7 @@ use std::mem; +use base_db::SourceDatabase; use cfg::CfgOptions; use hir_expand::{ AstId, AttrMacroAttrIds, ExpandTo, HirFileId, InFile, Intern, Lookup, MacroCallKind, @@ -21,7 +22,6 @@ use thin_vec::ThinVec; use crate::{ AssocItemId, AstIdWithPath, ConstLoc, FunctionId, FunctionLoc, ImplId, ItemContainerId, ItemLoc, MacroCallId, ModuleId, TraitId, TypeAliasId, TypeAliasLoc, - db::DefDatabase, item_tree::AttrsOrCfg, macro_call_as_call_id, nameres::{ @@ -41,17 +41,17 @@ pub struct TraitItems { #[salsa::tracked] impl TraitItems { #[inline] - pub(crate) fn query(db: &dyn DefDatabase, tr: TraitId) -> &TraitItems { + pub(crate) fn query(db: &dyn SourceDatabase, tr: TraitId) -> &TraitItems { &Self::query_with_diagnostics(db, tr).0 } #[salsa::tracked(returns(ref))] pub fn query_with_diagnostics( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, tr: TraitId, ) -> (TraitItems, DefDiagnostics) { let ItemLoc { container: module_id, id: ast_id } = *tr.lookup(db); - let ast_id_map = db.ast_id_map(ast_id.file_id); + let ast_id_map = ast_id.file_id.ast_id_map(db); let source = ast_id.with_value(ast_id_map.get(ast_id.value)).to_node(db); if source.eq_token().is_some() { // FIXME(trait-alias) probably needs special handling here @@ -113,7 +113,7 @@ pub struct ImplItems { #[salsa::tracked] impl ImplItems { #[salsa::tracked(returns(ref))] - pub fn of(db: &dyn DefDatabase, id: ImplId) -> (ImplItems, DefDiagnostics) { + pub fn of(db: &dyn SourceDatabase, id: ImplId) -> (ImplItems, DefDiagnostics) { let _p = tracing::info_span!("impl_items_with_diagnostics_query").entered(); let ItemLoc { container: module_id, id: ast_id } = *id.lookup(db); @@ -133,7 +133,7 @@ impl ImplItems { } struct AssocItemCollector<'db> { - db: &'db dyn DefDatabase, + db: &'db dyn SourceDatabase, module_id: ModuleId, def_map: &'db DefMap, local_def_map: &'db LocalDefMap, @@ -151,7 +151,7 @@ struct AssocItemCollector<'db> { impl<'db> AssocItemCollector<'db> { fn new( - db: &'db dyn DefDatabase, + db: &'db dyn SourceDatabase, module_id: ModuleId, container: ItemContainerId, file_id: HirFileId, @@ -162,8 +162,8 @@ impl<'db> AssocItemCollector<'db> { module_id, def_map, local_def_map, - ast_id_map: db.ast_id_map(file_id), - span_map: db.span_map(file_id), + ast_id_map: file_id.ast_id_map(db), + span_map: file_id.span_map(db), cfg_options: module_id.krate(db).cfg_options(db), file_id, container, @@ -312,7 +312,7 @@ impl<'db> AssocItemCollector<'db> { ) .0 .take_macros() - .map(|it| self.db.macro_def(it)) + .map(|it| it.definition(self.db)) }; match macro_call_as_call_id( self.db, @@ -356,9 +356,9 @@ impl<'db> AssocItemCollector<'db> { return; } - let (syntax, span_map) = &self.db.parse_macro_expansion(macro_call_id).value; + let (syntax, span_map) = ¯o_call_id.parse_macro_expansion(self.db).value; let old_file_id = mem::replace(&mut self.file_id, macro_call_id.into()); - let old_ast_id_map = mem::replace(&mut self.ast_id_map, self.db.ast_id_map(self.file_id)); + let old_ast_id_map = mem::replace(&mut self.ast_id_map, self.file_id.ast_id_map(self.db)); let old_span_map = mem::replace(&mut self.span_map, SpanMap::ExpansionSpanMap(span_map)); self.depth += 1; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs index 5aabd7dbc6fcc..e78c38bf5ad38 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs @@ -1,6 +1,6 @@ //! Post-nameres attribute resolution. -use base_db::Crate; +use base_db::{Crate, SourceDatabase}; use hir_expand::{ AttrMacroAttrIds, MacroCallId, MacroCallKind, MacroDefId, attrs::{Attr, AttrId, AttrInput}, @@ -12,7 +12,6 @@ use syntax::ast; use crate::{ AstIdWithPath, MacroId, ModuleId, UnresolvedMacro, - db::DefDatabase, item_scope::BuiltinShadowMode, nameres::{LocalDefMap, path_resolution::ResolveMode}, }; @@ -31,7 +30,7 @@ impl DefMap { pub(crate) fn resolve_attr_macro( &self, local_def_map: &LocalDefMap, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, original_module: ModuleId, ast_id: AstIdWithPath, attr: &Attr, @@ -73,7 +72,7 @@ impl DefMap { // replace their input, and derive macros are not allowed in this function. AttrMacroAttrIds::from_one(attr_id), self.krate, - db.macro_def(def), + def.definition(db), ))) } @@ -103,7 +102,7 @@ impl DefMap { } pub(super) fn attr_macro_as_call_id( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, item_attr: &AstIdWithPath, macro_attr: &Attr, censored_attr_ids: AttrMacroAttrIds, @@ -133,7 +132,7 @@ pub(super) fn attr_macro_as_call_id( } pub(super) fn derive_macro_as_call_id( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, item_attr: &AstIdWithPath, derive_attr_index: AttrId, derive_pos: u32, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index 25daf2c3f9177..a15d6d7474084 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -5,7 +5,7 @@ use std::{iter, mem, ops::Range}; -use base_db::{BuiltDependency, Crate, CrateOrigin, LangCrateOrigin}; +use base_db::{BuiltDependency, Crate, CrateOrigin, LangCrateOrigin, SourceDatabase}; use cfg::{CfgAtom, CfgExpr, CfgOptions}; use either::Either; use hir_expand::{ @@ -33,8 +33,7 @@ use crate::{ ImplLoc, Intern, ItemContainerId, Lookup, Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, UseId, - UseLoc, - db::DefDatabase, + UseLoc, file_item_tree, item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports}, item_tree::{ self, Attrs, AttrsOrCfg, FieldsShape, ImportAlias, ImportKind, ItemTree, ItemTreeAstId, @@ -61,7 +60,7 @@ const GLOB_RECURSION_LIMIT: usize = 100; const FIXED_POINT_LIMIT: usize = 8192; pub(super) fn collect_defs( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, def_map: DefMap, tree_id: TreeId, crate_local_def_map: Option<&LocalDefMap>, @@ -231,7 +230,7 @@ struct DeferredBuiltinDerive { /// Walks the tree of module recursively struct DefCollector<'db> { - db: &'db dyn DefDatabase, + db: &'db dyn SourceDatabase, def_map: DefMap, local_def_map: LocalDefMap, /// Set only in case of blocks. @@ -279,7 +278,7 @@ impl<'db> DefCollector<'db> { let _p = tracing::info_span!("seed_with_top_level").entered(); let file_id = self.def_map.krate.root_file_id(self.db); - let item_tree = self.db.file_item_tree(file_id.into(), self.def_map.krate); + let item_tree = file_item_tree(self.db, file_id.into(), self.def_map.krate); let attrs = match item_tree.top_level_attrs() { AttrsOrCfg::Enabled { attrs } => attrs.as_ref(), AttrsOrCfg::CfgDisabled(it) => it.1.as_ref(), @@ -616,7 +615,7 @@ impl<'db> DefCollector<'db> { let (expander, kind) = match self.proc_macros.iter().find(|(n, _, _)| n == &def.name) { Some(_) if kind == hir_expand::proc_macro::ProcMacroKind::Attr - && !crate::db::ExpandProcAttrMacros::get(self.db).enabled(self.db) => + && !crate::ExpandProcAttrMacros::get(self.db).enabled(self.db) => { (CustomProcMacroExpander::disabled_proc_attr(), kind) } @@ -1336,7 +1335,7 @@ impl<'db> DefCollector<'db> { BuiltinShadowMode::Module, Some(subns), ); - resolved_res.resolved_def.take_macros().map(|it| (it, self.db.macro_def(it))) + resolved_res.resolved_def.take_macros().map(|it| (it, it.definition(self.db))) }; let resolver_def_id = |path: &_| resolver(&self.def_map, path).map(|(_, it)| it); @@ -1715,7 +1714,7 @@ impl<'db> DefCollector<'db> { } let file_id = macro_call_id.into(); - let item_tree = self.db.file_item_tree(file_id, self.def_map.krate); + let item_tree = file_item_tree(self.db, file_id, self.def_map.krate); // Derive helpers that are in scope for an item are also in scope for attribute macro expansions // of that item (but not derive or fn like macros). @@ -1787,7 +1786,7 @@ impl<'db> DefCollector<'db> { BuiltinShadowMode::Module, Some(MacroSubNs::Bang), ); - resolved_res.resolved_def.take_macros().map(|it| self.db.macro_def(it)) + resolved_res.resolved_def.take_macros().map(|it| it.definition(self.db)) }, &mut |_, _| (), ); @@ -2345,7 +2344,7 @@ impl ModCollector<'_, '_> { ) { Ok((file_id, is_mod_rs, mod_dir)) => { let item_tree = - db.file_item_tree(file_id.into(), self.def_collector.def_map.krate); + file_item_tree(db, file_id.into(), self.def_collector.def_map.krate); match item_tree.top_level_attrs() { AttrsOrCfg::CfgDisabled(cfg) => { self.emit_unconfigured_diagnostic( @@ -2561,7 +2560,7 @@ impl ModCollector<'_, '_> { } else { // Case 2: normal `macro_rules!` macro let id = InFile::new(self.file_id(), ast_id); - let decl_expander = self.def_collector.db.decl_macro_expander(krate, id.upcast()); + let decl_expander = id.upcast().decl_macro_expander(self.def_collector.db, krate); let styles = decl_expander.mac.rule_styles(); MacroExpander::Declarative { styles } }; @@ -2639,7 +2638,7 @@ impl ModCollector<'_, '_> { } else { // Case 2: normal `macro` let id = InFile::new(self.file_id(), ast_id); - let decl_expander = self.def_collector.db.decl_macro_expander(krate, id.upcast()); + let decl_expander = id.upcast().decl_macro_expander(self.def_collector.db, krate); let styles = decl_expander.mac.rule_styles(); MacroExpander::Declarative { styles } }; @@ -2702,7 +2701,7 @@ impl ModCollector<'_, '_> { .or_else(|| def_map[self.module_id].scope.get(name).take_macros()) .or_else(|| Some(def_map.macro_use_prelude.get(name).copied()?.0)) .filter(|&id| sub_namespace_match(db, id, Some(MacroSubNs::Bang))) - .map(|it| self.def_collector.db.macro_def(it)) + .map(|it| it.definition(self.def_collector.db)) }) }, &mut |ptr, call_id| eager_callback_buffer.push((ptr, call_id)), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs index 0c50f13edfb6c..af7bd818f4e62 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs @@ -1,9 +1,9 @@ //! This module resolves `mod foo;` declaration to file. use arrayvec::ArrayVec; -use base_db::AnchoredPath; +use base_db::{AnchoredPath, SourceDatabase}; use hir_expand::{EditionedFileId, name::Name}; -use crate::{HirFileId, db::DefDatabase}; +use crate::HirFileId; const MOD_DEPTH_LIMIT: usize = 32; @@ -58,7 +58,7 @@ impl ModDir { pub(super) fn resolve_declaration( &self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, file_id: HirFileId, name: &Name, attr_path: Option<&str>, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs index 54fd30fe6ba3e..7ffac38086729 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs @@ -10,6 +10,7 @@ //! //! `ReachedFixedPoint` signals about this. +use base_db::SourceDatabase; use either::Either; use hir_expand::{ mod_path::{ModPath, PathKind}, @@ -20,7 +21,6 @@ use stdx::TupleExt; use crate::{ AdtId, ModuleDefId, ModuleId, - db::DefDatabase, item_scope::{BUILTIN_SCOPE, ImportOrExternCrate}, item_tree::FieldsShape, nameres::{ @@ -82,7 +82,7 @@ impl ResolvePathResult { impl PerNs { pub(super) fn filter_macro( mut self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, expected: Option, ) -> Self { self.macros = self.macros.filter(|def| sub_namespace_match(db, def.def, expected)); @@ -95,7 +95,7 @@ impl DefMap { pub(crate) fn resolve_visibility( &self, local_def_map: &LocalDefMap, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, // module to import to original_module: ModuleId, // pub(path) @@ -155,7 +155,7 @@ impl DefMap { pub(super) fn resolve_path_fp_with_macro( &self, local_def_map: &LocalDefMap, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, mode: ResolveMode, // module to import to mut original_module: ModuleId, @@ -243,7 +243,7 @@ impl DefMap { pub(super) fn resolve_path_fp_with_macro_single( &self, local_def_map: &LocalDefMap, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, mode: ResolveMode, original_module: ModuleId, path: &ModPath, @@ -371,7 +371,7 @@ impl DefMap { pub(super) fn resolve_path_fp_in_all_preludes( &self, local_def_map: &LocalDefMap, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, mode: ResolveMode, original_module: ModuleId, path: &ModPath, @@ -448,7 +448,7 @@ impl DefMap { fn resolve_remaining_segments<'a>( &self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, mode: ResolveMode, mut segments: impl Iterator, mut curr_per_ns: PerNs, @@ -632,7 +632,7 @@ impl DefMap { fn resolve_name_in_module( &self, local_def_map: &LocalDefMap, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, module: ModuleId, name: &Name, shadow: BuiltinShadowMode, @@ -693,7 +693,7 @@ impl DefMap { fn resolve_name_in_all_preludes( &self, local_def_map: &LocalDefMap, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, name: &Name, ) -> PerNs { // Resolve in: @@ -729,7 +729,7 @@ impl DefMap { fn resolve_name_in_crate_root_or_extern_prelude( &self, local_def_map: &LocalDefMap, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, module: ModuleId, name: &Name, ) -> PerNs { @@ -751,7 +751,7 @@ impl DefMap { from_crate_root.or_else(from_extern_prelude) } - fn resolve_in_prelude(&self, db: &dyn DefDatabase, name: &Name) -> PerNs { + fn resolve_in_prelude(&self, db: &dyn SourceDatabase, name: &Name) -> PerNs { if let Some((prelude, _use)) = self.prelude { let keep; let def_map = if prelude.krate(db) == self.krate { @@ -771,7 +771,7 @@ impl DefMap { /// Given a block module, returns its nearest non-block module and the `DefMap` it belongs to. #[inline] fn adjust_to_nearest_non_block_module<'db>( - db: &'db dyn DefDatabase, + db: &'db dyn SourceDatabase, mut def_map: &'db DefMap, mut local_id: ModuleId, ) -> (&'db DefMap, ModuleId) { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs index bb19456f46fb2..49d94b969d06f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs @@ -9,7 +9,7 @@ use test_fixture::WithFixture; use triomphe::Arc; use crate::{ - db::DefDatabase, + file_item_tree, nameres::{crate_def_map, tests::TestDB}, }; @@ -166,15 +166,15 @@ fn no() {} [ "crate_local_def_map", "file_item_tree_query", - "ast_id_map", + "HirFileId::ast_id_map_", "parse", "real_span_map", "file_item_tree_query", - "ast_id_map", + "HirFileId::ast_id_map_", "parse", "real_span_map", "file_item_tree_query", - "ast_id_map", + "HirFileId::ast_id_map_", "parse", "real_span_map", "EnumVariants::of_", @@ -183,7 +183,7 @@ fn no() {} expect![[r#" [ "parse", - "ast_id_map", + "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", "EnumVariants::of_", @@ -224,34 +224,34 @@ pub struct S {} [ "crate_local_def_map", "file_item_tree_query", - "ast_id_map", + "HirFileId::ast_id_map_", "parse", "real_span_map", - "DeclarativeMacroExpander::expander_", + "AstId < ast :: Macro >::decl_macro_expander_", "file_item_tree_query", - "ast_id_map", + "HirFileId::ast_id_map_", "parse", "real_span_map", "file_item_tree_query", - "ast_id_map", + "HirFileId::ast_id_map_", "parse", "real_span_map", - "macro_def_shim", + "MacroId::definition_", "file_item_tree_query", - "ast_id_map", - "parse_macro_expansion", - "macro_arg", + "HirFileId::ast_id_map_", + "MacroCallId::parse_macro_expansion_", + "MacroCallId::macro_arg_", ] "#]], expect![[r#" [ "parse", - "ast_id_map", + "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", - "macro_arg", - "parse_macro_expansion", - "ast_id_map", + "MacroCallId::macro_arg_", + "MacroCallId::parse_macro_expansion_", + "HirFileId::ast_id_map_", "file_item_tree_query", ] "#]], @@ -282,42 +282,42 @@ fn f() { foo } [ "crate_local_def_map", "file_item_tree_query", - "ast_id_map", + "HirFileId::ast_id_map_", "parse", "real_span_map", "crate_local_def_map", "ProcMacros::get_for_crate_", "file_item_tree_query", - "ast_id_map", + "HirFileId::ast_id_map_", "parse", "real_span_map", "file_item_tree_query", - "ast_id_map", + "HirFileId::ast_id_map_", "parse", "real_span_map", "file_item_tree_query", - "ast_id_map", + "HirFileId::ast_id_map_", "parse", "real_span_map", - "macro_def_shim", + "MacroId::definition_", "file_item_tree_query", - "ast_id_map", - "parse_macro_expansion", - "expand_proc_macro", - "macro_arg", + "HirFileId::ast_id_map_", + "MacroCallId::parse_macro_expansion_", + "MacroCallId::expand_proc_macro_", + "MacroCallId::macro_arg_", "proc_macro_span", ] "#]], expect![[r#" [ "parse", - "ast_id_map", + "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", - "macro_arg", - "expand_proc_macro", - "parse_macro_expansion", - "ast_id_map", + "MacroCallId::macro_arg_", + "MacroCallId::expand_proc_macro_", + "MacroCallId::parse_macro_expansion_", + "HirFileId::ast_id_map_", "file_item_tree_query", ] "#]], @@ -406,54 +406,54 @@ pub struct S {} [ "crate_local_def_map", "file_item_tree_query", - "ast_id_map", + "HirFileId::ast_id_map_", "parse", "real_span_map", "crate_local_def_map", "ProcMacros::get_for_crate_", "file_item_tree_query", - "ast_id_map", + "HirFileId::ast_id_map_", "parse", "real_span_map", - "DeclarativeMacroExpander::expander_", + "AstId < ast :: Macro >::decl_macro_expander_", "file_item_tree_query", - "ast_id_map", + "HirFileId::ast_id_map_", "parse", "real_span_map", "file_item_tree_query", - "ast_id_map", + "HirFileId::ast_id_map_", "parse", "real_span_map", - "macro_def_shim", - "file_item_tree_query", - "ast_id_map", - "parse_macro_expansion", - "macro_arg", - "DeclarativeMacroExpander::expander_", - "macro_def_shim", - "file_item_tree_query", - "ast_id_map", - "parse_macro_expansion", - "macro_arg", - "macro_def_shim", - "file_item_tree_query", - "ast_id_map", - "parse_macro_expansion", - "expand_proc_macro", - "macro_arg", + "MacroId::definition_", + "file_item_tree_query", + "HirFileId::ast_id_map_", + "MacroCallId::parse_macro_expansion_", + "MacroCallId::macro_arg_", + "AstId < ast :: Macro >::decl_macro_expander_", + "MacroId::definition_", + "file_item_tree_query", + "HirFileId::ast_id_map_", + "MacroCallId::parse_macro_expansion_", + "MacroCallId::macro_arg_", + "MacroId::definition_", + "file_item_tree_query", + "HirFileId::ast_id_map_", + "MacroCallId::parse_macro_expansion_", + "MacroCallId::expand_proc_macro_", + "MacroCallId::macro_arg_", "proc_macro_span", ] "#]], expect![[r#" [ "parse", - "ast_id_map", + "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", - "macro_arg", - "DeclarativeMacroExpander::expander_", - "macro_arg", - "macro_arg", + "MacroCallId::macro_arg_", + "AstId < ast :: Macro >::decl_macro_expander_", + "MacroCallId::macro_arg_", + "MacroCallId::macro_arg_", ] "#]], ); @@ -523,31 +523,31 @@ m!(Z); [ "crate_local_def_map", "file_item_tree_query", - "ast_id_map", + "HirFileId::ast_id_map_", "parse", "real_span_map", - "DeclarativeMacroExpander::expander_", + "AstId < ast :: Macro >::decl_macro_expander_", "file_item_tree_query", - "ast_id_map", + "HirFileId::ast_id_map_", "parse", "real_span_map", "file_item_tree_query", - "ast_id_map", + "HirFileId::ast_id_map_", "parse", "real_span_map", - "macro_def_shim", + "MacroId::definition_", "file_item_tree_query", - "ast_id_map", - "parse_macro_expansion", - "macro_arg", + "HirFileId::ast_id_map_", + "MacroCallId::parse_macro_expansion_", + "MacroCallId::macro_arg_", "file_item_tree_query", - "ast_id_map", - "parse_macro_expansion", - "macro_arg", + "HirFileId::ast_id_map_", + "MacroCallId::parse_macro_expansion_", + "MacroCallId::macro_arg_", "file_item_tree_query", - "ast_id_map", - "parse_macro_expansion", - "macro_arg", + "HirFileId::ast_id_map_", + "MacroCallId::parse_macro_expansion_", + "MacroCallId::macro_arg_", ] "#]], ); @@ -572,12 +572,12 @@ m!(Z); expect![[r#" [ "parse", - "ast_id_map", + "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", - "macro_arg", - "macro_arg", - "macro_arg", + "MacroCallId::macro_arg_", + "MacroCallId::macro_arg_", + "MacroCallId::macro_arg_", ] "#]], ); @@ -604,13 +604,13 @@ pub type Ty = (); execute_assert_events( &db, || { - db.file_item_tree(pos.file_id.into(), db.test_crate()); + file_item_tree(&db, pos.file_id.into(), db.test_crate()); }, &[("file_item_tree_query", 1), ("parse", 1)], expect![[r#" [ "file_item_tree_query", - "ast_id_map", + "HirFileId::ast_id_map_", "parse", "real_span_map", ] @@ -624,13 +624,13 @@ pub type Ty = (); execute_assert_events( &db, || { - db.file_item_tree(pos.file_id.into(), db.test_crate()); + file_item_tree(&db, pos.file_id.into(), db.test_crate()); }, &[("file_item_tree_query", 1), ("parse", 1)], expect![[r#" [ "parse", - "ast_id_map", + "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", ] diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index c16ad9b4f2867..28d460b503fd6 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -1,7 +1,7 @@ //! Name resolution façade. use std::{fmt, mem}; -use base_db::Crate; +use base_db::{Crate, SourceDatabase}; use hir_expand::{ MacroDefId, mod_path::{ModPath, PathKind}, @@ -21,7 +21,6 @@ use crate::{ MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UseId, VariantId, builtin_type::BuiltinType, - db::DefDatabase, expr_store::{ HygieneId, path::Path, @@ -135,7 +134,7 @@ pub enum LifetimeNs { impl<'db> Resolver<'db> { /// Resolve known trait from std, like `std::futures::Future` - pub fn resolve_known_trait(&self, db: &dyn DefDatabase, path: &ModPath) -> Option { + pub fn resolve_known_trait(&self, db: &dyn SourceDatabase, path: &ModPath) -> Option { let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?; match res { ModuleDefId::TraitId(it) => Some(it), @@ -144,7 +143,11 @@ impl<'db> Resolver<'db> { } /// Resolve known struct from std, like `std::boxed::Box` - pub fn resolve_known_struct(&self, db: &dyn DefDatabase, path: &ModPath) -> Option { + pub fn resolve_known_struct( + &self, + db: &dyn SourceDatabase, + path: &ModPath, + ) -> Option { let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?; match res { ModuleDefId::AdtId(AdtId::StructId(it)) => Some(it), @@ -153,7 +156,7 @@ impl<'db> Resolver<'db> { } /// Resolve known enum from std, like `std::result::Result` - pub fn resolve_known_enum(&self, db: &dyn DefDatabase, path: &ModPath) -> Option { + pub fn resolve_known_enum(&self, db: &dyn SourceDatabase, path: &ModPath) -> Option { let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?; match res { ModuleDefId::AdtId(AdtId::EnumId(it)) => Some(it), @@ -161,13 +164,13 @@ impl<'db> Resolver<'db> { } } - pub fn resolve_module_path_in_items(&self, db: &dyn DefDatabase, path: &ModPath) -> PerNs { + pub fn resolve_module_path_in_items(&self, db: &dyn SourceDatabase, path: &ModPath) -> PerNs { self.resolve_module_path(db, path, BuiltinShadowMode::Module) } pub fn resolve_path_in_type_ns( &self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, path: &Path, ) -> Option<(TypeNs, Option, Option)> { self.resolve_path_in_type_ns_with_prefix_info(db, path).map( @@ -177,7 +180,7 @@ impl<'db> Resolver<'db> { pub fn resolve_path_in_type_ns_with_prefix_info( &self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, path: &Path, ) -> Option<(TypeNs, Option, Option, ResolvePathResultPrefixInfo)> { @@ -278,7 +281,7 @@ impl<'db> Resolver<'db> { pub fn resolve_path_in_type_ns_fully( &self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, path: &Path, ) -> Option { let (res, unresolved, _) = self.resolve_path_in_type_ns(db, path)?; @@ -290,7 +293,7 @@ impl<'db> Resolver<'db> { pub fn resolve_visibility( &self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, visibility: &RawVisibility, ) -> Option { match visibility { @@ -316,7 +319,7 @@ impl<'db> Resolver<'db> { pub fn resolve_path_in_value_ns( &self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, path: &Path, hygiene_id: HygieneId, ) -> Option { @@ -325,7 +328,7 @@ impl<'db> Resolver<'db> { pub fn resolve_path_in_value_ns_with_prefix_info( &self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, path: &Path, mut hygiene_id: HygieneId, ) -> Option<(ResolveValueResult, ResolvePathResultPrefixInfo)> { @@ -483,7 +486,7 @@ impl<'db> Resolver<'db> { pub fn resolve_path_in_value_ns_fully( &self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, path: &Path, hygiene: HygieneId, ) -> Option { @@ -495,7 +498,7 @@ impl<'db> Resolver<'db> { pub fn resolve_path_as_macro( &self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, path: &ModPath, expected_macro_kind: Option, ) -> Option<(MacroId, Option)> { @@ -515,11 +518,11 @@ impl<'db> Resolver<'db> { pub fn resolve_path_as_macro_def( &self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, path: &ModPath, expected_macro_kind: Option, ) -> Option { - self.resolve_path_as_macro(db, path, expected_macro_kind).map(|(it, _)| db.macro_def(it)) + self.resolve_path_as_macro(db, path, expected_macro_kind).map(|(it, _)| it.definition(db)) } pub fn resolve_lifetime(&self, lifetime: &LifetimeRef) -> Option { @@ -579,7 +582,7 @@ impl<'db> Resolver<'db> { /// we use the position of the first scope. pub fn names_in_scope( &self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, ) -> FxIndexMap> { let mut res = ScopeNames::default(); for scope in self.scopes() { @@ -625,7 +628,7 @@ impl<'db> Resolver<'db> { /// Note: Not to be used directly within hir-def/hir-ty pub fn extern_crate_decls_in_scope<'a>( &'a self, - db: &'a dyn DefDatabase, + db: &'a dyn SourceDatabase, ) -> impl Iterator + 'a { self.module_scope.def_map[self.module_scope.module_id] .scope @@ -650,7 +653,7 @@ impl<'db> Resolver<'db> { .map(|(name, module_id)| (name.clone(), module_id.0)) } - pub fn traits_in_scope(&self, db: &dyn DefDatabase) -> FxHashSet { + pub fn traits_in_scope(&self, db: &dyn SourceDatabase) -> FxHashSet { // FIXME(trait_alias): Trait alias brings aliased traits in scope! Note that supertraits of // aliased traits are NOT brought in scope (unless also aliased). let mut traits = FxHashSet::default(); @@ -713,7 +716,7 @@ impl<'db> Resolver<'db> { } #[inline] - pub fn is_visible(&self, db: &dyn DefDatabase, visibility: Visibility) -> bool { + pub fn is_visible(&self, db: &dyn SourceDatabase, visibility: Visibility) -> bool { visibility.is_visible_from_def_map( db, self.module_scope.def_map, @@ -760,7 +763,7 @@ impl<'db> Resolver<'db> { /// (that contains `current_name` path) change from `renamed` to some another variable (returned as `Some`). pub fn rename_will_conflict_with_another_variable( &self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, current_name: &Name, current_name_as_path: &ModPath, mut hygiene_id: HygieneId, @@ -809,7 +812,7 @@ impl<'db> Resolver<'db> { /// from some other variable (returned as `Some`) to `renamed`. pub fn rename_will_conflict_with_renamed( &self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, name: &Name, name_as_path: &ModPath, mut hygiene_id: HygieneId, @@ -859,7 +862,7 @@ impl<'db> Resolver<'db> { #[must_use] pub fn update_to_inner_scope( &mut self, - db: &'db dyn DefDatabase, + db: &'db dyn SourceDatabase, owner: impl Into, expr_id: ExprId, ) -> UpdateGuard { @@ -868,13 +871,13 @@ impl<'db> Resolver<'db> { fn update_to_inner_scope_( &mut self, - db: &'db dyn DefDatabase, + db: &'db dyn SourceDatabase, owner: ExpressionStoreOwnerId, expr_id: ExprId, ) -> UpdateGuard { #[inline(always)] fn append_expr_scope<'db>( - db: &'db dyn DefDatabase, + db: &'db dyn SourceDatabase, resolver: &mut Resolver<'db>, owner: ExpressionStoreOwnerId, expr_scopes: &'db ExprScopes, @@ -929,7 +932,7 @@ impl<'db> Resolver<'db> { #[inline] fn handle_macro_def_scope( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, hygiene_id: &mut HygieneId, hygiene_info: &mut Option<(SyntaxContext, MacroDefId)>, macro_id: &MacroDefId, @@ -950,7 +953,7 @@ fn handle_macro_def_scope( #[inline] fn hygiene_info( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, hygiene_id: HygieneId, ) -> Option<(SyntaxContext, MacroDefId)> { if !hygiene_id.is_root() { @@ -973,7 +976,7 @@ impl<'db> Resolver<'db> { fn resolve_module_path( &self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, path: &ModPath, shadow: BuiltinShadowMode, ) -> PerNs { @@ -1014,7 +1017,7 @@ pub enum ScopeDef { } impl<'db> Scope<'db> { - fn process_names(&self, acc: &mut ScopeNames, db: &'db dyn DefDatabase) { + fn process_names(&self, acc: &mut ScopeNames, db: &'db dyn SourceDatabase) { match self { Scope::BlockScope(m) => { m.def_map[m.module_id].scope.entries().for_each(|(name, def)| { @@ -1069,7 +1072,7 @@ impl<'db> Scope<'db> { } pub fn resolver_for_scope( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, owner: impl Into + HasResolver, scope_id: Option, ) -> Resolver<'_> { @@ -1080,7 +1083,7 @@ pub fn resolver_for_scope( } fn resolver_for_scope_<'db>( - db: &'db dyn DefDatabase, + db: &'db dyn SourceDatabase, scopes: &'db ExprScopes, scope_id: Option, mut r: Resolver<'db>, @@ -1117,7 +1120,7 @@ impl<'db> Resolver<'db> { fn push_generic_params_scope( self, - db: &'db dyn DefDatabase, + db: &'db dyn SourceDatabase, def: GenericDefId, ) -> Resolver<'db> { let params = GenericParams::of(db, def); @@ -1146,7 +1149,7 @@ impl<'db> Resolver<'db> { impl<'db> ModuleItemMap<'db> { fn resolve_path_in_value_ns( &self, - db: &'db dyn DefDatabase, + db: &'db dyn SourceDatabase, path: &ModPath, ) -> Option<(ResolveValueResult, ResolvePathResultPrefixInfo)> { let (module_def, unresolved_idx, prefix_info) = self.def_map.resolve_path_locally( @@ -1183,7 +1186,7 @@ impl<'db> ModuleItemMap<'db> { fn resolve_path_in_type_ns( &self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, path: &ModPath, ) -> Option<(TypeNs, Option, Option, ResolvePathResultPrefixInfo)> { @@ -1287,11 +1290,11 @@ impl ScopeNames { pub trait HasResolver: Copy { /// Builds a resolver for type references inside this def. - fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_>; + fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_>; } impl HasResolver for ModuleId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { let (mut def_map, local_def_map) = self.local_def_map(db); let mut module_id = self; @@ -1323,69 +1326,69 @@ impl HasResolver for ModuleId { } impl HasResolver for TraitId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { lookup_resolver(db, self).push_generic_params_scope(db, self.into()) } } impl + Copy> HasResolver for T { - fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { let def = self.into(); def.module(db).resolver(db).push_generic_params_scope(db, def.into()) } } impl HasResolver for FunctionId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { lookup_resolver(db, self).push_generic_params_scope(db, self.into()) } } impl HasResolver for ConstId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { lookup_resolver(db, self) } } impl HasResolver for StaticId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { lookup_resolver(db, self) } } impl HasResolver for TypeAliasId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { lookup_resolver(db, self).push_generic_params_scope(db, self.into()) } } impl HasResolver for ImplId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into()) } } impl HasResolver for ExternBlockId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { // Same as parent's lookup_resolver(db, self) } } impl HasResolver for ExternCrateId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { lookup_resolver(db, self) } } impl HasResolver for UseId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { lookup_resolver(db, self) } } impl HasResolver for DefWithBodyId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { match self { DefWithBodyId::ConstId(c) => c.resolver(db), DefWithBodyId::FunctionId(f) => f.resolver(db), @@ -1396,7 +1399,7 @@ impl HasResolver for DefWithBodyId { } impl HasResolver for ItemContainerId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { match self { ItemContainerId::ModuleId(it) => it.resolver(db), ItemContainerId::TraitId(it) => it.resolver(db), @@ -1407,7 +1410,7 @@ impl HasResolver for ItemContainerId { } impl HasResolver for GenericDefId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { match self { GenericDefId::FunctionId(inner) => inner.resolver(db), GenericDefId::AdtId(adt) => adt.resolver(db), @@ -1421,7 +1424,7 @@ impl HasResolver for GenericDefId { } impl HasResolver for ExpressionStoreOwnerId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { match self { ExpressionStoreOwnerId::Signature(def) => def.resolver(db), ExpressionStoreOwnerId::Body(def) => def.resolver(db), @@ -1431,13 +1434,13 @@ impl HasResolver for ExpressionStoreOwnerId { } impl HasResolver for EnumVariantId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { self.lookup(db).parent.resolver(db) } } impl HasResolver for VariantId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { match self { VariantId::EnumVariantId(it) => it.resolver(db), VariantId::StructId(it) => it.resolver(db), @@ -1447,7 +1450,7 @@ impl HasResolver for VariantId { } impl HasResolver for MacroId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { match self { MacroId::Macro2Id(it) => it.resolver(db), MacroId::MacroRulesId(it) => it.resolver(db), @@ -1457,26 +1460,26 @@ impl HasResolver for MacroId { } impl HasResolver for Macro2Id { - fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { lookup_resolver(db, self) } } impl HasResolver for ProcMacroId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { lookup_resolver(db, self) } } impl HasResolver for MacroRulesId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { lookup_resolver(db, self) } } fn lookup_resolver( - db: &dyn DefDatabase, - lookup: impl Lookup>, + db: &dyn SourceDatabase, + lookup: impl Lookup>, ) -> Resolver<'_> { lookup.lookup(db).container().resolver(db) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs index e9307a125502a..9126105530249 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs @@ -2,6 +2,7 @@ use std::cell::LazyCell; +use base_db::SourceDatabase; use bitflags::bitflags; use cfg::{CfgExpr, CfgOptions}; use hir_expand::{ @@ -23,7 +24,6 @@ use crate::{ HasModule, ImplId, ItemContainerId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, UnionId, VariantId, attrs::AttrFlags, - db::DefDatabase, expr_store::{ Body, ExpressionStore, ExpressionStoreBuilder, ExpressionStoreSourceMap, lower::{ @@ -75,13 +75,13 @@ bitflags! { #[salsa::tracked] impl StructSignature { #[salsa::tracked(returns(deref))] - pub fn of(db: &dyn DefDatabase, id: StructId) -> Arc { + pub fn of(db: &dyn SourceDatabase, id: StructId) -> Arc { Self::with_source_map(db, id).0.clone() } #[salsa::tracked(returns(ref))] pub fn with_source_map( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, id: StructId, ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); @@ -131,7 +131,7 @@ impl StructSignature { } #[inline] - pub fn repr(&self, db: &dyn DefDatabase, id: StructId) -> Option { + pub fn repr(&self, db: &dyn SourceDatabase, id: StructId) -> Option { if self.flags.contains(StructFlags::HAS_REPR) { AttrFlags::repr_assume_has(db, id.into()) } else { @@ -160,13 +160,13 @@ pub struct UnionSignature { #[salsa::tracked] impl UnionSignature { #[salsa::tracked(returns(deref))] - pub fn of(db: &dyn DefDatabase, id: UnionId) -> Arc { + pub fn of(db: &dyn SourceDatabase, id: UnionId) -> Arc { Self::with_source_map(db, id).0.clone() } #[salsa::tracked(returns(ref))] pub fn with_source_map( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, id: UnionId, ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); @@ -203,7 +203,7 @@ impl UnionSignature { } #[inline] - pub fn repr(&self, db: &dyn DefDatabase, id: UnionId) -> Option { + pub fn repr(&self, db: &dyn SourceDatabase, id: UnionId) -> Option { if self.flags.contains(StructFlags::HAS_REPR) { AttrFlags::repr_assume_has(db, id.into()) } else { @@ -235,13 +235,13 @@ pub struct EnumSignature { #[salsa::tracked] impl EnumSignature { #[salsa::tracked(returns(deref))] - pub fn of(db: &dyn DefDatabase, id: EnumId) -> Arc { + pub fn of(db: &dyn SourceDatabase, id: EnumId) -> Arc { Self::with_source_map(db, id).0.clone() } #[salsa::tracked(returns(ref))] pub fn with_source_map( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, id: EnumId, ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); @@ -280,7 +280,7 @@ impl EnumSignature { } impl EnumSignature { - pub fn variant_body_type(db: &dyn DefDatabase, id: EnumId) -> IntegerType { + pub fn variant_body_type(db: &dyn SourceDatabase, id: EnumId) -> IntegerType { match AttrFlags::repr(db, id.into()) { Some(ReprOptions { int: Some(builtin), .. }) => builtin, _ => IntegerType::Pointer(true), @@ -288,7 +288,7 @@ impl EnumSignature { } #[inline] - pub fn repr(&self, db: &dyn DefDatabase, id: EnumId) -> Option { + pub fn repr(&self, db: &dyn SourceDatabase, id: EnumId) -> Option { if self.flags.contains(EnumFlags::HAS_REPR) { AttrFlags::repr_assume_has(db, id.into()) } else { @@ -316,13 +316,13 @@ pub struct ConstSignature { #[salsa::tracked] impl ConstSignature { #[salsa::tracked(returns(deref))] - pub fn of(db: &dyn DefDatabase, id: ConstId) -> Arc { + pub fn of(db: &dyn SourceDatabase, id: ConstId) -> Arc { Self::with_source_map(db, id).0.clone() } #[salsa::tracked(returns(ref))] pub fn with_source_map( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, id: ConstId, ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); @@ -384,13 +384,13 @@ pub struct StaticSignature { #[salsa::tracked] impl StaticSignature { #[salsa::tracked(returns(deref))] - pub fn of(db: &dyn DefDatabase, id: StaticId) -> Arc { + pub fn of(db: &dyn SourceDatabase, id: StaticId) -> Arc { Self::with_source_map(db, id).0.clone() } #[salsa::tracked(returns(ref))] pub fn with_source_map( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, id: StaticId, ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); @@ -456,13 +456,13 @@ pub struct ImplSignature { #[salsa::tracked] impl ImplSignature { #[salsa::tracked(returns(deref))] - pub fn of(db: &dyn DefDatabase, id: ImplId) -> Arc { + pub fn of(db: &dyn SourceDatabase, id: ImplId) -> Arc { Self::with_source_map(db, id).0.clone() } #[salsa::tracked(returns(ref))] pub fn with_source_map( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, id: ImplId, ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); @@ -527,13 +527,13 @@ pub struct TraitSignature { #[salsa::tracked] impl TraitSignature { #[salsa::tracked(returns(deref))] - pub fn of(db: &dyn DefDatabase, id: TraitId) -> Arc { + pub fn of(db: &dyn SourceDatabase, id: TraitId) -> Arc { Self::with_source_map(db, id).0.clone() } #[salsa::tracked(returns(ref))] pub fn with_source_map( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, id: TraitId, ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); @@ -615,13 +615,13 @@ pub struct FunctionSignature { #[salsa::tracked] impl FunctionSignature { #[salsa::tracked(returns(deref))] - pub fn of(db: &dyn DefDatabase, id: FunctionId) -> Arc { + pub fn of(db: &dyn SourceDatabase, id: FunctionId) -> Arc { Self::with_source_map(db, id).0.clone() } #[salsa::tracked(returns(ref))] pub fn with_source_map( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, id: FunctionId, ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); @@ -763,7 +763,7 @@ impl FunctionSignature { #[inline] pub fn legacy_const_generics_indices<'db>( &self, - db: &'db dyn DefDatabase, + db: &'db dyn SourceDatabase, id: FunctionId, ) -> Option<&'db [u32]> { if !self.flags.contains(FnFlags::HAS_LEGACY_CONST_GENERICS) { @@ -773,7 +773,7 @@ impl FunctionSignature { AttrFlags::legacy_const_generic_indices(db, id).as_deref() } - pub fn is_intrinsic(db: &dyn DefDatabase, id: FunctionId) -> bool { + pub fn is_intrinsic(db: &dyn SourceDatabase, id: FunctionId) -> bool { let data = FunctionSignature::of(db, id); data.flags.contains(FnFlags::RUSTC_INTRINSIC) } @@ -801,13 +801,13 @@ pub struct TypeAliasSignature { #[salsa::tracked] impl TypeAliasSignature { #[salsa::tracked(returns(deref))] - pub fn of(db: &dyn DefDatabase, id: TypeAliasId) -> Arc { + pub fn of(db: &dyn SourceDatabase, id: TypeAliasId) -> Arc { Self::with_source_map(db, id).0.clone() } #[salsa::tracked(returns(ref))] pub fn with_source_map( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, id: TypeAliasId, ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); @@ -878,7 +878,7 @@ pub struct VariantFields { impl VariantFields { #[salsa::tracked(returns(ref))] pub fn with_source_map( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, id: VariantId, ) -> (Arc, ExpressionStoreSourceMap) { let (shape, result) = match id { @@ -935,7 +935,7 @@ impl VariantFields { } #[salsa::tracked(returns(deref))] - pub fn of(db: &dyn DefDatabase, id: VariantId) -> Arc { + pub fn of(db: &dyn SourceDatabase, id: VariantId) -> Arc { Self::with_source_map(db, id).0.clone() } } @@ -955,7 +955,7 @@ impl VariantFields { } fn lower_field_list( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, module: ModuleId, fields: InFile>, override_visibility: Option>, @@ -980,7 +980,7 @@ fn lower_field_list( } fn lower_fields( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, module: ModuleId, fields: InFile, Field)>>, mut field_name: impl FnMut(usize, &Field) -> Name, @@ -990,7 +990,7 @@ fn lower_fields( let mut col = ExprCollector::new(db, module, fields.file_id); let override_visibility = override_visibility.map(|vis| { LazyCell::new(|| { - let span_map = db.span_map(fields.file_id); + let span_map = fields.file_id.span_map(db); visibility_from_ast(db, vis, &mut |range| span_map.span_for_range(range).ctx) }) }); @@ -1063,12 +1063,12 @@ pub struct EnumVariants { impl EnumVariants { #[salsa::tracked(returns(ref))] pub(crate) fn of( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, e: EnumId, ) -> (EnumVariants, ThinVec) { let loc = e.lookup(db); let source = loc.source(db); - let ast_id_map = db.ast_id_map(source.file_id); + let ast_id_map = source.file_id.ast_id_map(db); let mut diagnostics = ThinVec::new(); let cfg_options = loc.container.krate(db).cfg_options(db); @@ -1121,7 +1121,7 @@ impl EnumVariants { } // [Adopted from rustc](https://github.com/rust-lang/rust/blob/bd53aa3bf7a24a70d763182303bd75e5fc51a9af/compiler/rustc_middle/src/ty/adt.rs#L446-L448) - pub fn is_payload_free(&self, db: &dyn DefDatabase) -> bool { + pub fn is_payload_free(&self, db: &dyn SourceDatabase) -> bool { self.variants.values().all(|&(v, shape)| { // The condition check order is slightly modified from rustc // to improve performance by early returning with relatively fast checks @@ -1145,7 +1145,7 @@ impl EnumVariants { } #[salsa::tracked] -pub(crate) fn extern_block_abi(db: &dyn DefDatabase, extern_block: ExternBlockId) -> ExternAbi { +pub(crate) fn extern_block_abi(db: &dyn SourceDatabase, extern_block: ExternBlockId) -> ExternAbi { let source = extern_block.lookup(db).source(db); source .value diff --git a/src/tools/rust-analyzer/crates/hir-def/src/src.rs b/src/tools/rust-analyzer/crates/hir-def/src/src.rs index e33fd95908b9f..62b273a017d98 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/src.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/src.rs @@ -1,5 +1,6 @@ //! Utilities for mapping between hir IDs and the surface syntax. +use base_db::SourceDatabase; use either::Either; use hir_expand::{AstId, InFile}; use la_arena::{Arena, ArenaMap, Idx}; @@ -7,16 +8,16 @@ use syntax::{AstNode, AstPtr, ast}; use crate::{ AstIdLoc, GenericDefId, LocalFieldId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, - UseId, VariantId, attrs::AttrFlags, db::DefDatabase, hir::generics::GenericParams, + UseId, VariantId, attrs::AttrFlags, hir::generics::GenericParams, }; pub trait HasSource { type Value: AstNode; - fn source(&self, db: &dyn DefDatabase) -> InFile { + fn source(&self, db: &dyn SourceDatabase) -> InFile { let InFile { file_id, value } = self.ast_ptr(db); - InFile::new(file_id, value.to_node(&db.parse_or_expand(file_id))) + InFile::new(file_id, value.to_node(&file_id.parse_or_expand(db))) } - fn ast_ptr(&self, db: &dyn DefDatabase) -> InFile>; + fn ast_ptr(&self, db: &dyn SourceDatabase) -> InFile>; } impl HasSource for T @@ -24,21 +25,21 @@ where T: AstIdLoc, { type Value = T::Ast; - fn ast_ptr(&self, db: &dyn DefDatabase) -> InFile> { + fn ast_ptr(&self, db: &dyn SourceDatabase) -> InFile> { let id = self.ast_id(); - let ast_id_map = db.ast_id_map(id.file_id); + let ast_id_map = id.file_id.ast_id_map(db); InFile::new(id.file_id, ast_id_map.get(id.value)) } } pub trait HasChildSource { type Value; - fn child_source(&self, db: &dyn DefDatabase) -> InFile>; + fn child_source(&self, db: &dyn SourceDatabase) -> InFile>; } /// Maps a `UseTree` contained in this import back to its AST node. pub fn use_tree_to_ast( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, use_ast_id: AstId, index: Idx, ) -> ast::UseTree { @@ -46,14 +47,17 @@ pub fn use_tree_to_ast( } /// Maps a `UseTree` contained in this import back to its AST node. -fn use_tree_source_map(db: &dyn DefDatabase, use_ast_id: AstId) -> Arena { +fn use_tree_source_map( + db: &dyn SourceDatabase, + use_ast_id: AstId, +) -> Arena { // Re-lower the AST item and get the source map. // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`. let ast = use_ast_id.to_node(db); let ast_use_tree = ast.use_tree().expect("missing `use_tree`"); let mut span_map = None; crate::item_tree::lower_use_tree(db, ast_use_tree, &mut |range| { - span_map.get_or_insert_with(|| db.span_map(use_ast_id.file_id)).span_for_range(range).ctx + span_map.get_or_insert_with(|| use_ast_id.file_id.span_map(db)).span_for_range(range).ctx }) .expect("failed to lower use tree") .1 @@ -63,7 +67,7 @@ impl HasChildSource> for UseId { type Value = ast::UseTree; fn child_source( &self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, ) -> InFile, Self::Value>> { let loc = self.lookup(db); InFile::new(loc.id.file_id, use_tree_source_map(db, loc.id).into_iter().collect()) @@ -74,7 +78,7 @@ impl HasChildSource for GenericDefId { type Value = Either; fn child_source( &self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, ) -> InFile> { let generic_params = GenericParams::of(db, *self); let mut idx_iter = generic_params.iter_type_or_consts().map(|(idx, _)| idx); @@ -108,7 +112,7 @@ impl HasChildSource for GenericDefId { type Value = ast::LifetimeParam; fn child_source( &self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, ) -> InFile> { let generic_params = GenericParams::of(db, *self); let idx_iter = generic_params.iter_lt().map(|(idx, _)| idx); @@ -130,7 +134,7 @@ impl HasChildSource for GenericDefId { impl HasChildSource for VariantId { type Value = Either; - fn child_source(&self, db: &dyn DefDatabase) -> InFile> { + fn child_source(&self, db: &dyn SourceDatabase) -> InFile> { let (src, container) = match *self { VariantId::EnumVariantId(it) => { let lookup = it.lookup(db); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs index 7831f58046804..0e4dd25c39df6 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs @@ -47,7 +47,7 @@ impl Default for TestDB { crates_map: Default::default(), nonce: Nonce::new(), }; - crate::db::set_expand_proc_attr_macros(&mut this, true); + crate::set_expand_proc_attr_macros(&mut this, true); // This needs to be here otherwise `CrateGraphBuilder` panics. set_all_crates_with_durability(&mut this, std::iter::empty(), Durability::HIGH); _ = base_db::LibraryRoots::builder(Default::default()) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/unstable_features.rs b/src/tools/rust-analyzer/crates/hir-def/src/unstable_features.rs index f581f02617883..3f9f54aa81129 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/unstable_features.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/unstable_features.rs @@ -7,12 +7,10 @@ use std::fmt; -use base_db::Crate; +use base_db::{Crate, SourceDatabase}; use intern::{Symbol, sym}; use rustc_hash::FxHashSet; -use crate::db::DefDatabase; - impl fmt::Debug for UnstableFeatures { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_set().entries(&self.all).finish() @@ -50,7 +48,7 @@ impl UnstableFeatures { /// This is also available as `DefMap::features()`. Use that if you have a DefMap available. /// Otherwise, use this, to not draw a dependency to the def map. #[salsa::tracked(returns(ref))] - pub fn query(db: &dyn DefDatabase, krate: Crate) -> UnstableFeatures { + pub fn query(db: &dyn SourceDatabase, krate: Crate) -> UnstableFeatures { crate::crate_def_map(db, krate).features().clone() } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs index 81a61ec20f17e..632aa1b352a10 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs @@ -2,15 +2,14 @@ use std::iter; -use base_db::Crate; +use base_db::{Crate, SourceDatabase}; use hir_expand::{InFile, Lookup}; use la_arena::ArenaMap; use syntax::ast::{self, HasVisibility}; use crate::{ AssocItemId, HasModule, ItemContainerId, LocalFieldId, ModuleId, TraitId, VariantId, - db::DefDatabase, nameres::DefMap, resolver::HasResolver, signatures::VariantFields, - src::HasSource, + nameres::DefMap, resolver::HasResolver, signatures::VariantFields, src::HasSource, }; pub use crate::item_tree::{RawVisibility, VisibilityExplicitness}; @@ -28,7 +27,7 @@ pub enum Visibility { impl Visibility { pub fn resolve( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, resolver: &crate::resolver::Resolver<'_>, raw_vis: &RawVisibility, ) -> Self { @@ -41,7 +40,7 @@ impl Visibility { } #[tracing::instrument(skip_all)] - pub fn is_visible_from(self, db: &dyn DefDatabase, from_module: ModuleId) -> bool { + pub fn is_visible_from(self, db: &dyn SourceDatabase, from_module: ModuleId) -> bool { let to_module = match self { Visibility::Module(m, _) => m, Visibility::PubCrate(krate) => return from_module.krate(db) == krate, @@ -61,7 +60,7 @@ impl Visibility { pub(crate) fn is_visible_from_def_map( self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, def_map: &DefMap, from_module: ModuleId, ) -> bool { @@ -90,7 +89,7 @@ impl Visibility { } fn is_visible_from_def_map_( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, def_map: &DefMap, mut to_module: ModuleId, mut from_module: ModuleId, @@ -150,7 +149,7 @@ impl Visibility { /// visible in unrelated modules). pub(crate) fn max( self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, other: Visibility, def_map: &DefMap, ) -> Option { @@ -216,7 +215,7 @@ impl Visibility { /// visible in unrelated modules). pub(crate) fn min( self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, other: Visibility, def_map: &DefMap, ) -> Option { @@ -282,7 +281,7 @@ impl VariantFields { /// Resolve visibility of all specific fields of a struct or union variant. #[salsa::tracked(returns(ref))] pub fn field_visibilities( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, variant_id: VariantId, ) -> ArenaMap { let variant_fields = variant_id.fields(db); @@ -300,13 +299,13 @@ impl VariantFields { } pub fn visibility_from_ast( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, has_resolver: impl HasResolver + HasModule, ast_vis: InFile>, ) -> Visibility { let mut span_map = None; let raw_vis = crate::item_tree::visibility_from_ast(db, ast_vis.value, &mut |range| { - span_map.get_or_insert_with(|| db.span_map(ast_vis.file_id)).span_for_range(range).ctx + span_map.get_or_insert_with(|| ast_vis.file_id.span_map(db)).span_for_range(range).ctx }); match raw_vis { RawVisibility::PubSelf(explicitness) => { @@ -318,41 +317,48 @@ pub fn visibility_from_ast( } } -/// Resolve visibility of a type alias. -pub(crate) fn assoc_visibility_query(db: &dyn DefDatabase, def: AssocItemId) -> Visibility { - match def { - AssocItemId::FunctionId(function_id) => { - let loc = function_id.lookup(db); - trait_item_visibility(db, loc.container).unwrap_or_else(|| { - let source = loc.source(db); - visibility_from_ast(db, function_id, source.map(|src| src.visibility())) - }) - } - AssocItemId::ConstId(const_id) => { - let loc = const_id.lookup(db); - trait_item_visibility(db, loc.container).unwrap_or_else(|| { - let source = loc.source(db); - visibility_from_ast(db, const_id, source.map(|src| src.visibility())) - }) - } - AssocItemId::TypeAliasId(type_alias_id) => { - let loc = type_alias_id.lookup(db); - trait_item_visibility(db, loc.container).unwrap_or_else(|| { - let source = loc.source(db); - visibility_from_ast(db, type_alias_id, source.map(|src| src.visibility())) - }) +#[salsa::tracked] +impl AssocItemId { + /// Resolve visibility of an assoc item. + #[salsa::tracked] + pub fn assoc_visibility(self, db: &dyn SourceDatabase) -> Visibility { + match self { + AssocItemId::FunctionId(function_id) => { + let loc = function_id.lookup(db); + trait_item_visibility(db, loc.container).unwrap_or_else(|| { + let source = loc.source(db); + visibility_from_ast(db, function_id, source.map(|src| src.visibility())) + }) + } + AssocItemId::ConstId(const_id) => { + let loc = const_id.lookup(db); + trait_item_visibility(db, loc.container).unwrap_or_else(|| { + let source = loc.source(db); + visibility_from_ast(db, const_id, source.map(|src| src.visibility())) + }) + } + AssocItemId::TypeAliasId(type_alias_id) => { + let loc = type_alias_id.lookup(db); + trait_item_visibility(db, loc.container).unwrap_or_else(|| { + let source = loc.source(db); + visibility_from_ast(db, type_alias_id, source.map(|src| src.visibility())) + }) + } } } } -fn trait_item_visibility(db: &dyn DefDatabase, container: ItemContainerId) -> Option { +fn trait_item_visibility( + db: &dyn SourceDatabase, + container: ItemContainerId, +) -> Option { match container { ItemContainerId::TraitId(trait_) => Some(trait_visibility(db, trait_)), _ => None, } } -fn trait_visibility(db: &dyn DefDatabase, def: TraitId) -> Visibility { +fn trait_visibility(db: &dyn SourceDatabase, def: TraitId) -> Visibility { let loc = def.lookup(db); let source = loc.source(db); visibility_from_ast(db, def, source.map(|src| src.visibility())) diff --git a/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml b/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml index 43b0bea891e39..9af75a0d8a6c1 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml @@ -20,7 +20,6 @@ rustc-hash.workspace = true itertools.workspace = true smallvec.workspace = true triomphe.workspace = true -query-group.workspace = true salsa.workspace = true salsa-macros.workspace = true thin-vec.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs index 896baacf04599..f5e581e8cf472 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs @@ -17,7 +17,7 @@ use std::{borrow::Cow, cell::OnceCell, convert::Infallible, fmt, ops::ControlFlow}; use ::tt::TextRange; -use base_db::Crate; +use base_db::{Crate, SourceDatabase}; use cfg::{CfgExpr, CfgOptions}; use either::Either; use intern::Interned; @@ -30,7 +30,6 @@ use syntax_bridge::DocCommentDesugarMode; use crate::{ AstId, - db::ExpandDatabase, mod_path::ModPath, span_map::SpanMap, tt::{self, TopSubtree}, @@ -293,7 +292,7 @@ impl Attr { /// Parses this attribute as a token tree consisting of comma separated paths. pub fn parse_path_comma_token_tree<'a>( &'a self, - db: &'a dyn ExpandDatabase, + db: &'a dyn SourceDatabase, ) -> Option)> + 'a> { let args = self.token_tree_value()?; @@ -305,7 +304,7 @@ impl Attr { } fn parse_path_comma_token_tree<'a>( - db: &'a dyn ExpandDatabase, + db: &'a dyn SourceDatabase, args: &'a tt::TopSubtree, ) -> impl Iterator)> { args.token_trees() @@ -366,7 +365,7 @@ impl AttrId { /// to `cfg_attr`) and its [`ast::Meta`]. pub fn find_attr_range( self, - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, krate: Crate, owner: AstId, ) -> (ast::Attr, ast::Meta) { @@ -380,7 +379,7 @@ impl AttrId { /// original file (not speculatively expanded macro output). pub fn find_attr_range_with_source( self, - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, krate: Crate, owner: &dyn ast::HasAttrs, ) -> (ast::Attr, ast::Meta) { @@ -393,7 +392,7 @@ impl AttrId { /// to `cfg_attr`) and its [`ast::Meta`]. pub(crate) fn find_attr_range_with_source_opt( self, - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, krate: Crate, owner: &dyn ast::HasAttrs, ) -> Option<(ast::Attr, ast::Meta)> { @@ -418,7 +417,7 @@ impl AttrId { pub fn find_derive_range( self, - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, krate: Crate, owner: AstId, derive_index: u32, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/attr_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/attr_macro.rs index 9b13f9fb00eba..540b3e66ce199 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/attr_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/attr_macro.rs @@ -1,8 +1,9 @@ //! Builtin attributes. +use base_db::SourceDatabase; use intern::sym; use span::Span; -use crate::{ExpandResult, MacroCallId, MacroCallKind, db::ExpandDatabase, name, tt}; +use crate::{ExpandResult, MacroCallId, MacroCallKind, name, tt}; use super::quote; @@ -14,7 +15,7 @@ macro_rules! register_builtin { } impl BuiltinAttrExpander { - pub fn expander(&self) -> fn (&dyn ExpandDatabase, MacroCallId, &tt::TopSubtree, Span) -> ExpandResult { + pub fn expander(&self) -> fn (&dyn SourceDatabase, MacroCallId, &tt::TopSubtree, Span) -> ExpandResult { match *self { $( BuiltinAttrExpander::$variant => $expand, )* } @@ -34,7 +35,7 @@ macro_rules! register_builtin { impl BuiltinAttrExpander { pub fn expand( &self, - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, id: MacroCallId, tt: &tt::TopSubtree, span: Span, @@ -74,7 +75,7 @@ pub fn find_builtin_attr(ident: &name::Name) -> Option { } fn dummy_attr_expand( - _db: &dyn ExpandDatabase, + _db: &dyn SourceDatabase, _id: MacroCallId, tt: &tt::TopSubtree, _span: Span, @@ -83,7 +84,7 @@ fn dummy_attr_expand( } fn dummy_gate_test_expand( - _db: &dyn ExpandDatabase, + _db: &dyn SourceDatabase, _id: MacroCallId, tt: &tt::TopSubtree, span: Span, @@ -117,7 +118,7 @@ fn dummy_gate_test_expand( /// So this hacky approach is a lot more friendly for us, though it does require a bit of support in /// hir::Semantics to make this work. fn derive_expand( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, id: MacroCallId, tt: &tt::TopSubtree, span: Span, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs index c4da558fdab24..5e85a710e0855 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs @@ -1,5 +1,6 @@ //! Builtin derives. +use base_db::SourceDatabase; use either::Either; use intern::sym; use itertools::{Itertools, izip}; @@ -13,7 +14,6 @@ use tracing::debug; use crate::{ ExpandError, ExpandResult, MacroCallId, builtin::quote::dollar_crate, - db::ExpandDatabase, hygiene::span_with_def_site_ctxt, name::{self, AsName, Name}, span_map::ExpansionSpanMap, @@ -35,7 +35,7 @@ macro_rules! register_builtin { } impl BuiltinDeriveExpander { - pub fn expander(&self) -> fn(&dyn ExpandDatabase, Span, &tt::TopSubtree) -> ExpandResult { + pub fn expander(&self) -> fn(&dyn SourceDatabase, Span, &tt::TopSubtree) -> ExpandResult { match *self { $( BuiltinDeriveExpander::$trait => $expand, )* } @@ -54,7 +54,7 @@ macro_rules! register_builtin { impl BuiltinDeriveExpander { pub fn expand( &self, - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, id: MacroCallId, tt: &tt::TopSubtree, span: Span, @@ -228,7 +228,7 @@ struct AdtParam { // FIXME: This whole thing needs a refactor. Each derive requires its special values, and the result is a mess. fn parse_adt( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, tt: &tt::TopSubtree, call_site: Span, ) -> Result { @@ -387,11 +387,11 @@ fn parse_adt_from_syntax( } fn to_adt_syntax( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, tt: &tt::TopSubtree, call_site: Span, ) -> Result<(ast::Adt, span::SpanMap), ExpandError> { - let (parsed, tm) = crate::db::token_tree_to_syntax_node(db, tt, crate::ExpandTo::Items); + let (parsed, tm) = crate::token_tree_to_syntax_node(db, tt, crate::ExpandTo::Items); let macro_items = ast::MacroItems::cast(parsed.syntax_node()) .ok_or_else(|| ExpandError::other(call_site, "invalid item definition"))?; let item = @@ -448,7 +448,7 @@ fn name_to_token( /// where B1, ..., BN are the bounds given by `bounds_paths`. Z is a phantom type, and /// therefore does not get bound by the derived trait. fn expand_simple_derive( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, invoc_span: Span, tt: &tt::TopSubtree, trait_path: tt::TopSubtree, @@ -531,7 +531,7 @@ fn expand_simple_derive_with_parsed( } fn copy_expand( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, span: Span, tt: &tt::TopSubtree, ) -> ExpandResult { @@ -547,7 +547,7 @@ fn copy_expand( } fn clone_expand( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, span: Span, tt: &tt::TopSubtree, ) -> ExpandResult { @@ -602,7 +602,7 @@ fn and_and(span: Span) -> tt::TopSubtree { } fn default_expand( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, span: Span, tt: &tt::TopSubtree, ) -> ExpandResult { @@ -667,7 +667,7 @@ fn default_expand( } fn debug_expand( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, span: Span, tt: &tt::TopSubtree, ) -> ExpandResult { @@ -740,7 +740,7 @@ fn debug_expand( } fn hash_expand( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, span: Span, tt: &tt::TopSubtree, ) -> ExpandResult { @@ -787,7 +787,7 @@ fn hash_expand( } fn eq_expand( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, span: Span, tt: &tt::TopSubtree, ) -> ExpandResult { @@ -803,7 +803,7 @@ fn eq_expand( } fn partial_eq_expand( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, span: Span, tt: &tt::TopSubtree, ) -> ExpandResult { @@ -875,7 +875,7 @@ fn self_and_other_patterns( } fn ord_expand( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, span: Span, tt: &tt::TopSubtree, ) -> ExpandResult { @@ -933,7 +933,7 @@ fn ord_expand( } fn partial_ord_expand( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, span: Span, tt: &tt::TopSubtree, ) -> ExpandResult { @@ -996,7 +996,7 @@ fn partial_ord_expand( } fn coerce_pointee_expand( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, span: Span, tt: &tt::TopSubtree, ) -> ExpandResult { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs index e12cdef495a8a..b173f44f34ab1 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; -use base_db::AnchoredPath; +use base_db::{AnchoredPath, SourceDatabase}; use cfg::CfgExpr; use either::Either; use intern::{Symbol, sym}; @@ -19,55 +19,39 @@ use syntax_bridge::syntax_node_to_token_tree; use crate::{ EditionedFileId, ExpandError, ExpandResult, MacroCallId, builtin::quote::{WithDelimiter, dollar_crate}, - db::ExpandDatabase, hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt}, name, - span_map::SpanMap, tt::{self, DelimSpan, TtElement, TtIter}, }; macro_rules! register_builtin { - ( $LAZY:ident: $(($name:ident, $kind: ident) => $expand:ident),* , $EAGER:ident: $(($e_name:ident, $e_kind: ident) => $e_expand:ident),* ) => { + ( $EXPANDER:ident: $(($name:ident, $kind: ident) => $expand:ident),* $(,)? ) => { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] - pub enum $LAZY { + pub enum $EXPANDER { $($kind),* } - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] - pub enum $EAGER { - $($e_kind),* - } - - impl BuiltinFnLikeExpander { - fn expander(&self) -> fn (&dyn ExpandDatabase, MacroCallId, &tt::TopSubtree, Span) -> ExpandResult { + impl $EXPANDER { + fn expander(&self) -> fn (&dyn SourceDatabase, MacroCallId, &tt::TopSubtree, Span) -> ExpandResult { match *self { - $( BuiltinFnLikeExpander::$kind => $expand, )* + $( Self::$kind => $expand, )* } } - } - impl EagerExpander { - fn expander(&self) -> fn (&dyn ExpandDatabase, MacroCallId, &tt::TopSubtree, Span) -> ExpandResult { - match *self { - $( EagerExpander::$e_kind => $e_expand, )* + fn find_by_name(ident: &name::Name) -> Option { + match ident { + $( id if *id == sym::$name => Some(Self::$kind), )* + _ => None, } } } - - fn find_by_name(ident: &name::Name) -> Option> { - match ident { - $( id if id == &sym::$name => Some(Either::Left(BuiltinFnLikeExpander::$kind)), )* - $( id if id == &sym::$e_name => Some(Either::Right(EagerExpander::$e_kind)), )* - _ => return None, - } - } - }; + } } impl BuiltinFnLikeExpander { pub fn expand( &self, - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, id: MacroCallId, tt: &tt::TopSubtree, span: Span, @@ -84,7 +68,7 @@ impl BuiltinFnLikeExpander { impl EagerExpander { pub fn expand( &self, - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, id: MacroCallId, tt: &tt::TopSubtree, span: Span, @@ -112,7 +96,8 @@ impl EagerExpander { pub fn find_builtin_macro( ident: &name::Name, ) -> Option> { - find_by_name(ident) + (BuiltinFnLikeExpander::find_by_name(ident).map(Either::Left)) + .or_else(|| EagerExpander::find_by_name(ident).map(Either::Right)) } register_builtin! { @@ -138,7 +123,9 @@ register_builtin! { (format_args_nl, FormatArgsNl) => format_args_nl_expand, (quote, Quote) => quote_expand, (pattern_type, PatternType) => pattern_type_expand, +} +register_builtin! { EagerExpander: (compile_error, CompileError) => compile_error_expand, (concat, Concat) => concat_expand, @@ -147,7 +134,7 @@ register_builtin! { (include_bytes, IncludeBytes) => include_bytes_expand, (include_str, IncludeStr) => include_str_expand, (env, Env) => env_expand, - (option_env, OptionEnv) => option_env_expand + (option_env, OptionEnv) => option_env_expand, } fn mk_pound(span: Span) -> tt::Leaf { @@ -155,7 +142,7 @@ fn mk_pound(span: Span) -> tt::Leaf { } fn module_path_expand( - _db: &dyn ExpandDatabase, + _db: &dyn SourceDatabase, _id: MacroCallId, _tt: &tt::TopSubtree, span: Span, @@ -167,7 +154,7 @@ fn module_path_expand( } fn line_expand( - _db: &dyn ExpandDatabase, + _db: &dyn SourceDatabase, _id: MacroCallId, _tt: &tt::TopSubtree, span: Span, @@ -182,7 +169,7 @@ fn line_expand( } fn log_syntax_expand( - _db: &dyn ExpandDatabase, + _db: &dyn SourceDatabase, _id: MacroCallId, _tt: &tt::TopSubtree, span: Span, @@ -191,7 +178,7 @@ fn log_syntax_expand( } fn trace_macros_expand( - _db: &dyn ExpandDatabase, + _db: &dyn SourceDatabase, _id: MacroCallId, _tt: &tt::TopSubtree, span: Span, @@ -200,7 +187,7 @@ fn trace_macros_expand( } fn stringify_expand( - _db: &dyn ExpandDatabase, + _db: &dyn SourceDatabase, _id: MacroCallId, tt: &tt::TopSubtree, span: Span, @@ -215,7 +202,7 @@ fn stringify_expand( } fn assert_expand( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, id: MacroCallId, tt: &tt::TopSubtree, span: Span, @@ -254,7 +241,7 @@ fn assert_expand( } fn file_expand( - _db: &dyn ExpandDatabase, + _db: &dyn SourceDatabase, _id: MacroCallId, _tt: &tt::TopSubtree, span: Span, @@ -271,7 +258,7 @@ fn file_expand( } fn format_args_expand( - _db: &dyn ExpandDatabase, + _db: &dyn SourceDatabase, _id: MacroCallId, tt: &tt::TopSubtree, span: Span, @@ -285,7 +272,7 @@ fn format_args_expand( } fn format_args_nl_expand( - _db: &dyn ExpandDatabase, + _db: &dyn SourceDatabase, _id: MacroCallId, tt: &tt::TopSubtree, span: Span, @@ -308,7 +295,7 @@ fn format_args_nl_expand( } fn asm_expand( - _db: &dyn ExpandDatabase, + _db: &dyn SourceDatabase, _id: MacroCallId, tt: &tt::TopSubtree, span: Span, @@ -323,7 +310,7 @@ fn asm_expand( } fn global_asm_expand( - _db: &dyn ExpandDatabase, + _db: &dyn SourceDatabase, _id: MacroCallId, tt: &tt::TopSubtree, span: Span, @@ -338,7 +325,7 @@ fn global_asm_expand( } fn naked_asm_expand( - _db: &dyn ExpandDatabase, + _db: &dyn SourceDatabase, _id: MacroCallId, tt: &tt::TopSubtree, span: Span, @@ -353,7 +340,7 @@ fn naked_asm_expand( } fn cfg_select_expand( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, id: MacroCallId, tt: &tt::TopSubtree, span: Span, @@ -442,7 +429,7 @@ fn cfg_select_expand( } fn cfg_expand( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, id: MacroCallId, tt: &tt::TopSubtree, span: Span, @@ -455,7 +442,7 @@ fn cfg_expand( } fn panic_expand( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, id: MacroCallId, tt: &tt::TopSubtree, span: Span, @@ -482,7 +469,7 @@ fn panic_expand( } fn unreachable_expand( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, id: MacroCallId, tt: &tt::TopSubtree, span: Span, @@ -511,7 +498,7 @@ fn unreachable_expand( } #[allow(clippy::never_loop)] -fn use_panic_2021(db: &dyn ExpandDatabase, span: Span) -> bool { +fn use_panic_2021(db: &dyn SourceDatabase, span: Span) -> bool { // To determine the edition, we check the first span up the expansion // stack that does not have #[allow_internal_unstable(edition_panic)]. // (To avoid using the edition of e.g. the assert!() or debug_assert!() definition.) @@ -533,7 +520,7 @@ fn use_panic_2021(db: &dyn ExpandDatabase, span: Span) -> bool { } fn compile_error_expand( - _db: &dyn ExpandDatabase, + _db: &dyn SourceDatabase, _id: MacroCallId, tt: &tt::TopSubtree, span: Span, @@ -553,7 +540,7 @@ fn compile_error_expand( } fn concat_expand( - _db: &dyn ExpandDatabase, + _db: &dyn SourceDatabase, _arg_id: MacroCallId, tt: &tt::TopSubtree, call_site: Span, @@ -660,7 +647,7 @@ fn concat_expand( } fn concat_bytes_expand( - _db: &dyn ExpandDatabase, + _db: &dyn SourceDatabase, _arg_id: MacroCallId, tt: &tt::TopSubtree, call_site: Span, @@ -759,7 +746,7 @@ fn concat_bytes_expand_subtree( } fn relative_file( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, call_id: MacroCallId, path_str: &str, allow_recursion: bool, @@ -812,7 +799,7 @@ fn parse_string(tt: &tt::TopSubtree) -> Result<(Symbol, Span), ExpandError> { } fn include_expand( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, arg_id: MacroCallId, tt: &tt::TopSubtree, span: Span, @@ -826,18 +813,17 @@ fn include_expand( ); } }; - let span_map = db.real_span_map(editioned_file_id); // FIXME: Parse errors ExpandResult::ok(syntax_node_to_token_tree( &editioned_file_id.parse(db).syntax_node(), - SpanMap::RealSpanMap(span_map), + crate::HirFileId::from(editioned_file_id).span_map(db), span, syntax_bridge::DocCommentDesugarMode::ProcMacro, )) } pub fn include_input_to_file_id( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, arg_id: MacroCallId, arg: &tt::TopSubtree, ) -> Result { @@ -846,7 +832,7 @@ pub fn include_input_to_file_id( } fn include_bytes_expand( - _db: &dyn ExpandDatabase, + _db: &dyn SourceDatabase, _arg_id: MacroCallId, _tt: &tt::TopSubtree, span: Span, @@ -860,7 +846,7 @@ fn include_bytes_expand( } fn include_str_expand( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, arg_id: MacroCallId, tt: &tt::TopSubtree, call_site: Span, @@ -892,13 +878,13 @@ fn include_str_expand( ExpandResult::ok(quote!(call_site =>#text)) } -fn get_env_inner(db: &dyn ExpandDatabase, arg_id: MacroCallId, key: &Symbol) -> Option { +fn get_env_inner(db: &dyn SourceDatabase, arg_id: MacroCallId, key: &Symbol) -> Option { let krate = arg_id.loc(db).krate; krate.env(db).get(key.as_str()) } fn env_expand( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, arg_id: MacroCallId, tt: &tt::TopSubtree, span: Span, @@ -936,7 +922,7 @@ fn env_expand( } fn option_env_expand( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, arg_id: MacroCallId, tt: &tt::TopSubtree, call_site: Span, @@ -963,7 +949,7 @@ fn option_env_expand( } fn quote_expand( - _db: &dyn ExpandDatabase, + _db: &dyn SourceDatabase, _arg_id: MacroCallId, _tt: &tt::TopSubtree, span: Span, @@ -989,7 +975,7 @@ fn unescape_str(s: &str) -> Cow<'_, str> { } fn pattern_type_expand( - _db: &dyn ExpandDatabase, + _db: &dyn SourceDatabase, _arg_id: MacroCallId, tt: &tt::TopSubtree, call_site: Span, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs b/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs index 81edc9f2cffaf..45a81d3b3650f 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs @@ -2,7 +2,7 @@ use std::{cell::OnceCell, ops::ControlFlow}; use ::tt::TextRange; -use base_db::Crate; +use base_db::{Crate, SourceDatabase}; use cfg::CfgExpr; use parser::T; use smallvec::SmallVec; @@ -14,7 +14,6 @@ use syntax_bridge::DocCommentDesugarMode; use crate::{ attrs::{AstPathExt, AttrId, expand_cfg_attr, is_item_tree_filtered_attr}, - db::ExpandDatabase, fixup::{self, SyntaxFixupUndoInfo}, span_map::SpanMap, tt::{self, DelimSpan, Span}, @@ -46,7 +45,7 @@ struct AstAttrToProcess { } fn macro_input_callback( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, is_derive: bool, censor_item_tree_attr_ids: &[AttrId], krate: Crate, @@ -293,7 +292,7 @@ fn macro_input_callback( } pub(crate) fn attr_macro_input_to_token_tree( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, node: &SyntaxNode, span_map: SpanMap<'_>, span: Span, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/change.rs b/src/tools/rust-analyzer/crates/hir-expand/src/change.rs index f75f45983c4f1..58808bc6c8741 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/change.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/change.rs @@ -1,9 +1,9 @@ //! Defines a unit of change that can applied to the database to get the next //! state. Changes are transactional. -use base_db::{CrateGraphBuilder, FileChange, SourceRoot}; +use base_db::{CrateGraphBuilder, FileChange, SourceDatabase, SourceRoot}; use span::FileId; -use crate::{db::ExpandDatabase, proc_macro::ProcMacrosBuilder}; +use crate::proc_macro::ProcMacrosBuilder; #[derive(Debug, Default)] pub struct ChangeWithProcMacros { @@ -12,7 +12,7 @@ pub struct ChangeWithProcMacros { } impl ChangeWithProcMacros { - pub fn apply(self, db: &mut impl ExpandDatabase) { + pub fn apply(self, db: &mut impl SourceDatabase) { let crates_id_map = self.source_change.apply(db); if let Some(proc_macros) = self.proc_macros { proc_macros.build_in( diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs deleted file mode 100644 index 90e4e0086e035..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs +++ /dev/null @@ -1,687 +0,0 @@ -//! Defines database & queries for macro expansion. - -use base_db::{Crate, SourceDatabase}; -use mbe::MatchedArmIndex; -use span::{AstIdMap, Span}; -use std::borrow::Cow; -use syntax::{AstNode, Parse, SyntaxError, SyntaxNode, SyntaxToken, T, ast}; -use syntax_bridge::{DocCommentDesugarMode, syntax_node_to_token_tree}; -use triomphe::Arc; - -use crate::{ - AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallInfo, - EagerExpander, EditionedFileId, ExpandError, ExpandResult, ExpandTo, FileRange, HirFileId, - MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind, - builtin::pseudo_derive_attr_expansion, - cfg_process::attr_macro_input_to_token_tree, - declarative::DeclarativeMacroExpander, - fixup::{self, SyntaxFixupUndoInfo}, - hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt, span_with_mixed_site_ctxt}, - proc_macro::CustomProcMacroExpander, - span_map::{ExpansionSpanMap, RealSpanMap, SpanMap}, - tt, -}; -/// This is just to ensure the types of smart_macro_arg and macro_arg are the same -type MacroArgResult = (tt::TopSubtree, SyntaxFixupUndoInfo, Span); -/// Total limit on the number of tokens produced by any macro invocation. -/// -/// If an invocation produces more tokens than this limit, it will not be stored in the database and -/// an error will be emitted. -/// -/// Actual max for `analysis-stats .` at some point: 30672. -const TOKEN_LIMIT: usize = 2_097_152; - -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub enum TokenExpander<'db> { - /// Old-style `macro_rules` or the new macros 2.0 - DeclarativeMacro(&'db DeclarativeMacroExpander), - /// Stuff like `line!` and `file!`. - BuiltIn(BuiltinFnLikeExpander), - /// Built-in eagerly expanded fn-like macros (`include!`, `concat!`, etc.) - BuiltInEager(EagerExpander), - /// `global_allocator` and such. - BuiltInAttr(BuiltinAttrExpander), - /// `derive(Copy)` and such. - BuiltInDerive(BuiltinDeriveExpander), - UnimplementedBuiltIn, - /// The thing we love the most here in rust-analyzer -- procedural macros. - ProcMacro(CustomProcMacroExpander), -} - -#[query_group::query_group] -pub trait ExpandDatabase: SourceDatabase { - #[salsa::invoke(ast_id_map)] - #[salsa::transparent] - fn ast_id_map(&self, file_id: HirFileId) -> &AstIdMap; - - #[salsa::transparent] - fn resolve_span(&self, span: Span) -> FileRange; - - #[salsa::transparent] - fn parse_or_expand(&self, file_id: HirFileId) -> SyntaxNode; - - /// Implementation for the macro case. - #[salsa::transparent] - fn parse_macro_expansion( - &self, - macro_file: MacroCallId, - ) -> &ExpandResult<(Parse, ExpansionSpanMap)>; - - #[salsa::transparent] - #[salsa::invoke(SpanMap::new)] - fn span_map(&self, file_id: HirFileId) -> SpanMap<'_>; - - #[salsa::transparent] - #[salsa::invoke(crate::span_map::expansion_span_map)] - fn expansion_span_map(&self, file_id: MacroCallId) -> &ExpansionSpanMap; - #[salsa::invoke(crate::span_map::real_span_map)] - #[salsa::transparent] - fn real_span_map(&self, file_id: EditionedFileId) -> &RealSpanMap; - - /// Lowers syntactic macro call to a token tree representation. That's a firewall - /// query, only typing in the macro call itself changes the returned - /// subtree. - #[deprecated = "calling this is incorrect, call `macro_arg_considering_derives` instead"] - #[salsa::invoke(macro_arg)] - #[salsa::transparent] - fn macro_arg(&self, id: MacroCallId) -> &MacroArgResult; - - #[salsa::transparent] - fn macro_arg_considering_derives<'db>( - &'db self, - id: MacroCallId, - kind: &MacroCallKind, - ) -> &'db MacroArgResult; - - /// Fetches the expander for this macro. - #[salsa::transparent] - #[salsa::invoke(TokenExpander::macro_expander)] - fn macro_expander(&self, id: MacroDefId) -> TokenExpander<'_>; - - /// Fetches (and compiles) the expander of this decl macro. - #[salsa::invoke(DeclarativeMacroExpander::expander)] - #[salsa::transparent] - fn decl_macro_expander( - &self, - def_crate: Crate, - id: AstId, - ) -> &DeclarativeMacroExpander; - - #[salsa::invoke(parse_macro_expansion_error)] - #[salsa::transparent] - fn parse_macro_expansion_error( - &self, - macro_call: MacroCallId, - ) -> Option>>; -} - -fn resolve_span(db: &dyn ExpandDatabase, Span { range, anchor, ctx: _ }: Span) -> FileRange { - let file_id = EditionedFileId::from_span_file_id(db, anchor.file_id); - let anchor_offset = - db.ast_id_map(file_id.into()).get_erased(anchor.ast_id).text_range().start(); - FileRange { file_id, range: range + anchor_offset } -} - -/// This expands the given macro call, but with different arguments. This is -/// used for completion, where we want to see what 'would happen' if we insert a -/// token. The `token_to_map` mapped down into the expansion, with the mapped -/// token(s) returned with their priority. -pub fn expand_speculative( - db: &dyn ExpandDatabase, - actual_macro_call: MacroCallId, - speculative_args: &SyntaxNode, - token_to_map: SyntaxToken, -) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> { - let loc = actual_macro_call.loc(db); - let (_, _, span) = *db.macro_arg_considering_derives(actual_macro_call, &loc.kind); - - let span_map = RealSpanMap::absolute(span.anchor.file_id); - let span_map = SpanMap::RealSpanMap(&span_map); - - // Build the subtree and token mapping for the speculative args - let (mut tt, undo_info) = match &loc.kind { - MacroCallKind::FnLike { .. } => ( - syntax_bridge::syntax_node_to_token_tree( - speculative_args, - span_map, - span, - if loc.def.is_proc_macro() { - DocCommentDesugarMode::ProcMacro - } else { - DocCommentDesugarMode::Mbe - }, - ), - SyntaxFixupUndoInfo::NONE, - ), - MacroCallKind::Attr { .. } if loc.def.is_attribute_derive() => ( - syntax_bridge::syntax_node_to_token_tree( - speculative_args, - span_map, - span, - DocCommentDesugarMode::ProcMacro, - ), - SyntaxFixupUndoInfo::NONE, - ), - MacroCallKind::Derive { derive_macro_id, .. } => { - let MacroCallKind::Attr { censored_attr_ids: attr_ids, .. } = - &derive_macro_id.loc(db).kind - else { - unreachable!("`derive_macro_id` should be `MacroCallKind::Attr`"); - }; - attr_macro_input_to_token_tree( - db, - speculative_args, - span_map, - span, - true, - attr_ids, - loc.krate, - ) - } - MacroCallKind::Attr { censored_attr_ids: attr_ids, .. } => attr_macro_input_to_token_tree( - db, - speculative_args, - span_map, - span, - false, - attr_ids, - loc.krate, - ), - }; - - let attr_arg = match &loc.kind { - MacroCallKind::Attr { censored_attr_ids: attr_ids, .. } => { - if loc.def.is_attribute_derive() { - // for pseudo-derive expansion we actually pass the attribute itself only - ast::Attr::cast(speculative_args.clone()) - .and_then(|attr| { - if let ast::Meta::TokenTreeMeta(meta) = attr.meta()? { - meta.token_tree() - } else { - None - } - }) - .map(|token_tree| { - let mut tree = syntax_node_to_token_tree( - token_tree.syntax(), - span_map, - span, - DocCommentDesugarMode::ProcMacro, - ); - tree.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible); - tree.set_top_subtree_delimiter_span(tt::DelimSpan::from_single(span)); - tree - }) - } else { - // Attributes may have an input token tree, build the subtree and map for this as well - // then try finding a token id for our token if it is inside this input subtree. - let item = ast::Item::cast(speculative_args.clone())?; - let (_, meta) = - attr_ids.invoc_attr().find_attr_range_with_source_opt(db, loc.krate, &item)?; - if let ast::Meta::TokenTreeMeta(meta) = meta - && let Some(tt) = meta.token_tree() - { - let mut attr_arg = syntax_bridge::syntax_node_to_token_tree( - tt.syntax(), - span_map, - span, - DocCommentDesugarMode::ProcMacro, - ); - attr_arg.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible); - Some(attr_arg) - } else { - None - } - } - } - _ => None, - }; - - // Do the actual expansion, we need to directly expand the proc macro due to the attribute args - // Otherwise the expand query will fetch the non speculative attribute args and pass those instead. - let mut speculative_expansion = match loc.def.kind { - MacroDefKind::ProcMacro(ast, expander, _) => { - let span = proc_macro_span(db, ast); - tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible); - tt.set_top_subtree_delimiter_span(tt::DelimSpan::from_single(span)); - expander.expand( - db, - loc.def.krate, - loc.krate, - &tt, - attr_arg.as_ref(), - span_with_def_site_ctxt(db, span, actual_macro_call.into(), loc.def.edition), - span_with_call_site_ctxt(db, span, actual_macro_call.into(), loc.def.edition), - span_with_mixed_site_ctxt(db, span, actual_macro_call.into(), loc.def.edition), - ) - } - MacroDefKind::BuiltInAttr(_, it) if it.is_derive() => { - pseudo_derive_attr_expansion(&tt, attr_arg.as_ref()?, span) - } - MacroDefKind::Declarative(it, _) => db - .decl_macro_expander(loc.krate, it) - .expand_unhygienic(db, &tt, loc.kind.call_style(), span), - MacroDefKind::BuiltIn(_, it) => { - it.expand(db, actual_macro_call, &tt, span).map_err(Into::into) - } - MacroDefKind::BuiltInDerive(_, it) => { - it.expand(db, actual_macro_call, &tt, span).map_err(Into::into) - } - MacroDefKind::BuiltInEager(_, it) => { - it.expand(db, actual_macro_call, &tt, span).map_err(Into::into) - } - MacroDefKind::BuiltInAttr(_, it) => it.expand(db, actual_macro_call, &tt, span), - MacroDefKind::UnimplementedBuiltIn(_) => expand_unimplemented_builtin_macro(span), - }; - - let expand_to = loc.expand_to(); - - fixup::reverse_fixups(&mut speculative_expansion.value, &undo_info); - let (node, rev_tmap) = token_tree_to_syntax_node(db, &speculative_expansion.value, expand_to); - - let syntax_node = node.syntax_node(); - let token = rev_tmap - .ranges_with_span(span_map.span_for_range(token_to_map.text_range())) - .filter_map(|(range, ctx)| syntax_node.covering_element(range).into_token().zip(Some(ctx))) - .map(|(t, ctx)| { - // prefer tokens of the same kind and text, as well as non opaque marked ones - // Note the inversion of the score here, as we want to prefer the first token in case - // of all tokens having the same score - let ranking = ctx.is_opaque(db) as u8 - + 2 * (t.kind() != token_to_map.kind()) as u8 - + 4 * ((t.text() != token_to_map.text()) as u8); - (t, ranking) - }) - .collect(); - Some((node.syntax_node(), token)) -} - -fn expand_unimplemented_builtin_macro(span: Span) -> ExpandResult { - ExpandResult::new( - tt::TopSubtree::empty(tt::DelimSpan::from_single(span)), - ExpandError::other(span, "this built-in macro is not implemented"), - ) -} - -#[salsa::tracked(lru = 1024, returns(ref))] -fn ast_id_map(db: &dyn ExpandDatabase, file_id: HirFileId) -> AstIdMap { - AstIdMap::from_source(&db.parse_or_expand(file_id)) -} - -/// Main public API -- parses a hir file, not caring whether it's a real -/// file or a macro expansion. -fn parse_or_expand(db: &dyn ExpandDatabase, file_id: HirFileId) -> SyntaxNode { - match file_id { - HirFileId::FileId(file_id) => file_id.parse(db).syntax_node(), - HirFileId::MacroFile(macro_file) => { - db.parse_macro_expansion(macro_file).value.0.syntax_node() - } - } -} - -// FIXME: We should verify that the parsed node is one of the many macro node variants we expect -// instead of having it be untyped -#[salsa_macros::tracked(returns(ref), lru = 512)] -fn parse_macro_expansion( - db: &dyn ExpandDatabase, - macro_file: MacroCallId, -) -> ExpandResult<(Parse, ExpansionSpanMap)> { - let _p = tracing::info_span!("parse_macro_expansion").entered(); - let loc = macro_file.loc(db); - let expand_to = loc.expand_to(); - let mbe::ValueResult { value: (tt, matched_arm), err } = macro_expand(db, macro_file, loc); - - let (parse, mut rev_token_map) = token_tree_to_syntax_node(db, &tt, expand_to); - rev_token_map.matched_arm = matched_arm; - - ExpandResult { value: (parse, rev_token_map), err } -} - -fn parse_macro_expansion_error( - db: &dyn ExpandDatabase, - macro_call_id: MacroCallId, -) -> Option>> { - let e: ExpandResult> = - db.parse_macro_expansion(macro_call_id).as_ref().map(|it| Arc::from(it.0.errors())); - if e.value.is_empty() && e.err.is_none() { None } else { Some(e) } -} - -pub(crate) fn parse_with_map( - db: &dyn ExpandDatabase, - file_id: HirFileId, -) -> (Parse, SpanMap<'_>) { - match file_id { - HirFileId::FileId(file_id) => { - (file_id.parse(db).to_syntax(), SpanMap::RealSpanMap(db.real_span_map(file_id))) - } - HirFileId::MacroFile(macro_file) => { - let (parse, map) = &db.parse_macro_expansion(macro_file).value; - (parse.clone(), SpanMap::ExpansionSpanMap(map)) - } - } -} - -/// This resolves the [MacroCallId] to check if it is a derive macro if so get the [macro_arg] for the derive. -/// Other wise return the [macro_arg] for the macro_call_id. -/// -/// This is not connected to the database so it does not cache the result. However, the inner [macro_arg] query is -#[allow(deprecated)] // we are macro_arg_considering_derives -fn macro_arg_considering_derives<'db>( - db: &'db dyn ExpandDatabase, - id: MacroCallId, - kind: &MacroCallKind, -) -> &'db MacroArgResult { - match kind { - // Get the macro arg for the derive macro - MacroCallKind::Derive { derive_macro_id, .. } => db.macro_arg(*derive_macro_id), - // Normal macro arg - _ => db.macro_arg(id), - } -} - -#[salsa_macros::tracked(returns(ref))] -fn macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult { - let loc = id.loc(db); - - if let MacroCallLoc { - def: MacroDefId { kind: MacroDefKind::BuiltInEager(..), .. }, - kind: MacroCallKind::FnLike { eager: Some(eager), .. }, - .. - } = &loc - { - return (eager.arg.clone(), SyntaxFixupUndoInfo::NONE, eager.span); - } - - let (parse, map) = parse_with_map(db, loc.kind.file_id()); - let root = parse.syntax_node(); - - let (is_derive, censor_item_tree_attr_ids, item_node, span) = match &loc.kind { - MacroCallKind::FnLike { ast_id, .. } => { - let node = &ast_id.to_ptr(db).to_node(&root); - let path_range = node - .path() - .map_or_else(|| node.syntax().text_range(), |path| path.syntax().text_range()); - let span = map.span_for_range(path_range); - - let dummy_tt = |kind| { - ( - tt::TopSubtree::from_token_trees( - tt::Delimiter { open: span, close: span, kind }, - tt::TokenTreesView::empty(), - ), - SyntaxFixupUndoInfo::default(), - span, - ) - }; - - let Some(tt) = node.token_tree() else { - return dummy_tt(tt::DelimiterKind::Invisible); - }; - let first = tt.left_delimiter_token().map(|it| it.kind()).unwrap_or(T!['(']); - let last = tt.right_delimiter_token().map(|it| it.kind()).unwrap_or(T![.]); - - let mismatched_delimiters = !matches!( - (first, last), - (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) - ); - if mismatched_delimiters { - // Don't expand malformed (unbalanced) macro invocations. This is - // less than ideal, but trying to expand unbalanced macro calls - // sometimes produces pathological, deeply nested code which breaks - // all kinds of things. - // - // So instead, we'll return an empty subtree here - cov_mark::hit!(issue9358_bad_macro_stack_overflow); - - let kind = match first { - _ if loc.def.is_proc_macro() => tt::DelimiterKind::Invisible, - T!['('] => tt::DelimiterKind::Parenthesis, - T!['['] => tt::DelimiterKind::Bracket, - T!['{'] => tt::DelimiterKind::Brace, - _ => tt::DelimiterKind::Invisible, - }; - return dummy_tt(kind); - } - - let mut tt = syntax_bridge::syntax_node_to_token_tree( - tt.syntax(), - map, - span, - if loc.def.is_proc_macro() { - DocCommentDesugarMode::ProcMacro - } else { - DocCommentDesugarMode::Mbe - }, - ); - if loc.def.is_proc_macro() { - // proc macros expect their inputs without parentheses, MBEs expect it with them included - tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible); - } - return (tt, SyntaxFixupUndoInfo::NONE, span); - } - // MacroCallKind::Derive should not be here. As we are getting the argument for the derive macro - MacroCallKind::Derive { .. } => { - unreachable!("`ExpandDatabase::macro_arg` called with `MacroCallKind::Derive`") - } - MacroCallKind::Attr { ast_id, censored_attr_ids: attr_ids, .. } => { - let node = ast_id.to_ptr(db).to_node(&root); - let (_, attr) = attr_ids.invoc_attr().find_attr_range_with_source(db, loc.krate, &node); - let range = attr - .path() - .map(|path| path.syntax().text_range()) - .unwrap_or_else(|| attr.syntax().text_range()); - let span = map.span_for_range(range); - - let is_derive = matches!(loc.def.kind, MacroDefKind::BuiltInAttr(_, expander) if expander.is_derive()); - (is_derive, &**attr_ids, node, span) - } - }; - - let (mut tt, undo_info) = attr_macro_input_to_token_tree( - db, - item_node.syntax(), - map, - span, - is_derive, - censor_item_tree_attr_ids, - loc.krate, - ); - - if loc.def.is_proc_macro() { - // proc macros expect their inputs without parentheses, MBEs expect it with them included - tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible); - } - - (tt, undo_info, span) -} - -impl<'db> TokenExpander<'db> { - fn macro_expander(db: &'db dyn ExpandDatabase, id: MacroDefId) -> TokenExpander<'db> { - match id.kind { - MacroDefKind::Declarative(ast_id, _) => { - TokenExpander::DeclarativeMacro(db.decl_macro_expander(id.krate, ast_id)) - } - MacroDefKind::BuiltIn(_, expander) => TokenExpander::BuiltIn(expander), - MacroDefKind::BuiltInAttr(_, expander) => TokenExpander::BuiltInAttr(expander), - MacroDefKind::BuiltInDerive(_, expander) => TokenExpander::BuiltInDerive(expander), - MacroDefKind::BuiltInEager(_, expander) => TokenExpander::BuiltInEager(expander), - MacroDefKind::ProcMacro(_, expander, _) => TokenExpander::ProcMacro(expander), - MacroDefKind::UnimplementedBuiltIn(_) => TokenExpander::UnimplementedBuiltIn, - } - } -} - -fn macro_expand<'db>( - db: &'db dyn ExpandDatabase, - macro_call_id: MacroCallId, - loc: &MacroCallLoc, -) -> ExpandResult<(Cow<'db, tt::TopSubtree>, MatchedArmIndex)> { - let _p = tracing::info_span!("macro_expand").entered(); - - let (ExpandResult { value: (tt, matched_arm), err }, span) = match loc.def.kind { - MacroDefKind::ProcMacro(..) => { - return expand_proc_macro(db, macro_call_id) - .as_ref() - .map(|it| (Cow::Borrowed(it), None)); - } - _ => { - let (macro_arg, undo_info, span) = - db.macro_arg_considering_derives(macro_call_id, &loc.kind); - let span = *span; - - let arg = macro_arg; - let res = match loc.def.kind { - MacroDefKind::Declarative(id, _) => { - db.decl_macro_expander(loc.def.krate, id).expand(db, arg, macro_call_id, span) - } - MacroDefKind::BuiltIn(_, it) => { - it.expand(db, macro_call_id, arg, span).map_err(Into::into).zip_val(None) - } - MacroDefKind::BuiltInDerive(_, it) => { - it.expand(db, macro_call_id, arg, span).map_err(Into::into).zip_val(None) - } - MacroDefKind::UnimplementedBuiltIn(_) => { - expand_unimplemented_builtin_macro(span).zip_val(None) - } - MacroDefKind::BuiltInEager(_, it) => { - // This might look a bit odd, but we do not expand the inputs to eager macros here. - // Eager macros inputs are expanded, well, eagerly when we collect the macro calls. - // That kind of expansion uses the ast id map of an eager macros input though which goes through - // the HirFileId machinery. As eager macro inputs are assigned a macro file id that query - // will end up going through here again, whereas we want to just want to inspect the raw input. - // As such we just return the input subtree here. - let eager = match &loc.kind { - MacroCallKind::FnLike { eager: None, .. } => { - return ExpandResult::ok(Cow::Borrowed(macro_arg)).zip_val(None); - } - MacroCallKind::FnLike { eager: Some(eager), .. } => Some(&**eager), - _ => None, - }; - - let mut res = it.expand(db, macro_call_id, arg, span).map_err(Into::into); - - if let Some(EagerCallInfo { error, .. }) = eager { - // FIXME: We should report both errors! - res.err = error.clone().or(res.err); - } - res.zip_val(None) - } - MacroDefKind::BuiltInAttr(_, it) => { - let mut res = it.expand(db, macro_call_id, arg, span); - fixup::reverse_fixups(&mut res.value, undo_info); - res.zip_val(None) - } - MacroDefKind::ProcMacro(_, _, _) => unreachable!(), - }; - (res, span) - } - }; - - // Skip checking token tree limit for include! macro call - if !loc.def.is_include() { - // Set a hard limit for the expanded tt - if let Err(value) = check_tt_count(&tt) { - return value - .map(|()| Cow::Owned(tt::TopSubtree::empty(tt::DelimSpan::from_single(span)))) - .zip_val(matched_arm); - } - } - - ExpandResult { value: (Cow::Owned(tt), matched_arm), err } -} - -/// Retrieves the span to be used for a proc-macro expansions spans. -/// This is a firewall query as it requires parsing the file, which we don't want proc-macros to -/// directly depend on as that would cause to frequent invalidations, mainly because of the -/// parse queries being LRU cached. If they weren't the invalidations would only happen if the -/// user wrote in the file that defines the proc-macro. -fn proc_macro_span(db: &dyn ExpandDatabase, ast: AstId) -> Span { - #[salsa::tracked] - fn proc_macro_span(db: &dyn ExpandDatabase, ast: AstId, _: ()) -> Span { - let root = db.parse_or_expand(ast.file_id); - let ast_id_map = db.ast_id_map(ast.file_id); - let span_map = db.span_map(ast.file_id); - - let node = ast_id_map.get(ast.value).to_node(&root); - let range = ast::HasName::name(&node) - .map_or_else(|| node.syntax().text_range(), |name| name.syntax().text_range()); - span_map.span_for_range(range) - } - proc_macro_span(db, ast, ()) -} - -/// Special case of [`macro_expand`] for procedural macros. We can't LRU -/// proc macros, since they are not deterministic in general, and -/// non-determinism breaks salsa in a very, very, very bad way. -/// @edwin0cheng heroically debugged this once! See #4315 for details -#[salsa_macros::tracked(returns(ref))] -fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult { - let loc = id.loc(db); - let (macro_arg, undo_info, span) = db.macro_arg_considering_derives(id, &loc.kind); - - let (ast, expander) = match loc.def.kind { - MacroDefKind::ProcMacro(ast, expander, _) => (ast, expander), - _ => unreachable!(), - }; - - let attr_arg = match &loc.kind { - MacroCallKind::Attr { attr_args: Some(attr_args), .. } => Some(&**attr_args), - _ => None, - }; - - let ExpandResult { value: mut tt, err } = { - let span = proc_macro_span(db, ast); - expander.expand( - db, - loc.def.krate, - loc.krate, - macro_arg, - attr_arg, - span_with_def_site_ctxt(db, span, id.into(), loc.def.edition), - span_with_call_site_ctxt(db, span, id.into(), loc.def.edition), - span_with_mixed_site_ctxt(db, span, id.into(), loc.def.edition), - ) - }; - - // Set a hard limit for the expanded tt - if let Err(value) = check_tt_count(&tt) { - return value.map(|()| tt::TopSubtree::empty(tt::DelimSpan::from_single(*span))); - } - - fixup::reverse_fixups(&mut tt, undo_info); - - ExpandResult { value: tt, err } -} - -pub(crate) fn token_tree_to_syntax_node( - db: &dyn ExpandDatabase, - tt: &tt::TopSubtree, - expand_to: ExpandTo, -) -> (Parse, ExpansionSpanMap) { - let entry_point = match expand_to { - ExpandTo::Statements => syntax_bridge::TopEntryPoint::MacroStmts, - ExpandTo::Items => syntax_bridge::TopEntryPoint::MacroItems, - ExpandTo::Pattern => syntax_bridge::TopEntryPoint::Pattern, - ExpandTo::Type => syntax_bridge::TopEntryPoint::Type, - ExpandTo::Expr => syntax_bridge::TopEntryPoint::Expr, - }; - syntax_bridge::token_tree_to_syntax_node(tt, entry_point, &mut |ctx| ctx.edition(db)) -} - -fn check_tt_count(tt: &tt::TopSubtree) -> Result<(), ExpandResult<()>> { - let tt = tt.top_subtree(); - let count = tt.count(); - if count <= TOKEN_LIMIT { - Ok(()) - } else { - Err(ExpandResult { - value: (), - err: Some(ExpandError::other( - tt.delimiter.open, - format!( - "macro invocation exceeds token limit: produced {count} tokens, limit is {TOKEN_LIMIT}", - ), - )), - }) - } -} diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs index 107014164e78d..a3c9047d764f7 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs @@ -2,7 +2,7 @@ use std::ops::ControlFlow; -use base_db::Crate; +use base_db::{Crate, SourceDatabase}; use span::{Edition, Span, SyntaxContext}; use stdx::TupleExt; use syntax::{ @@ -15,7 +15,6 @@ use crate::{ AstId, ExpandError, ExpandErrorKind, ExpandResult, HirFileId, Lookup, MacroCallId, MacroCallStyle, attrs::{AstKeyValueMetaExt, AstPathExt, expand_cfg_attr}, - db::ExpandDatabase, hygiene::{Transparency, apply_mark}, tt, }; @@ -31,7 +30,7 @@ pub struct DeclarativeMacroExpander { impl DeclarativeMacroExpander { pub fn expand( &self, - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, tt: &tt::TopSubtree, call_id: MacroCallId, span: Span, @@ -60,7 +59,7 @@ impl DeclarativeMacroExpander { pub fn expand_unhygienic( &self, - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, tt: &tt::TopSubtree, call_style: MacroCallStyle, call_site: Span, @@ -80,14 +79,17 @@ impl DeclarativeMacroExpander { } #[salsa::tracked] -impl DeclarativeMacroExpander { +impl AstId { + /// Fetches (and compiles) the expander of this decl macro. #[salsa::tracked(returns(ref))] - pub(crate) fn expander( - db: &dyn ExpandDatabase, + pub fn decl_macro_expander( + self, + db: &dyn SourceDatabase, def_crate: Crate, - id: AstId, ) -> DeclarativeMacroExpander { - let (root, map) = crate::db::parse_with_map(db, id.file_id); + let id = self; + let (root, map) = id.file_id.parse_with_map(db); + let root = root.syntax_node(); let transparency = |node: ast::AnyHasAttrs| { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs index f8a560834adb3..22413e7851dbe 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs @@ -18,7 +18,7 @@ //! //! //! See the full discussion : -use base_db::Crate; +use base_db::{Crate, SourceDatabase}; use span::SyntaxContext; use syntax::{ AstPtr, Parse, SyntaxElement, SyntaxNode, TextSize, WalkEvent, syntax_editor::SyntaxEditor, @@ -29,7 +29,6 @@ use crate::{ AstId, EagerCallInfo, ExpandError, ExpandResult, ExpandTo, ExpansionSpanMap, InFile, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind, ast::{self, AstNode}, - db::ExpandDatabase, mod_path::ModPath, }; @@ -39,7 +38,7 @@ pub type EagerCallBackFn<'a> = &'a mut dyn FnMut( ); pub fn expand_eager_macro_input( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, krate: Crate, macro_call: &ast::MacroCall, ast_id: AstId, @@ -62,9 +61,9 @@ pub fn expand_eager_macro_input( }; let arg_id = MacroCallId::new(db, loc); #[allow(deprecated)] // builtin eager macros are never derives - let (_, _, span) = db.macro_arg(arg_id); + let (_, _, span) = arg_id.macro_arg(db); let ExpandResult { value: (arg_exp, arg_exp_map), err: parse_err } = - db.parse_macro_expansion(arg_id); + arg_id.parse_macro_expansion(db); let mut arg_map = ExpansionSpanMap::empty(); @@ -119,7 +118,7 @@ pub fn expand_eager_macro_input( } fn lazy_expand<'db>( - db: &'db dyn ExpandDatabase, + db: &'db dyn SourceDatabase, def: &MacroDefId, macro_call: &ast::MacroCall, ast_id: AstId, @@ -136,13 +135,13 @@ fn lazy_expand<'db>( ); eager_callback(ast_id.map(|ast_id| (AstPtr::new(macro_call), ast_id)), id); - db.parse_macro_expansion(id) + id.parse_macro_expansion(db) .as_ref() .map(|parse| (InFile::new(id.into(), parse.0.clone()), &parse.1)) } fn eager_macro_recur( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, span_map: &ExpansionSpanMap, expanded_map: &mut ExpansionSpanMap, mut offset: TextSize, @@ -206,7 +205,7 @@ fn eager_macro_recur( continue; } }; - let ast_id = db.ast_id_map(curr.file_id).ast_id(&call); + let ast_id = curr.file_id.ast_id_map(db).ast_id(&call); let ExpandResult { value, err } = match def.kind { MacroDefKind::BuiltInEager(..) => { let ExpandResult { value, err } = expand_eager_macro_input( @@ -226,14 +225,14 @@ fn eager_macro_recur( call_id, ); let ExpandResult { value: (parse, map), err: err2 } = - db.parse_macro_expansion(call_id); + call_id.parse_macro_expansion(db); map.iter().for_each(|(o, span)| expanded_map.push(o + offset, span)); let syntax_node = parse.syntax_node(); ExpandResult { value: Some(( - syntax_node.clone_for_update(), + syntax_node.clone(), offset + syntax_node.text_range().len(), )), err: err.clone().or_else(|| err2.clone()), diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs index a4c206156da34..3524e0cb090cd 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs @@ -1,14 +1,14 @@ //! Things to wrap other things in file ids. use std::borrow::Borrow; +use base_db::SourceDatabase; use either::Either; use span::{AstIdNode, ErasedFileAstId, FileAstId, FileId, SyntaxContext}; use syntax::{AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextSize}; use crate::{ - EditionedFileId, HirFileId, MacroCallId, MacroKind, - db::{self, ExpandDatabase}, - map_node_range_up, map_node_range_up_rooted, span_for_offset, + EditionedFileId, HirFileId, MacroCallId, MacroKind, map_node_range_up, + map_node_range_up_rooted, span_for_offset, }; /// `InFile` stores a value of `T` inside a particular file/syntax tree. @@ -38,7 +38,7 @@ pub type FilePosition = FilePositionWrapper; impl FilePosition { #[inline] - pub fn into_file_id(self, db: &dyn ExpandDatabase) -> FilePositionWrapper { + pub fn into_file_id(self, db: &dyn SourceDatabase) -> FilePositionWrapper { FilePositionWrapper { file_id: self.file_id.file_id(db), offset: self.offset } } } @@ -72,17 +72,17 @@ pub type FileRange = FileRangeWrapper; impl FileRange { #[inline] - pub fn into_file_id(self, db: &dyn ExpandDatabase) -> FileRangeWrapper { + pub fn into_file_id(self, db: &dyn SourceDatabase) -> FileRangeWrapper { FileRangeWrapper { file_id: self.file_id.file_id(db), range: self.range } } #[inline] - pub fn file_text(self, db: &dyn ExpandDatabase) -> &triomphe::Arc { + pub fn file_text(self, db: &dyn SourceDatabase) -> &triomphe::Arc { db.file_text(self.file_id.file_id(db)).text(db) } #[inline] - pub fn text(self, db: &dyn ExpandDatabase) -> &str { + pub fn text(self, db: &dyn SourceDatabase) -> &str { &self.file_text(db)[self.range] } } @@ -93,17 +93,17 @@ impl FileRange { pub type AstId = crate::InFile>; impl AstId { - pub fn to_node(&self, db: &dyn ExpandDatabase) -> N { - self.to_ptr(db).to_node(&db.parse_or_expand(self.file_id)) + pub fn to_node(&self, db: &dyn SourceDatabase) -> N { + self.to_ptr(db).to_node(&self.file_id.parse_or_expand(db)) } - pub fn to_range(&self, db: &dyn ExpandDatabase) -> TextRange { + pub fn to_range(&self, db: &dyn SourceDatabase) -> TextRange { self.to_ptr(db).text_range() } - pub fn to_in_file_node(&self, db: &dyn ExpandDatabase) -> crate::InFile { - crate::InFile::new(self.file_id, self.to_ptr(db).to_node(&db.parse_or_expand(self.file_id))) + pub fn to_in_file_node(&self, db: &dyn SourceDatabase) -> crate::InFile { + crate::InFile::new(self.file_id, self.to_ptr(db).to_node(&self.file_id.parse_or_expand(db))) } - pub fn to_ptr(&self, db: &dyn ExpandDatabase) -> AstPtr { - db.ast_id_map(self.file_id).get(self.value) + pub fn to_ptr(&self, db: &dyn SourceDatabase) -> AstPtr { + self.file_id.ast_id_map(db).get(self.value) } pub fn erase(&self) -> ErasedAstId { crate::InFile::new(self.file_id, self.value.erase()) @@ -120,11 +120,11 @@ impl AstId { pub type ErasedAstId = crate::InFile; impl ErasedAstId { - pub fn to_range(&self, db: &dyn ExpandDatabase) -> TextRange { + pub fn to_range(&self, db: &dyn SourceDatabase) -> TextRange { self.to_ptr(db).text_range() } - pub fn to_ptr(&self, db: &dyn ExpandDatabase) -> SyntaxNodePtr { - db.ast_id_map(self.file_id).get_erased(self.value) + pub fn to_ptr(&self, db: &dyn SourceDatabase) -> SyntaxNodePtr { + self.file_id.ast_id_map(db).get_erased(self.value) } } @@ -203,35 +203,35 @@ impl InFileWrapper> { // endregion:transpose impls trait FileIdToSyntax: Copy { - fn file_syntax(self, db: &dyn db::ExpandDatabase) -> SyntaxNode; + fn file_syntax(self, db: &dyn SourceDatabase) -> SyntaxNode; } impl FileIdToSyntax for EditionedFileId { - fn file_syntax(self, db: &dyn db::ExpandDatabase) -> SyntaxNode { + fn file_syntax(self, db: &dyn SourceDatabase) -> SyntaxNode { self.parse(db).syntax_node() } } impl FileIdToSyntax for MacroCallId { - fn file_syntax(self, db: &dyn db::ExpandDatabase) -> SyntaxNode { - db.parse_macro_expansion(self).value.0.syntax_node() + fn file_syntax(self, db: &dyn SourceDatabase) -> SyntaxNode { + self.parse_macro_expansion(db).value.0.syntax_node() } } impl FileIdToSyntax for HirFileId { - fn file_syntax(self, db: &dyn db::ExpandDatabase) -> SyntaxNode { - db.parse_or_expand(self) + fn file_syntax(self, db: &dyn SourceDatabase) -> SyntaxNode { + self.parse_or_expand(db) } } #[allow(private_bounds)] impl InFileWrapper { - pub fn file_syntax(&self, db: &dyn db::ExpandDatabase) -> SyntaxNode { + pub fn file_syntax(&self, db: &dyn SourceDatabase) -> SyntaxNode { FileIdToSyntax::file_syntax(self.file_id, db) } } #[allow(private_bounds)] impl InFileWrapper> { - pub fn to_node(&self, db: &dyn ExpandDatabase) -> N { + pub fn to_node(&self, db: &dyn SourceDatabase) -> N { self.value.to_node(&self.file_syntax(db)) } } @@ -262,7 +262,7 @@ impl> InFileWrapper { impl> InFile { pub fn parent_ancestors_with_macros( self, - db: &dyn db::ExpandDatabase, + db: &dyn SourceDatabase, ) -> impl Iterator> + '_ { let succ = move |node: &InFile| match node.value.parent() { Some(parent) => Some(node.with_value(parent)), @@ -281,7 +281,7 @@ impl> InFile { pub fn ancestors_with_macros( self, - db: &dyn db::ExpandDatabase, + db: &dyn SourceDatabase, ) -> impl Iterator> + '_ { let succ = move |node: &InFile| match node.value.parent() { Some(parent) => Some(node.with_value(parent)), @@ -310,21 +310,18 @@ impl> InFile { /// /// For attributes and derives, this will point back to the attribute only. /// For the entire item use `InFile::original_file_range_full`. - pub fn original_file_range_rooted(self, db: &dyn db::ExpandDatabase) -> FileRange { + pub fn original_file_range_rooted(self, db: &dyn SourceDatabase) -> FileRange { self.borrow().map(SyntaxNode::text_range).original_node_file_range_rooted(db) } /// Falls back to the macro call range if the node cannot be mapped up fully. - pub fn original_file_range_with_macro_call_input( - self, - db: &dyn db::ExpandDatabase, - ) -> FileRange { + pub fn original_file_range_with_macro_call_input(self, db: &dyn SourceDatabase) -> FileRange { self.borrow().map(SyntaxNode::text_range).original_node_file_range_with_macro_call_input(db) } pub fn original_syntax_node_rooted( self, - db: &dyn db::ExpandDatabase, + db: &dyn SourceDatabase, ) -> Option> { // This kind of upmapping can only be achieved in attribute expanded files, // as we don't have node inputs otherwise and therefore can't find an `N` node in the input @@ -342,7 +339,7 @@ impl> InFile { let FileRange { file_id: editioned_file_id, range } = map_node_range_up_rooted( db, - db.expansion_span_map(file_id), + file_id.expansion_span_map(db), self.value.borrow().text_range(), )?; @@ -362,30 +359,27 @@ impl InFile<&SyntaxNode> { /// Attempts to map the syntax node back up its macro calls. pub fn original_file_range_opt( self, - db: &dyn db::ExpandDatabase, + db: &dyn SourceDatabase, ) -> Option<(FileRange, SyntaxContext)> { self.borrow().map(SyntaxNode::text_range).original_node_file_range_opt(db) } } impl InMacroFile { - pub fn upmap_once( - self, - db: &dyn db::ExpandDatabase, - ) -> InFile> { + pub fn upmap_once(self, db: &dyn SourceDatabase) -> InFile> { self.file_id.expansion_info(db).map_range_up_once(db, self.value.text_range()) } } impl InFile { /// Falls back to the macro call range if the node cannot be mapped up fully. - pub fn original_file_range(self, db: &dyn db::ExpandDatabase) -> FileRange { + pub fn original_file_range(self, db: &dyn SourceDatabase) -> FileRange { match self.file_id { HirFileId::FileId(file_id) => FileRange { file_id, range: self.value.text_range() }, HirFileId::MacroFile(mac_file) => { let (range, ctxt) = span_for_offset( db, - db.expansion_span_map(mac_file), + mac_file.expansion_span_map(db), self.value.text_range().start(), ); @@ -403,7 +397,7 @@ impl InFile { } /// Attempts to map the syntax node back up its macro calls. - pub fn original_file_range_opt(self, db: &dyn db::ExpandDatabase) -> Option { + pub fn original_file_range_opt(self, db: &dyn SourceDatabase) -> Option { match self.file_id { HirFileId::FileId(file_id) => { Some(FileRange { file_id, range: self.value.text_range() }) @@ -411,7 +405,7 @@ impl InFile { HirFileId::MacroFile(mac_file) => { let (range, ctxt) = span_for_offset( db, - db.expansion_span_map(mac_file), + mac_file.expansion_span_map(db), self.value.text_range().start(), ); @@ -424,22 +418,19 @@ impl InFile { } impl InMacroFile { - pub fn original_file_range(self, db: &dyn db::ExpandDatabase) -> (FileRange, SyntaxContext) { - span_for_offset(db, db.expansion_span_map(self.file_id), self.value) + pub fn original_file_range(self, db: &dyn SourceDatabase) -> (FileRange, SyntaxContext) { + span_for_offset(db, self.file_id.expansion_span_map(db), self.value) } } impl InFile { - pub fn original_node_file_range( - self, - db: &dyn db::ExpandDatabase, - ) -> (FileRange, SyntaxContext) { + pub fn original_node_file_range(self, db: &dyn SourceDatabase) -> (FileRange, SyntaxContext) { match self.file_id { HirFileId::FileId(file_id) => { (FileRange { file_id, range: self.value }, SyntaxContext::root(file_id.edition(db))) } HirFileId::MacroFile(mac_file) => { - match map_node_range_up(db, db.expansion_span_map(mac_file), self.value) { + match map_node_range_up(db, mac_file.expansion_span_map(db), self.value) { Some(it) => it, None => { let loc = mac_file.loc(db); @@ -453,11 +444,11 @@ impl InFile { } } - pub fn original_node_file_range_rooted(self, db: &dyn db::ExpandDatabase) -> FileRange { + pub fn original_node_file_range_rooted(self, db: &dyn SourceDatabase) -> FileRange { match self.file_id { HirFileId::FileId(file_id) => FileRange { file_id, range: self.value }, HirFileId::MacroFile(mac_file) => { - match map_node_range_up_rooted(db, db.expansion_span_map(mac_file), self.value) { + match map_node_range_up_rooted(db, mac_file.expansion_span_map(db), self.value) { Some(it) => it, _ => { let loc = mac_file.loc(db); @@ -470,12 +461,12 @@ impl InFile { pub fn original_node_file_range_with_macro_call_input( self, - db: &dyn db::ExpandDatabase, + db: &dyn SourceDatabase, ) -> FileRange { match self.file_id { HirFileId::FileId(file_id) => FileRange { file_id, range: self.value }, HirFileId::MacroFile(mac_file) => { - match map_node_range_up_rooted(db, db.expansion_span_map(mac_file), self.value) { + match map_node_range_up_rooted(db, mac_file.expansion_span_map(db), self.value) { Some(it) => it, _ => { let loc = mac_file.loc(db); @@ -488,7 +479,7 @@ impl InFile { pub fn original_node_file_range_opt( self, - db: &dyn db::ExpandDatabase, + db: &dyn SourceDatabase, ) -> Option<(FileRange, SyntaxContext)> { match self.file_id { HirFileId::FileId(file_id) => Some(( @@ -496,26 +487,23 @@ impl InFile { SyntaxContext::root(file_id.edition(db)), )), HirFileId::MacroFile(mac_file) => { - map_node_range_up(db, db.expansion_span_map(mac_file), self.value) + map_node_range_up(db, mac_file.expansion_span_map(db), self.value) } } } - pub fn original_node_file_range_rooted_opt( - self, - db: &dyn db::ExpandDatabase, - ) -> Option { + pub fn original_node_file_range_rooted_opt(self, db: &dyn SourceDatabase) -> Option { match self.file_id { HirFileId::FileId(file_id) => Some(FileRange { file_id, range: self.value }), HirFileId::MacroFile(mac_file) => { - map_node_range_up_rooted(db, db.expansion_span_map(mac_file), self.value) + map_node_range_up_rooted(db, mac_file.expansion_span_map(db), self.value) } } } } impl InFile { - pub fn original_ast_node_rooted(self, db: &dyn db::ExpandDatabase) -> Option> { + pub fn original_ast_node_rooted(self, db: &dyn SourceDatabase) -> Option> { // This kind of upmapping can only be achieved in attribute expanded files, // as we don't have node inputs otherwise and therefore can't find an `N` node in the input let file_id = match self.file_id { @@ -530,7 +518,7 @@ impl InFile { let FileRange { file_id: editioned_file_id, range } = map_node_range_up_rooted( db, - db.expansion_span_map(file_id), + file_id.expansion_span_map(db), self.value.syntax().text_range(), )?; diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs index 1cf8ce2a57f95..e471c6d2bd3e2 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs @@ -26,12 +26,12 @@ use std::convert::identity; use span::{Edition, MacroCallId, Span, SyntaxContext}; -use crate::db::ExpandDatabase; +use base_db::SourceDatabase; pub use span::Transparency; pub fn span_with_def_site_ctxt( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, span: Span, expn_id: MacroCallId, edition: Edition, @@ -40,7 +40,7 @@ pub fn span_with_def_site_ctxt( } pub fn span_with_call_site_ctxt( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, span: Span, expn_id: MacroCallId, edition: Edition, @@ -49,7 +49,7 @@ pub fn span_with_call_site_ctxt( } pub fn span_with_mixed_site_ctxt( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, span: Span, expn_id: MacroCallId, edition: Edition, @@ -58,7 +58,7 @@ pub fn span_with_mixed_site_ctxt( } fn span_with_ctxt_from_mark( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, span: Span, expn_id: MacroCallId, transparency: Transparency, @@ -71,7 +71,7 @@ fn span_with_ctxt_from_mark( } pub(super) fn apply_mark( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, ctxt: span::SyntaxContext, call_id: span::MacroCallId, transparency: Transparency, @@ -108,7 +108,7 @@ pub(super) fn apply_mark( } fn apply_mark_internal( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, ctxt: SyntaxContext, call_id: MacroCallId, transparency: Transparency, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index 0ba04bc395b40..511b94d7418f1 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -12,7 +12,6 @@ pub use intern; pub mod attrs; pub mod builtin; pub mod change; -pub mod db; pub mod declarative; pub mod eager; pub mod files; @@ -28,33 +27,36 @@ mod fixup; mod prettify_macro_expansion_; use salsa::plumbing::{AsId, FromId}; -use stdx::TupleExt; use thin_vec::ThinVec; use triomphe::Arc; use core::fmt; -use std::{hash::Hash, ops}; +use std::{borrow::Cow, ops}; -use base_db::Crate; +use base_db::{Crate, SourceDatabase}; use either::Either; +use mbe::MatchedArmIndex; use span::{ - Edition, ErasedFileAstId, FileAstId, NO_DOWNMAP_ERASED_FILE_AST_ID_MARKER, Span, SyntaxContext, + AstIdMap, Edition, ErasedFileAstId, FileAstId, NO_DOWNMAP_ERASED_FILE_AST_ID_MARKER, Span, + SyntaxContext, }; use syntax::{ - SyntaxNode, SyntaxToken, TextRange, TextSize, + Parse, SyntaxError, SyntaxNode, SyntaxToken, T, TextRange, TextSize, ast::{self, AstNode}, }; +use syntax_bridge::{DocCommentDesugarMode, syntax_node_to_token_tree}; use crate::{ attrs::AttrId, builtin::{ BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerExpander, - include_input_to_file_id, + include_input_to_file_id, pseudo_derive_attr_expansion, }, - db::ExpandDatabase, - mod_path::ModPath, + cfg_process::attr_macro_input_to_token_tree, + fixup::SyntaxFixupUndoInfo, + hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt, span_with_mixed_site_ctxt}, proc_macro::{CustomProcMacroExpander, ProcMacroKind, ProcMacros}, - span_map::{ExpansionSpanMap, SpanMap}, + span_map::{ExpansionSpanMap, RealSpanMap, SpanMap}, }; pub use crate::{ @@ -67,21 +69,31 @@ pub use mbe::{DeclarativeMacro, MacroCallStyle, MacroCallStyles, ValueResult}; pub use tt; +/// This is just to ensure the types of [`MacroCallId::macro_arg_considering_derives`] +/// and [`MacroCallId::macro_arg`] are the same. +type MacroArgResult = (tt::TopSubtree, SyntaxFixupUndoInfo, Span); + +/// Total limit on the number of tokens produced by any macro invocation. +/// +/// If an invocation produces more tokens than this limit, it will not be stored in the database and +/// an error will be emitted. +/// +/// Actual max for `analysis-stats .` at some point: 30672. +const TOKEN_LIMIT: usize = 2_097_152; + #[macro_export] macro_rules! impl_intern_lookup { - ($db:ident, $id:ident, $loc:ident) => { + ($id:ident, $loc:ident) => { impl $crate::Intern for $loc { - type Database = dyn $db; type ID = $id; - fn intern(self, db: &Self::Database) -> Self::ID { + fn intern(self, db: &dyn ::base_db::SourceDatabase) -> Self::ID { $id::new(db, self) } } impl $crate::Lookup for $id { - type Database = dyn $db; type Data = $loc; - fn lookup<'db>(&self, db: &'db Self::Database) -> &'db Self::Data { + fn lookup<'db>(&self, db: &'db dyn ::base_db::SourceDatabase) -> &'db Self::Data { self.loc(db) } } @@ -90,18 +102,16 @@ macro_rules! impl_intern_lookup { // ideally these would be defined in base-db, but the orphan rule doesn't let us pub trait Intern { - type Database: ?Sized; type ID; - fn intern(self, db: &Self::Database) -> Self::ID; + fn intern(self, db: &dyn SourceDatabase) -> Self::ID; } pub trait Lookup { - type Database: ?Sized; type Data; - fn lookup<'db>(&self, db: &'db Self::Database) -> &'db Self::Data; + fn lookup<'db>(&self, db: &'db dyn SourceDatabase) -> &'db Self::Data; } -impl_intern_lookup!(ExpandDatabase, MacroCallId, MacroCallLoc); +impl_intern_lookup!(MacroCallId, MacroCallLoc); pub type ExpandResult = ValueResult; @@ -124,7 +134,7 @@ impl ExpandError { self.inner.1 } - pub fn render_to_string(&self, db: &dyn ExpandDatabase) -> RenderedExpandError { + pub fn render_to_string(&self, db: &dyn SourceDatabase) -> RenderedExpandError { self.inner.0.render_to_string(db) } } @@ -163,7 +173,7 @@ impl RenderedExpandError { } impl ExpandErrorKind { - pub fn render_to_string(&self, db: &dyn ExpandDatabase) -> RenderedExpandError { + pub fn render_to_string(&self, db: &dyn SourceDatabase) -> RenderedExpandError { match self { ExpandErrorKind::ProcMacroAttrExpansionDisabled => RenderedExpandError { message: "procedural attribute macro expansion is disabled".to_owned(), @@ -378,75 +388,6 @@ impl MacroCallKind { } } -impl HirFileId { - pub fn edition(self, db: &dyn ExpandDatabase) -> Edition { - match self { - HirFileId::FileId(file_id) => file_id.edition(db), - HirFileId::MacroFile(m) => m.loc(db).def.edition, - } - } - pub fn original_file(self, db: &dyn ExpandDatabase) -> EditionedFileId { - let mut file_id = self; - loop { - match file_id { - HirFileId::FileId(id) => break id, - HirFileId::MacroFile(macro_call_id) => { - file_id = macro_call_id.loc(db).kind.file_id() - } - } - } - } - - pub fn original_file_respecting_includes(mut self, db: &dyn ExpandDatabase) -> EditionedFileId { - loop { - match self { - HirFileId::FileId(id) => break id, - HirFileId::MacroFile(file) => { - let loc = file.loc(db); - if loc.def.is_include() - && let MacroCallKind::FnLike { eager: Some(eager), .. } = &loc.kind - && let Ok(it) = include_input_to_file_id(db, file, &eager.arg) - { - break it; - } - self = loc.kind.file_id(); - } - } - } - } - - pub fn original_call_node(self, db: &dyn ExpandDatabase) -> Option> { - let mut call = self.macro_file()?.loc(db).to_node(db); - loop { - match call.file_id { - HirFileId::FileId(file_id) => { - break Some(InRealFile { file_id, value: call.value }); - } - HirFileId::MacroFile(macro_call_id) => { - call = macro_call_id.loc(db).to_node(db); - } - } - } - } - - pub fn call_node(self, db: &dyn ExpandDatabase) -> Option> { - Some(self.macro_file()?.loc(db).to_node(db)) - } - - pub fn as_builtin_derive_attr_node( - &self, - db: &dyn ExpandDatabase, - ) -> Option> { - let macro_file = self.macro_file()?; - let loc = macro_file.loc(db); - let attr = match loc.def.kind { - MacroDefKind::BuiltInDerive(..) => loc.to_node(db), - _ => return None, - }; - Some(attr.with_value(ast::Attr::cast(attr.value.clone())?)) - } -} - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum MacroKind { /// `macro_rules!` or Macros 2.0 macro. @@ -466,10 +407,10 @@ pub enum MacroKind { } impl MacroCallId { - pub fn call_node(self, db: &dyn ExpandDatabase) -> InFile { + pub fn call_node(self, db: &dyn SourceDatabase) -> InFile { self.loc(db).to_node(db) } - pub fn expansion_level(self, db: &dyn ExpandDatabase) -> u32 { + pub fn expansion_level(self, db: &dyn SourceDatabase) -> u32 { let mut level = 0; let mut macro_file = self; loop { @@ -482,16 +423,16 @@ impl MacroCallId { }; } } - pub fn parent(self, db: &dyn ExpandDatabase) -> HirFileId { + pub fn parent(self, db: &dyn SourceDatabase) -> HirFileId { self.loc(db).kind.file_id() } /// Return expansion information if it is a macro-expansion file - pub fn expansion_info(self, db: &dyn ExpandDatabase) -> ExpansionInfo<'_> { + pub fn expansion_info(self, db: &dyn SourceDatabase) -> ExpansionInfo<'_> { ExpansionInfo::new(db, self) } - pub fn kind(self, db: &dyn ExpandDatabase) -> MacroKind { + pub fn kind(self, db: &dyn SourceDatabase) -> MacroKind { match self.loc(db).def.kind { MacroDefKind::Declarative(..) => MacroKind::Declarative, MacroDefKind::BuiltIn(..) | MacroDefKind::BuiltInEager(..) => { @@ -506,24 +447,24 @@ impl MacroCallId { } } - pub fn is_include_macro(self, db: &dyn ExpandDatabase) -> bool { + pub fn is_include_macro(self, db: &dyn SourceDatabase) -> bool { self.loc(db).def.is_include() } - pub fn is_include_like_macro(self, db: &dyn ExpandDatabase) -> bool { + pub fn is_include_like_macro(self, db: &dyn SourceDatabase) -> bool { self.loc(db).def.is_include_like() } - pub fn is_env_or_option_env(self, db: &dyn ExpandDatabase) -> bool { + pub fn is_env_or_option_env(self, db: &dyn SourceDatabase) -> bool { self.loc(db).def.is_env_or_option_env() } - pub fn is_eager(self, db: &dyn ExpandDatabase) -> bool { + pub fn is_eager(self, db: &dyn SourceDatabase) -> bool { let loc = self.loc(db); matches!(loc.def.kind, MacroDefKind::BuiltInEager(..)) } - pub fn eager_arg(self, db: &dyn ExpandDatabase) -> Option { + pub fn eager_arg(self, db: &dyn SourceDatabase) -> Option { let loc = self.loc(db); match &loc.kind { MacroCallKind::FnLike { eager, .. } => eager.as_ref().map(|it| it.arg_id), @@ -531,16 +472,545 @@ impl MacroCallId { } } - pub fn is_derive_attr_pseudo_expansion(self, db: &dyn ExpandDatabase) -> bool { + pub fn is_derive_attr_pseudo_expansion(self, db: &dyn SourceDatabase) -> bool { let loc = self.loc(db); loc.def.is_attribute_derive() } } +#[salsa::tracked] +impl MacroCallId { + /// Implementation of [`HirFileId::parse_or_expand`] for the macro case. + // FIXME: We should verify that the parsed node is one of the many macro node variants we expect + // instead of having it be untyped + #[salsa::tracked(returns(ref), lru = 512)] + pub fn parse_macro_expansion( + self, + db: &dyn SourceDatabase, + ) -> ExpandResult<(Parse, ExpansionSpanMap)> { + let _p = tracing::info_span!("parse_macro_expansion").entered(); + let loc = self.loc(db); + let expand_to = loc.expand_to(); + let mbe::ValueResult { value: (tt, matched_arm), err } = self.macro_expand(db, loc); + + let (parse, mut rev_token_map) = token_tree_to_syntax_node(db, &tt, expand_to); + rev_token_map.matched_arm = matched_arm; + + ExpandResult { value: (parse, rev_token_map), err } + } + + pub fn parse_macro_expansion_error( + self, + db: &dyn SourceDatabase, + ) -> Option>> { + let e: ExpandResult> = + self.parse_macro_expansion(db).as_ref().map(|it| Arc::from(it.0.errors())); + if e.value.is_empty() && e.err.is_none() { None } else { Some(e) } + } + + /// This resolves the [MacroCallId] to check if it is a derive macro if so get the [macro_arg] for the derive. + /// Other wise return the [macro_arg] for the macro_call_id. + /// + /// This is not connected to the database so it does not cache the result. However, the inner [macro_arg] query is + /// + /// [macro_arg]: Self::macro_arg + #[allow(deprecated)] // we are macro_arg_considering_derives + pub fn macro_arg_considering_derives<'db>( + self, + db: &'db dyn SourceDatabase, + kind: &MacroCallKind, + ) -> &'db MacroArgResult { + match kind { + // Get the macro arg for the derive macro + MacroCallKind::Derive { derive_macro_id, .. } => derive_macro_id.macro_arg(db), + // Normal macro arg + _ => self.macro_arg(db), + } + } + + /// Lowers syntactic macro call to a token tree representation. That's a firewall + /// query, only typing in the macro call itself changes the returned + /// subtree. + #[salsa::tracked(returns(ref))] + fn macro_arg(self, db: &dyn SourceDatabase) -> MacroArgResult { + let loc = self.loc(db); + + if let MacroCallLoc { + def: MacroDefId { kind: MacroDefKind::BuiltInEager(..), .. }, + kind: MacroCallKind::FnLike { eager: Some(eager), .. }, + .. + } = &loc + { + return (eager.arg.clone(), SyntaxFixupUndoInfo::NONE, eager.span); + } + + let (parse, map) = loc.kind.file_id().parse_with_map(db); + let root = parse.syntax_node(); + + let (is_derive, censor_item_tree_attr_ids, item_node, span) = match &loc.kind { + MacroCallKind::FnLike { ast_id, .. } => { + let node = &ast_id.to_ptr(db).to_node(&root); + let path_range = node + .path() + .map_or_else(|| node.syntax().text_range(), |path| path.syntax().text_range()); + let span = map.span_for_range(path_range); + + let dummy_tt = |kind| { + ( + tt::TopSubtree::from_token_trees( + tt::Delimiter { open: span, close: span, kind }, + tt::TokenTreesView::empty(), + ), + SyntaxFixupUndoInfo::default(), + span, + ) + }; + + let Some(tt) = node.token_tree() else { + return dummy_tt(tt::DelimiterKind::Invisible); + }; + let first = tt.left_delimiter_token().map(|it| it.kind()).unwrap_or(T!['(']); + let last = tt.right_delimiter_token().map(|it| it.kind()).unwrap_or(T![.]); + + let mismatched_delimiters = !matches!( + (first, last), + (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) + ); + if mismatched_delimiters { + // Don't expand malformed (unbalanced) macro invocations. This is + // less than ideal, but trying to expand unbalanced macro calls + // sometimes produces pathological, deeply nested code which breaks + // all kinds of things. + // + // So instead, we'll return an empty subtree here + cov_mark::hit!(issue9358_bad_macro_stack_overflow); + + let kind = match first { + _ if loc.def.is_proc_macro() => tt::DelimiterKind::Invisible, + T!['('] => tt::DelimiterKind::Parenthesis, + T!['['] => tt::DelimiterKind::Bracket, + T!['{'] => tt::DelimiterKind::Brace, + _ => tt::DelimiterKind::Invisible, + }; + return dummy_tt(kind); + } + + let mut tt = syntax_bridge::syntax_node_to_token_tree( + tt.syntax(), + map, + span, + if loc.def.is_proc_macro() { + DocCommentDesugarMode::ProcMacro + } else { + DocCommentDesugarMode::Mbe + }, + ); + if loc.def.is_proc_macro() { + // proc macros expect their inputs without parentheses, MBEs expect it with them included + tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible); + } + return (tt, SyntaxFixupUndoInfo::NONE, span); + } + // MacroCallKind::Derive should not be here. As we are getting the argument for the derive macro + MacroCallKind::Derive { .. } => { + unreachable!("`MacroCallId::macro_arg` called with `MacroCallKind::Derive`") + } + MacroCallKind::Attr { ast_id, censored_attr_ids: attr_ids, .. } => { + let node = ast_id.to_ptr(db).to_node(&root); + let (_, attr) = + attr_ids.invoc_attr().find_attr_range_with_source(db, loc.krate, &node); + let range = attr + .path() + .map(|path| path.syntax().text_range()) + .unwrap_or_else(|| attr.syntax().text_range()); + let span = map.span_for_range(range); + + let is_derive = matches!(loc.def.kind, MacroDefKind::BuiltInAttr(_, expander) if expander.is_derive()); + (is_derive, &**attr_ids, node, span) + } + }; + + let (mut tt, undo_info) = attr_macro_input_to_token_tree( + db, + item_node.syntax(), + map, + span, + is_derive, + censor_item_tree_attr_ids, + loc.krate, + ); + + if loc.def.is_proc_macro() { + // proc macros expect their inputs without parentheses, MBEs expect it with them included + tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible); + } + + (tt, undo_info, span) + } + + fn macro_expand<'db>( + self, + db: &'db dyn SourceDatabase, + loc: &MacroCallLoc, + ) -> ExpandResult<(Cow<'db, tt::TopSubtree>, MatchedArmIndex)> { + let _p = tracing::info_span!("macro_expand").entered(); + + let (ExpandResult { value: (tt, matched_arm), err }, span) = match loc.def.kind { + MacroDefKind::ProcMacro(..) => { + return self.expand_proc_macro(db).as_ref().map(|it| (Cow::Borrowed(it), None)); + } + _ => { + let (macro_arg, undo_info, span) = + self.macro_arg_considering_derives(db, &loc.kind); + let span = *span; + + let arg = macro_arg; + let res = match loc.def.kind { + MacroDefKind::Declarative(id, _) => { + id.decl_macro_expander(db, loc.def.krate).expand(db, arg, self, span) + } + MacroDefKind::BuiltIn(_, it) => { + it.expand(db, self, arg, span).map_err(Into::into).zip_val(None) + } + MacroDefKind::BuiltInDerive(_, it) => { + it.expand(db, self, arg, span).map_err(Into::into).zip_val(None) + } + MacroDefKind::UnimplementedBuiltIn(_) => { + expand_unimplemented_builtin_macro(span).zip_val(None) + } + MacroDefKind::BuiltInEager(_, it) => { + // This might look a bit odd, but we do not expand the inputs to eager macros here. + // Eager macros inputs are expanded, well, eagerly when we collect the macro calls. + // That kind of expansion uses the ast id map of an eager macros input though which goes through + // the HirFileId machinery. As eager macro inputs are assigned a macro file id that query + // will end up going through here again, whereas we want to just want to inspect the raw input. + // As such we just return the input subtree here. + let eager = match &loc.kind { + MacroCallKind::FnLike { eager: None, .. } => { + return ExpandResult::ok(Cow::Borrowed(macro_arg)).zip_val(None); + } + MacroCallKind::FnLike { eager: Some(eager), .. } => Some(&**eager), + _ => None, + }; + + let mut res = it.expand(db, self, arg, span).map_err(Into::into); + + if let Some(EagerCallInfo { error, .. }) = eager { + // FIXME: We should report both errors! + res.err = error.clone().or(res.err); + } + res.zip_val(None) + } + MacroDefKind::BuiltInAttr(_, it) => { + let mut res = it.expand(db, self, arg, span); + fixup::reverse_fixups(&mut res.value, undo_info); + res.zip_val(None) + } + MacroDefKind::ProcMacro(_, _, _) => unreachable!(), + }; + (res, span) + } + }; + + // Skip checking token tree limit for include! macro call + if !loc.def.is_include() { + // Set a hard limit for the expanded tt + if let Err(value) = check_tt_count(&tt) { + return value + .map(|()| Cow::Owned(tt::TopSubtree::empty(tt::DelimSpan::from_single(span)))) + .zip_val(matched_arm); + } + } + + ExpandResult { value: (Cow::Owned(tt), matched_arm), err } + } + + /// Special case of [`Self::macro_expand`] for procedural macros. We can't LRU + /// proc macros, since they are not deterministic in general, and + /// non-determinism breaks salsa in a very, very, very bad way. + /// @edwin0cheng heroically debugged this once! See #4315 for details + #[salsa::tracked(returns(ref))] + fn expand_proc_macro(self, db: &dyn SourceDatabase) -> ExpandResult { + let loc = self.loc(db); + let (macro_arg, undo_info, span) = self.macro_arg_considering_derives(db, &loc.kind); + + let (ast, expander) = match loc.def.kind { + MacroDefKind::ProcMacro(ast, expander, _) => (ast, expander), + _ => unreachable!(), + }; + + let attr_arg = match &loc.kind { + MacroCallKind::Attr { attr_args: Some(attr_args), .. } => Some(&**attr_args), + _ => None, + }; + + let ExpandResult { value: mut tt, err } = { + let span = proc_macro_span(db, ast); + expander.expand( + db, + loc.def.krate, + loc.krate, + macro_arg, + attr_arg, + span_with_def_site_ctxt(db, span, self.into(), loc.def.edition), + span_with_call_site_ctxt(db, span, self.into(), loc.def.edition), + span_with_mixed_site_ctxt(db, span, self.into(), loc.def.edition), + ) + }; + + // Set a hard limit for the expanded tt + if let Err(value) = check_tt_count(&tt) { + return value.map(|()| tt::TopSubtree::empty(tt::DelimSpan::from_single(*span))); + } + + fixup::reverse_fixups(&mut tt, undo_info); + + ExpandResult { value: tt, err } + } +} + +impl MacroCallId { + /// This expands the given macro call, but with different arguments. This is + /// used for completion, where we want to see what 'would happen' if we insert a + /// token. The `token_to_map` mapped down into the expansion, with the mapped + /// token(s) returned with their priority. + pub fn expand_speculative( + self, + db: &dyn SourceDatabase, + speculative_args: &SyntaxNode, + token_to_map: SyntaxToken, + ) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> { + let loc = self.loc(db); + let (_, _, span) = *self.macro_arg_considering_derives(db, &loc.kind); + + let span_map = RealSpanMap::absolute(span.anchor.file_id); + let span_map = SpanMap::RealSpanMap(&span_map); + + // Build the subtree and token mapping for the speculative args + let (mut tt, undo_info) = match &loc.kind { + MacroCallKind::FnLike { .. } => ( + syntax_bridge::syntax_node_to_token_tree( + speculative_args, + span_map, + span, + if loc.def.is_proc_macro() { + DocCommentDesugarMode::ProcMacro + } else { + DocCommentDesugarMode::Mbe + }, + ), + SyntaxFixupUndoInfo::NONE, + ), + MacroCallKind::Attr { .. } if loc.def.is_attribute_derive() => ( + syntax_bridge::syntax_node_to_token_tree( + speculative_args, + span_map, + span, + DocCommentDesugarMode::ProcMacro, + ), + SyntaxFixupUndoInfo::NONE, + ), + MacroCallKind::Derive { derive_macro_id, .. } => { + let MacroCallKind::Attr { censored_attr_ids: attr_ids, .. } = + &derive_macro_id.loc(db).kind + else { + unreachable!("`derive_macro_id` should be `MacroCallKind::Attr`"); + }; + attr_macro_input_to_token_tree( + db, + speculative_args, + span_map, + span, + true, + attr_ids, + loc.krate, + ) + } + MacroCallKind::Attr { censored_attr_ids: attr_ids, .. } => { + attr_macro_input_to_token_tree( + db, + speculative_args, + span_map, + span, + false, + attr_ids, + loc.krate, + ) + } + }; + + let attr_arg = match &loc.kind { + MacroCallKind::Attr { censored_attr_ids: attr_ids, .. } => { + if loc.def.is_attribute_derive() { + // for pseudo-derive expansion we actually pass the attribute itself only + ast::Attr::cast(speculative_args.clone()) + .and_then(|attr| { + if let ast::Meta::TokenTreeMeta(meta) = attr.meta()? { + meta.token_tree() + } else { + None + } + }) + .map(|token_tree| { + let mut tree = syntax_node_to_token_tree( + token_tree.syntax(), + span_map, + span, + DocCommentDesugarMode::ProcMacro, + ); + tree.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible); + tree.set_top_subtree_delimiter_span(tt::DelimSpan::from_single(span)); + tree + }) + } else { + // Attributes may have an input token tree, build the subtree and map for this as well + // then try finding a token id for our token if it is inside this input subtree. + let item = ast::Item::cast(speculative_args.clone())?; + let (_, meta) = attr_ids + .invoc_attr() + .find_attr_range_with_source_opt(db, loc.krate, &item)?; + if let ast::Meta::TokenTreeMeta(meta) = meta + && let Some(tt) = meta.token_tree() + { + let mut attr_arg = syntax_bridge::syntax_node_to_token_tree( + tt.syntax(), + span_map, + span, + DocCommentDesugarMode::ProcMacro, + ); + attr_arg.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible); + Some(attr_arg) + } else { + None + } + } + } + _ => None, + }; + + // Do the actual expansion, we need to directly expand the proc macro due to the attribute args + // Otherwise the expand query will fetch the non speculative attribute args and pass those instead. + let mut speculative_expansion = match loc.def.kind { + MacroDefKind::ProcMacro(ast, expander, _) => { + let span = proc_macro_span(db, ast); + tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible); + tt.set_top_subtree_delimiter_span(tt::DelimSpan::from_single(span)); + expander.expand( + db, + loc.def.krate, + loc.krate, + &tt, + attr_arg.as_ref(), + span_with_def_site_ctxt(db, span, self.into(), loc.def.edition), + span_with_call_site_ctxt(db, span, self.into(), loc.def.edition), + span_with_mixed_site_ctxt(db, span, self.into(), loc.def.edition), + ) + } + MacroDefKind::BuiltInAttr(_, it) if it.is_derive() => { + pseudo_derive_attr_expansion(&tt, attr_arg.as_ref()?, span) + } + MacroDefKind::Declarative(it, _) => it + .decl_macro_expander(db, loc.krate) + .expand_unhygienic(db, &tt, loc.kind.call_style(), span), + MacroDefKind::BuiltIn(_, it) => it.expand(db, self, &tt, span).map_err(Into::into), + MacroDefKind::BuiltInDerive(_, it) => { + it.expand(db, self, &tt, span).map_err(Into::into) + } + MacroDefKind::BuiltInEager(_, it) => it.expand(db, self, &tt, span).map_err(Into::into), + MacroDefKind::BuiltInAttr(_, it) => it.expand(db, self, &tt, span), + MacroDefKind::UnimplementedBuiltIn(_) => expand_unimplemented_builtin_macro(span), + }; + + let expand_to = loc.expand_to(); + + fixup::reverse_fixups(&mut speculative_expansion.value, &undo_info); + let (node, rev_tmap) = + token_tree_to_syntax_node(db, &speculative_expansion.value, expand_to); + + let syntax_node = node.syntax_node(); + let token = rev_tmap + .ranges_with_span(span_map.span_for_range(token_to_map.text_range())) + .filter_map(|(range, ctx)| { + syntax_node.covering_element(range).into_token().zip(Some(ctx)) + }) + .map(|(t, ctx)| { + // prefer tokens of the same kind and text, as well as non opaque marked ones + // Note the inversion of the score here, as we want to prefer the first token in case + // of all tokens having the same score + let ranking = ctx.is_opaque(db) as u8 + + 2 * (t.kind() != token_to_map.kind()) as u8 + + 4 * ((t.text() != token_to_map.text()) as u8); + (t, ranking) + }) + .collect(); + Some((node.syntax_node(), token)) + } +} + +fn expand_unimplemented_builtin_macro(span: Span) -> ExpandResult { + ExpandResult::new( + tt::TopSubtree::empty(tt::DelimSpan::from_single(span)), + ExpandError::other(span, "this built-in macro is not implemented"), + ) +} + +/// Retrieves the span to be used for a proc-macro expansions spans. +/// This is a firewall query as it requires parsing the file, which we don't want proc-macros to +/// directly depend on as that would cause to frequent invalidations, mainly because of the +/// parse queries being LRU cached. If they weren't the invalidations would only happen if the +/// user wrote in the file that defines the proc-macro. +fn proc_macro_span(db: &dyn SourceDatabase, ast: AstId) -> Span { + #[salsa::tracked] + fn proc_macro_span(db: &dyn SourceDatabase, ast: AstId, _: ()) -> Span { + let (parse, span_map) = ast.file_id.parse_with_map(db); + let root = parse.syntax_node(); + let ast_id_map = ast.file_id.ast_id_map(db); + + let node = ast_id_map.get(ast.value).to_node(&root); + let range = ast::HasName::name(&node) + .map_or_else(|| node.syntax().text_range(), |name| name.syntax().text_range()); + span_map.span_for_range(range) + } + proc_macro_span(db, ast, ()) +} + +pub(crate) fn token_tree_to_syntax_node( + db: &dyn SourceDatabase, + tt: &tt::TopSubtree, + expand_to: ExpandTo, +) -> (Parse, ExpansionSpanMap) { + let entry_point = match expand_to { + ExpandTo::Statements => syntax_bridge::TopEntryPoint::MacroStmts, + ExpandTo::Items => syntax_bridge::TopEntryPoint::MacroItems, + ExpandTo::Pattern => syntax_bridge::TopEntryPoint::Pattern, + ExpandTo::Type => syntax_bridge::TopEntryPoint::Type, + ExpandTo::Expr => syntax_bridge::TopEntryPoint::Expr, + }; + syntax_bridge::token_tree_to_syntax_node(tt, entry_point, &mut |ctx| ctx.edition(db)) +} + +fn check_tt_count(tt: &tt::TopSubtree) -> Result<(), ExpandResult<()>> { + let tt = tt.top_subtree(); + let count = tt.count(); + if count <= TOKEN_LIMIT { + Ok(()) + } else { + Err(ExpandResult { + value: (), + err: Some(ExpandError::other( + tt.delimiter.open, + format!( + "macro invocation exceeds token limit: produced {count} tokens, limit is {TOKEN_LIMIT}", + ), + )), + }) + } +} + impl MacroDefId { pub fn make_call( self, - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, krate: Crate, kind: MacroCallKind, ctxt: SyntaxContext, @@ -548,7 +1018,7 @@ impl MacroDefId { MacroCallId::new(db, MacroCallLoc { def: self, krate, kind, ctxt }) } - pub fn definition_range(&self, db: &dyn ExpandDatabase) -> InFile { + pub fn definition_range(&self, db: &dyn SourceDatabase) -> InFile { match self.kind { MacroDefKind::Declarative(id, _) | MacroDefKind::BuiltIn(id, _) @@ -556,10 +1026,10 @@ impl MacroDefId { | MacroDefKind::BuiltInDerive(id, _) | MacroDefKind::BuiltInEager(id, _) | MacroDefKind::UnimplementedBuiltIn(id) => { - id.with_value(db.ast_id_map(id.file_id).get(id.value).text_range()) + id.with_value(id.file_id.ast_id_map(db).get(id.value).text_range()) } MacroDefKind::ProcMacro(id, _, _) => { - id.with_value(db.ast_id_map(id.file_id).get(id.value).text_range()) + id.with_value(id.file_id.ast_id_map(db).get(id.value).text_range()) } } } @@ -629,7 +1099,7 @@ impl MacroDefId { } impl MacroCallLoc { - pub fn to_node(&self, db: &dyn ExpandDatabase) -> InFile { + pub fn to_node(&self, db: &dyn SourceDatabase) -> InFile { match &self.kind { MacroCallKind::FnLike { ast_id, .. } => { ast_id.with_value(ast_id.to_node(db).syntax().clone()) @@ -649,7 +1119,7 @@ impl MacroCallLoc { } } - pub fn to_node_item(&self, db: &dyn ExpandDatabase) -> InFile { + pub fn to_node_item(&self, db: &dyn SourceDatabase) -> InFile { match self.kind { MacroCallKind::FnLike { ast_id, .. } => { InFile::new(ast_id.file_id, ast_id.map(FileAstId::upcast).to_node(db)) @@ -675,7 +1145,7 @@ impl MacroCallLoc { pub fn include_file_id( &self, - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, macro_call_id: MacroCallId, ) -> Option { if self.def.is_include() @@ -721,7 +1191,7 @@ impl MacroCallKind { /// - fn_like! {}, it spans the path and token tree /// - #\[derive], it spans the `#[derive(...)]` attribute and the annotated item /// - #\[attr], it spans the `#[attr(...)]` attribute and the annotated item - pub fn original_call_range_with_input(&self, db: &dyn ExpandDatabase) -> FileRange { + pub fn original_call_range_with_input(&self, db: &dyn SourceDatabase) -> FileRange { let get_range = |kind: &_| match kind { MacroCallKind::FnLike { ast_id, .. } => ast_id.erase(), MacroCallKind::Derive { ast_id, .. } => ast_id.erase(), @@ -749,7 +1219,7 @@ impl MacroCallKind { /// Here we try to roughly match what rustc does to improve diagnostics: fn-like macros /// get the macro path (rustc shows the whole `ast::MacroCall`), attribute macros get the /// attribute's range, and derives get only the specific derive that is being referred to. - pub fn original_call_range(&self, db: &dyn ExpandDatabase, krate: Crate) -> FileRange { + pub fn original_call_range(&self, db: &dyn SourceDatabase, krate: Crate) -> FileRange { let get_range = |kind: &_| match kind { MacroCallKind::FnLike { ast_id, .. } => { let node = ast_id.to_node(db); @@ -785,7 +1255,7 @@ impl MacroCallKind { FileRange { range, file_id } } - fn arg(&self, db: &dyn ExpandDatabase) -> InFile> { + fn arg(&self, db: &dyn SourceDatabase) -> InFile> { match self { MacroCallKind::FnLike { ast_id, .. } => { ast_id.to_in_file_node(db).map(|it| Some(it.token_tree()?.syntax().clone())) @@ -875,7 +1345,7 @@ impl<'db> ExpansionInfo<'db> { /// Looks up the span at the given offset. pub fn span_for_offset( &self, - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, offset: TextSize, ) -> (FileRange, SyntaxContext) { debug_assert!(self.expanded.value.text_range().contains(offset)); @@ -885,7 +1355,7 @@ impl<'db> ExpansionInfo<'db> { /// Maps up the text range out of the expansion hierarchy back into the original file its from. pub fn map_node_range_up( &self, - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, range: TextRange, ) -> Option<(FileRange, SyntaxContext)> { debug_assert!(self.expanded.value.text_range().contains_range(range)); @@ -898,14 +1368,14 @@ impl<'db> ExpansionInfo<'db> { /// and as such we may consider inputs that are unrelated. pub fn map_range_up_once( &self, - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, token: TextRange, ) -> InFile> { debug_assert!(self.expanded.value.text_range().contains_range(token)); let span = self.exp_map.span_at(token.start()); match &self.arg_map { SpanMap::RealSpanMap(_) => { - let range = db.resolve_span(span); + let range = resolve_span(db, span); InFile { file_id: range.file_id.into(), value: smallvec::smallvec![range.range] } } SpanMap::ExpansionSpanMap(arg_map) => { @@ -917,22 +1387,22 @@ impl<'db> ExpansionInfo<'db> { self.arg.file_id, arg_map .ranges_with_span_exact(span) - .filter(|(range, _)| range.intersect(arg_range).is_some()) - .map(TupleExt::head) + .map(|(range, _)| range) + .filter(|range| range.intersect(arg_range).is_some()) .collect(), ) } } } - pub fn new(db: &'db dyn ExpandDatabase, macro_file: MacroCallId) -> ExpansionInfo<'db> { + pub fn new(db: &'db dyn SourceDatabase, macro_file: MacroCallId) -> ExpansionInfo<'db> { let _p = tracing::info_span!("ExpansionInfo::new").entered(); let loc = macro_file.loc(db); let arg_tt = loc.kind.arg(db); - let arg_map = db.span_map(arg_tt.file_id); + let arg_map = arg_tt.file_id.span_map(db); - let (parse, exp_map) = &db.parse_macro_expansion(macro_file).value; + let (parse, exp_map) = ¯o_file.parse_macro_expansion(db).value; let expanded = InMacroFile { file_id: macro_file, value: parse.syntax_node() }; ExpansionInfo { expanded, loc, arg: arg_tt, exp_map, arg_map } @@ -943,7 +1413,7 @@ impl<'db> ExpansionInfo<'db> { /// considering the root spans contained. /// Unlike [`map_node_range_up`], this will not return `None` if any anchors or syntax contexts differ. pub fn map_node_range_up_rooted( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, exp_map: &ExpansionSpanMap, range: TextRange, ) -> Option { @@ -959,14 +1429,14 @@ pub fn map_node_range_up_rooted( start = start.min(span.range.start()); end = end.max(span.range.end()); } - Some(db.resolve_span(Span { range: TextRange::new(start, end), anchor, ctx })) + Some(resolve_span(db, Span { range: TextRange::new(start, end), anchor, ctx })) } /// Maps up the text range out of the expansion hierarchy back into the original file its from. /// /// this will return `None` if any anchors or syntax contexts differ. pub fn map_node_range_up( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, exp_map: &ExpansionSpanMap, range: TextRange, ) -> Option<(FileRange, SyntaxContext)> { @@ -982,17 +1452,27 @@ pub fn map_node_range_up( start = start.min(span.range.start()); end = end.max(span.range.end()); } - Some((db.resolve_span(Span { range: TextRange::new(start, end), anchor, ctx }), ctx)) + Some((resolve_span(db, Span { range: TextRange::new(start, end), anchor, ctx }), ctx)) } /// Looks up the span at the given offset. pub fn span_for_offset( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, exp_map: &ExpansionSpanMap, offset: TextSize, ) -> (FileRange, SyntaxContext) { let span = exp_map.span_at(offset); - (db.resolve_span(span), span.ctx) + (resolve_span(db, span), span.ctx) +} + +// FIXME: This is only public because of its use in `load_cargo` (which we should consider removing +// by moving the implementations of the subrequests to `hir_expand`, and calling within `load-cargo`). +// Avoid adding any more outside uses. +pub fn resolve_span(db: &dyn SourceDatabase, Span { range, anchor, ctx: _ }: Span) -> FileRange { + let file_id = EditionedFileId::from_span_file_id(db, anchor.file_id); + let anchor_offset = + HirFileId::from(file_id).ast_id_map(db).get_erased(anchor.ast_id).text_range().start(); + FileRange { file_id, range: range + anchor_offset } } /// In Rust, macros expand token trees to token trees. When we want to turn a @@ -1059,8 +1539,6 @@ impl ExpandTo { } } -intern::impl_internable!(ModPath); - /// Macro ids. That's probably the tricksiest bit in rust-analyzer, and the /// reason why we use salsa at all. /// @@ -1107,6 +1585,17 @@ impl From for HirFileId { } } +impl PartialEq for HirFileId { + fn eq(&self, &other: &EditionedFileId) -> bool { + *self == HirFileId::from(other) + } +} +impl PartialEq for EditionedFileId { + fn eq(&self, &other: &HirFileId) -> bool { + other == HirFileId::from(*self) + } +} + impl HirFileId { #[inline] pub fn macro_file(self) -> Option { @@ -1129,24 +1618,116 @@ impl HirFileId { } } - pub fn syntax_context(self, db: &dyn ExpandDatabase, edition: Edition) -> SyntaxContext { + pub fn syntax_context(self, db: &dyn SourceDatabase, edition: Edition) -> SyntaxContext { match self { HirFileId::FileId(_) => SyntaxContext::root(edition), HirFileId::MacroFile(m) => { let kind = &m.loc(db).kind; - db.macro_arg_considering_derives(m, kind).2.ctx + m.macro_arg_considering_derives(db, kind).2.ctx } } } -} -impl PartialEq for HirFileId { - fn eq(&self, &other: &EditionedFileId) -> bool { - *self == HirFileId::from(other) + pub fn edition(self, db: &dyn SourceDatabase) -> Edition { + match self { + HirFileId::FileId(file_id) => file_id.edition(db), + HirFileId::MacroFile(m) => m.loc(db).def.edition, + } + } + + pub fn original_file(self, db: &dyn SourceDatabase) -> EditionedFileId { + let mut file_id = self; + loop { + match file_id { + HirFileId::FileId(id) => break id, + HirFileId::MacroFile(macro_call_id) => { + file_id = macro_call_id.loc(db).kind.file_id() + } + } + } + } + + pub fn original_file_respecting_includes(mut self, db: &dyn SourceDatabase) -> EditionedFileId { + loop { + match self { + HirFileId::FileId(id) => break id, + HirFileId::MacroFile(file) => { + let loc = file.loc(db); + if loc.def.is_include() + && let MacroCallKind::FnLike { eager: Some(eager), .. } = &loc.kind + && let Ok(it) = include_input_to_file_id(db, file, &eager.arg) + { + break it; + } + self = loc.kind.file_id(); + } + } + } + } + + pub fn original_call_node(self, db: &dyn SourceDatabase) -> Option> { + let mut call = self.macro_file()?.loc(db).to_node(db); + loop { + match call.file_id { + HirFileId::FileId(file_id) => { + break Some(InRealFile { file_id, value: call.value }); + } + HirFileId::MacroFile(macro_call_id) => { + call = macro_call_id.loc(db).to_node(db); + } + } + } + } + + pub fn call_node(self, db: &dyn SourceDatabase) -> Option> { + Some(self.macro_file()?.loc(db).to_node(db)) + } + + pub fn as_builtin_derive_attr_node( + &self, + db: &dyn SourceDatabase, + ) -> Option> { + let macro_file = self.macro_file()?; + let loc = macro_file.loc(db); + let attr = match loc.def.kind { + MacroDefKind::BuiltInDerive(..) => loc.to_node(db), + _ => return None, + }; + Some(attr.with_value(ast::Attr::cast(attr.value.clone())?)) + } + + /// Main public API -- parses a hir file, not caring whether it's a real + /// file or a macro expansion. + pub fn parse_or_expand(self, db: &dyn SourceDatabase) -> SyntaxNode { + match self { + HirFileId::FileId(file_id) => file_id.parse(db).syntax_node(), + HirFileId::MacroFile(macro_file) => { + macro_file.parse_macro_expansion(db).value.0.syntax_node() + } + } + } + + pub(crate) fn parse_with_map( + self, + db: &dyn SourceDatabase, + ) -> (Parse, SpanMap<'_>) { + match self { + HirFileId::FileId(file_id) => ( + file_id.parse(db).to_syntax(), + SpanMap::RealSpanMap(crate::span_map::real_span_map(db, file_id)), + ), + HirFileId::MacroFile(macro_file) => { + let (parse, map) = ¯o_file.parse_macro_expansion(db).value; + (parse.clone(), SpanMap::ExpansionSpanMap(map)) + } + } } } -impl PartialEq for EditionedFileId { - fn eq(&self, &other: &HirFileId) -> bool { - other == HirFileId::from(*self) + +#[salsa::tracked] +impl HirFileId { + #[salsa::tracked(lru = 1024, returns(ref))] + pub fn ast_id_map(self, db: &dyn SourceDatabase) -> AstIdMap { + AstIdMap::from_source(&self.parse_or_expand(db)) } } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs index 9142ad8b92119..59578bae89554 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs @@ -6,12 +6,11 @@ use std::{ }; use crate::{ - db::ExpandDatabase, hygiene::Transparency, name::{AsName, Name}, tt, }; -use base_db::Crate; +use base_db::{Crate, SourceDatabase}; use intern::{Symbol, sym}; use parser::T; use smallvec::SmallVec; @@ -24,6 +23,8 @@ pub struct ModPath { segments: SmallVec<[Name; 1]>, } +intern::impl_internable!(ModPath); + #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum PathKind { Plain, @@ -43,14 +44,14 @@ impl PathKind { impl ModPath { pub fn from_src( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, path: ast::Path, span_for_range: &mut dyn FnMut(::tt::TextRange) -> SyntaxContext, ) -> Option { convert_path(db, path, span_for_range) } - pub fn from_tt(db: &dyn ExpandDatabase, tt: tt::TokenTreesView<'_>) -> Option { + pub fn from_tt(db: &dyn SourceDatabase, tt: tt::TokenTreesView<'_>) -> Option { convert_path_tt(db, tt) } @@ -66,7 +67,7 @@ impl ModPath { } pub fn from_tokens( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, span_for_range: &mut dyn FnMut(::tt::TextRange) -> SyntaxContext, is_abs: bool, segments: impl Iterator, @@ -178,16 +179,13 @@ impl ModPath { _ => None, } } - pub fn display_verbatim<'a>( - &'a self, - db: &'a dyn crate::db::ExpandDatabase, - ) -> impl fmt::Display + 'a { + pub fn display_verbatim<'a>(&'a self, db: &'a dyn SourceDatabase) -> impl fmt::Display + 'a { Display { db, path: self, edition: None } } pub fn display<'a>( &'a self, - db: &'a dyn crate::db::ExpandDatabase, + db: &'a dyn SourceDatabase, edition: Edition, ) -> impl fmt::Display + 'a { Display { db, path: self, edition: Some(edition) } @@ -201,7 +199,7 @@ impl Extend for ModPath { } struct Display<'a> { - db: &'a dyn ExpandDatabase, + db: &'a dyn SourceDatabase, path: &'a ModPath, edition: Option, } @@ -219,7 +217,7 @@ impl From for ModPath { } fn display_fmt_path( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, path: &ModPath, f: &mut fmt::Formatter<'_>, edition: Option, @@ -259,7 +257,7 @@ fn display_fmt_path( } fn convert_path( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, path: ast::Path, span_for_range: &mut dyn FnMut(::tt::TextRange) -> SyntaxContext, ) -> Option { @@ -344,7 +342,7 @@ fn convert_path( Some(mod_path) } -fn convert_path_tt(db: &dyn ExpandDatabase, tt: tt::TokenTreesView<'_>) -> Option { +fn convert_path_tt(db: &dyn SourceDatabase, tt: tt::TokenTreesView<'_>) -> Option { let mut leaves = tt.iter().filter_map(|tt| match tt { tt::TtElement::Leaf(leaf) => Some(leaf), tt::TtElement::Subtree(..) => None, @@ -386,7 +384,7 @@ fn convert_path_tt(db: &dyn ExpandDatabase, tt: tt::TokenTreesView<'_>) -> Optio Some(ModPath { kind, segments }) } -pub fn resolve_crate_root(db: &dyn ExpandDatabase, mut ctxt: SyntaxContext) -> Option { +pub fn resolve_crate_root(db: &dyn SourceDatabase, mut ctxt: SyntaxContext) -> Option { // When resolving `$crate` from a `macro_rules!` invoked in a `macro`, // we don't want to pretend that the `macro_rules!` definition is in the `macro` // as described in `SyntaxContextId::apply_mark`, so we ignore prepended opaque marks. diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs index b511bc3c15ff0..d91b0f378e191 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs @@ -2,6 +2,7 @@ use std::fmt; +use base_db::SourceDatabase; use intern::{Symbol, sym}; use span::{Edition, SyntaxContext}; use syntax::utils::is_raw_identifier; @@ -180,7 +181,7 @@ impl Name { #[inline] pub fn display<'a>( &'a self, - db: &dyn crate::db::ExpandDatabase, + db: &dyn SourceDatabase, edition: Edition, ) -> impl fmt::Display + 'a { _ = db; diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/prettify_macro_expansion_.rs b/src/tools/rust-analyzer/crates/hir-expand/src/prettify_macro_expansion_.rs index 687bd1a71400f..d088b0d1a9f7c 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/prettify_macro_expansion_.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/prettify_macro_expansion_.rs @@ -1,15 +1,15 @@ //! Pretty printing of macros output. -use base_db::Crate; +use base_db::{Crate, SourceDatabase}; use rustc_hash::FxHashMap; use syntax::SyntaxNode; -use crate::{db::ExpandDatabase, span_map::ExpansionSpanMap}; +use crate::span_map::ExpansionSpanMap; /// Inserts whitespace and replaces `$crate` in macro expansions. #[expect(deprecated)] pub fn prettify_macro_expansion( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, syn: SyntaxNode, span_map: &ExpansionSpanMap, target_crate_id: Crate, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs index 94c105761db36..f4a259dcc1acb 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs @@ -4,14 +4,14 @@ use core::fmt; use std::any::Any; use std::{panic::RefUnwindSafe, sync}; -use base_db::{Crate, CrateBuilderId, CratesIdMap, Env, ProcMacroLoadingError}; +use base_db::{Crate, CrateBuilderId, CratesIdMap, Env, ProcMacroLoadingError, SourceDatabase}; use intern::Symbol; use rustc_hash::FxHashMap; use salsa::{Durability, Setter}; use span::Span; use triomphe::Arc; -use crate::{ExpandError, ExpandErrorKind, ExpandResult, db::ExpandDatabase, tt}; +use crate::{ExpandError, ExpandErrorKind, ExpandResult, tt}; #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Hash)] pub enum ProcMacroKind { @@ -26,7 +26,7 @@ pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe + Any { /// [`ProcMacroKind::Attr`]), environment variables, and span information. fn expand( &self, - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, subtree: &tt::TopSubtree, attrs: Option<&tt::TopSubtree>, env: &Env, @@ -85,7 +85,7 @@ impl ProcMacrosBuilder { } /// Builds [`ProcMacros`] and adds id to `db` - pub(crate) fn build_in(self, db: &mut dyn ExpandDatabase, crates_id_map: &CratesIdMap) { + pub(crate) fn build_in(self, db: &mut dyn SourceDatabase, crates_id_map: &CratesIdMap) { let mut map = self .0 .into_iter() @@ -121,7 +121,7 @@ pub struct ProcMacros { } impl ProcMacros { - pub fn init_default(db: &dyn ExpandDatabase, durability: Durability) { + pub fn init_default(db: &dyn SourceDatabase, durability: Durability) { _ = Self::builder(Default::default()).durability(durability).new(db); } } @@ -130,7 +130,7 @@ impl ProcMacros { impl ProcMacros { /// Incrementality query to prevent queries from directly depending on [`Self::get`]. #[salsa::tracked(returns(as_ref))] - pub fn get_for_crate(db: &dyn ExpandDatabase, krate: Crate) -> Option> { + pub fn get_for_crate(db: &dyn SourceDatabase, krate: Crate) -> Option> { Self::get(db).by_crate(db).get(&krate).cloned() } } @@ -273,7 +273,7 @@ impl CustomProcMacroExpander { pub fn expand( self, - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, def_crate: Crate, calling_crate: Crate, tt: &tt::TopSubtree, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs b/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs index 6a94df8b5a554..7b1a04de732bb 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs @@ -1,11 +1,12 @@ //! Span maps for real files and macro expansions. +use base_db::SourceDatabase; use span::Span; use syntax::{AstNode, TextRange, ast}; pub use span::RealSpanMap; -use crate::{HirFileId, MacroCallId, db::ExpandDatabase}; +use crate::{HirFileId, MacroCallId}; pub type ExpansionSpanMap = span::SpanMap; @@ -30,31 +31,33 @@ impl<'db> SpanMap<'db> { // FIXME: Is it correct for us to only take the span at the start? This feels somewhat // wrong. The context will be right, but the range could be considered wrong. See // https://github.com/rust-lang/rust/issues/23480, we probably want to fetch the span at - // the start and end, then merge them like rustc does in `Span::to + // the start and end, then merge them like rustc does in `Span::to` Self::ExpansionSpanMap(span_map) => span_map.span_at(range.start()), Self::RealSpanMap(span_map) => span_map.span_for_range(range), } } +} +impl HirFileId { #[inline] - pub(crate) fn new(db: &'db dyn ExpandDatabase, file_id: HirFileId) -> SpanMap<'db> { - match file_id { - HirFileId::FileId(file_id) => SpanMap::RealSpanMap(db.real_span_map(file_id)), - HirFileId::MacroFile(m) => { - SpanMap::ExpansionSpanMap(&db.parse_macro_expansion(m).value.1) - } + pub fn span_map<'db>(self, db: &'db dyn SourceDatabase) -> SpanMap<'db> { + match self { + HirFileId::FileId(file_id) => SpanMap::RealSpanMap(real_span_map(db, file_id)), + HirFileId::MacroFile(m) => SpanMap::ExpansionSpanMap(m.expansion_span_map(db)), } } } +/// This is an implementation detail of [`HirFileId::span_map`]. Outside this crate, use +/// `HirFileId::from(file_id).span_map(db)` instead of `real_span_map(db, file_id)`. #[salsa_macros::tracked(returns(ref))] pub(crate) fn real_span_map( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, editioned_file_id: base_db::EditionedFileId, ) -> RealSpanMap { use syntax::ast::HasModuleItem; let mut pairs = vec![(syntax::TextSize::new(0), span::ROOT_ERASED_FILE_AST_ID)]; - let ast_id_map = db.ast_id_map(editioned_file_id.into()); + let ast_id_map = HirFileId::from(editioned_file_id).ast_id_map(db); let tree = editioned_file_id.parse(db).tree(); // This is an incrementality layer. Basically we can't use absolute ranges for our spans as that @@ -111,9 +114,8 @@ pub(crate) fn real_span_map( ) } -pub(crate) fn expansion_span_map( - db: &dyn ExpandDatabase, - file_id: MacroCallId, -) -> &ExpansionSpanMap { - &db.parse_macro_expansion(file_id).value.1 +impl MacroCallId { + pub fn expansion_span_map(self, db: &dyn SourceDatabase) -> &ExpansionSpanMap { + &self.parse_macro_expansion(db).value.1 + } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs index a8ed4126abeae..ea0881923cb75 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs @@ -207,11 +207,10 @@ where } else { (AutoderefKind::Builtin, ty) } - } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) { + } else { + let ty = self.overloaded_deref_ty(self.state.cur_ty)?; // The overloaded deref check already normalizes the pointee type. (AutoderefKind::Overloaded, ty) - } else { - return None; }; self.state.steps.push(self.state.cur_ty, kind); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs index 85e917fe1a0d1..1772e3c172413 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs @@ -691,6 +691,33 @@ fn cttz() { "#, 3, ); + check_number( + r#" + #[rustc_intrinsic] + pub fn cttz(x: T) -> T; + + const GOAL: i8 = cttz(0i8); + "#, + 8, + ); + check_number( + r#" + #[rustc_intrinsic] + pub fn cttz(x: T) -> T; + + const GOAL: u32 = cttz(0u32); + "#, + 32, + ); + check_number( + r#" + #[rustc_intrinsic] + pub fn cttz(x: T) -> T; + + const GOAL: u64 = cttz(0u64); + "#, + 64, + ); } #[test] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index 93ae26abce88b..6b482870ab823 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -2,14 +2,13 @@ //! type inference-related queries. use arrayvec::ArrayVec; -use base_db::{Crate, target::TargetLoadError}; +use base_db::{Crate, SourceDatabase, target::TargetLoadError}; use either::Either; use hir_def::{ AdtId, BuiltinDeriveImplId, CallableDefId, ConstId, ConstParamId, EnumVariantId, ExpressionStoreOwnerId, FunctionId, GenericDefId, HasModule, ImplId, LocalFieldId, ModuleId, StaticId, TraitId, TypeAliasId, VariantId, builtin_derive::BuiltinDeriveImplMethod, - db::DefDatabase, expr_store::ExpressionStore, hir::{ClosureKind, ExprId, generics::LocalTypeOrConstParamId}, layout::TargetDataLayout, @@ -38,7 +37,7 @@ use crate::{ }; #[query_group::query_group] -pub trait HirDatabase: DefDatabase + std::fmt::Debug { +pub trait HirDatabase: SourceDatabase + std::fmt::Debug { // region:mir // FXME: Collapse `mir_body_for_closure` into `mir_body` @@ -416,20 +415,24 @@ pub struct AnonConstId { } impl AnonConstId { - pub(crate) fn new(db: &dyn DefDatabase, loc: AnonConstLoc, token: TrackedStructToken) -> Self { + pub(crate) fn new( + db: &dyn SourceDatabase, + loc: AnonConstLoc, + token: TrackedStructToken, + ) -> Self { _ = token; AnonConstId::new_(db, loc) } } impl HasModule for AnonConstId { - fn module(&self, db: &dyn DefDatabase) -> ModuleId { + fn module(&self, db: &dyn SourceDatabase) -> ModuleId { self.loc(db).owner.module(db) } } impl HasResolver for AnonConstId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { self.loc(db).owner.resolver(db) } } @@ -492,7 +495,7 @@ impl GeneralConstId { } } - pub fn name(self, db: &dyn DefDatabase) -> String { + pub fn name(self, db: &dyn SourceDatabase) -> String { match self { GeneralConstId::StaticId(it) => { StaticSignature::of(db, it).name.display(db, Edition::CURRENT).to_string() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs index ace361633916c..a465f8be4e175 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs @@ -19,7 +19,6 @@ use hir_def::{ AdtId, ConstId, EnumId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, ModuleDefId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, UnionId, attrs::AttrFlags, - db::DefDatabase, expr_store::Body, hir::Pat, item_tree::FieldsShape, @@ -710,7 +709,7 @@ impl<'a> DeclValidator<'a> { ) where N: AstNode + HasName + fmt::Debug, S: HasSource, - L: Lookup + HasModule + Copy, + L: Lookup + HasModule + Copy, { let to_expected_case_type = match expected_case { CaseType::LowerSnakeCase => to_lower_snake_case, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs index be4de11ceb36b..d04419c5e58b8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs @@ -333,17 +333,20 @@ impl<'db> ExprValidator<'db> { let pattern_arena = Arena::new(); let cx = MatchCheckCtx::new(self.owner.module(self.db()), &self.infcx, self.env); for stmt in &**statements { - let diag = match *stmt { + match *stmt { Statement::Expr { expr: stmt_expr, has_semi: true } if self.validate_lints => { - self.check_unused_must_use(stmt_expr) + let mut diags = Vec::new(); + self.check_unused_must_use(stmt_expr, &mut diags); + self.diagnostics.extend(diags); } Statement::Let { pat, initializer, else_branch: None, .. } => { - self.check_non_exhaustive_let(&cx, &pattern_arena, pat, initializer) + if let Some(diag) = + self.check_non_exhaustive_let(&cx, &pattern_arena, pat, initializer) + { + self.diagnostics.push(diag); + } } - _ => None, - }; - if let Some(diag) = diag { - self.diagnostics.push(diag); + _ => {} } } } @@ -415,7 +418,37 @@ impl<'db> ExprValidator<'db> { pattern } - fn check_unused_must_use(&self, expr: ExprId) -> Option> { + fn check_unused_must_use( + &self, + mut expr: ExprId, + acc: &mut Vec>, + ) { + // Walk through container expressions so that the value-producing leaf is + // checked even when wrapped in a block, `unsafe { .. }`, `if`/`match`, or + // a `const { .. }` block. Single-tail chains are followed by reassigning + // `expr`; branching containers (`if`/`match`) recurse on each arm. + loop { + match &self.body[expr] { + Expr::Block { tail: Some(tail), .. } + | Expr::Unsafe { tail: Some(tail), .. } + | Expr::Const(tail) => expr = *tail, + Expr::If { then_branch, else_branch, .. } => { + self.check_unused_must_use(*then_branch, acc); + if let Some(else_branch) = else_branch { + self.check_unused_must_use(*else_branch, acc); + } + return; + } + Expr::Match { arms, .. } => { + for arm in arms.iter() { + self.check_unused_must_use(arm.expr, acc); + } + return; + } + _ => break, + } + } + let fn_def = match &self.body[expr] { Expr::Call { callee, .. } => { let callee_ty = self.infer.expr_ty(*callee); @@ -430,7 +463,7 @@ impl<'db> ExprValidator<'db> { Expr::MethodCall { .. } => { self.infer.method_resolution(expr).map(|(func, _)| func.into()) } - _ => return None, + _ => None, }; let ty_def = self.infer.type_of_expr_with_adjust(expr).and_then(|ty| match ty.kind() { TyKind::Adt(adt, _) => Some(adt.def_id().into()), @@ -440,7 +473,9 @@ impl<'db> ExprValidator<'db> { AttrFlags::must_use_message(self.db(), owner?) .map(|message| BodyValidationDiagnostic::UnusedMustUse { expr, message }) }; - must_use_diag(fn_def).or_else(|| must_use_diag(ty_def)) + if let Some(diag) = must_use_diag(fn_def).or_else(|| must_use_diag(ty_def)) { + acc.push(diag); + } } fn check_for_trailing_return(&mut self, body_expr: ExprId, body: &Body) { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs index 08860e1e456cd..0a4d016c6a9c0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs @@ -28,10 +28,7 @@ pub fn destructor(db: &dyn HirDatabase, adt: AdtId) -> Option { let interner = DbInterner::new_with(db, module.krate(db)); let drop_trait = interner.lang_items().Drop?; let impls = match module.block(db) { - Some(block) => match TraitImpls::for_block(db, block) { - Some(it) => &**it, - None => return None, - }, + Some(block) => TraitImpls::for_block(db, block)?, None => TraitImpls::for_crate(db, module.krate(db)), }; impls.for_trait_and_self_ty(drop_trait, &SimplifiedType::Adt(adt.into())).0.first().copied() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs index 51c6eeac34af0..1f98fcb46642d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs @@ -9,10 +9,10 @@ //! where parent follows the same scheme. use arrayvec::ArrayVec; +use base_db::SourceDatabase; use hir_def::{ ConstParamId, GenericDefId, GenericParamId, ItemContainerId, LifetimeParamId, Lookup, TypeOrConstParamId, TypeParamId, - db::DefDatabase, expr_store::ExpressionStore, hir::generics::{ GenericParamDataRef, GenericParams, LifetimeParamData, TypeOrConstParamData, @@ -20,7 +20,7 @@ use hir_def::{ }, }; -pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics<'_> { +pub(crate) fn generics(db: &dyn SourceDatabase, def: GenericDefId) -> Generics<'_> { let mut chain = ArrayVec::new(); let mut parent_params_len = 0; if let Some(parent_def) = parent_generic_def(db, def) { @@ -306,7 +306,7 @@ pub(crate) struct ProvenanceSplit { pub(crate) lifetimes: usize, } -fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option { +fn parent_generic_def(db: &dyn SourceDatabase, def: GenericDefId) -> Option { let container = match def { GenericDefId::FunctionId(it) => it.lookup(db).container, GenericDefId::TypeAliasId(it) => it.lookup(db).container, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 1fddfc09c666f..964eb2abc3c98 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -61,11 +61,11 @@ mod tests; use std::{hash::Hash, ops::ControlFlow}; +use base_db::SourceDatabase; use hir_def::{ CallableDefId, ConstId, DefWithBodyId, EnumVariantId, ExpressionStoreOwnerId, FunctionId, GenericDefId, HasModule, LifetimeParamId, ModuleId, StaticId, TypeAliasId, TypeOrConstParamId, TypeParamId, - db::DefDatabase, expr_store::{Body, ExpressionStore}, hir::{BindingId, ExprId, ExprOrPatId, PatId}, resolver::{HasResolver, Resolver, TypeNs}, @@ -566,7 +566,7 @@ impl From for InferBodyId { } impl HasModule for InferBodyId { - fn module(&self, db: &dyn DefDatabase) -> ModuleId { + fn module(&self, db: &dyn SourceDatabase) -> ModuleId { match self { InferBodyId::DefWithBodyId(id) => id.module(db), InferBodyId::AnonConstId(id) => id.module(db), @@ -575,7 +575,7 @@ impl HasModule for InferBodyId { } impl HasResolver for InferBodyId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { match self { InferBodyId::DefWithBodyId(id) => id.resolver(db), InferBodyId::AnonConstId(id) => id.resolver(db), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index b68f664d512e8..2772663ec9ff2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -678,7 +678,7 @@ impl TraitImpls { Arc::new(result) } - #[salsa::tracked(returns(ref))] + #[salsa::tracked(returns(as_deref))] pub fn for_block(db: &dyn HirDatabase, block: BlockId) -> Option> { let _p = tracing::info_span!("inherent_impls_in_block_query").entered(); @@ -687,7 +687,7 @@ impl TraitImpls { if result.map.is_empty() { None } else { Some(Box::new(result)) } } - #[salsa::tracked(returns(ref))] + #[salsa::tracked(returns(deref))] pub fn for_crate_and_deps(db: &dyn HirDatabase, krate: Crate) -> Box<[Arc]> { krate.transitive_deps(db).iter().map(|&dep| Self::for_crate(db, dep).clone()).collect() } @@ -830,7 +830,7 @@ impl TraitImpls { for_each: &mut dyn FnMut(&TraitImpls), ) { let blocks = std::iter::successors(block, |block| block.loc(db).module.block(db)); - blocks.filter_map(|block| Self::for_block(db, block).as_deref()).for_each(&mut *for_each); + blocks.filter_map(|block| Self::for_block(db, block)).for_each(&mut *for_each); Self::for_crate_and_deps(db, krate).iter().map(|it| &**it).for_each(for_each); } @@ -858,11 +858,11 @@ impl TraitImpls { .take_while(move |&block| { other_block.is_none_or(|other_block| other_block != block) }) - .filter_map(move |block| TraitImpls::for_block(db, block).as_deref()) + .filter_map(move |block| TraitImpls::for_block(db, block)) }; if trait_block == type_block { blocks_iter(trait_block) - .filter_map(|block| TraitImpls::for_block(db, block).as_deref()) + .filter_map(|block| TraitImpls::for_block(db, block)) .for_each(for_each); } else { for_each_block(trait_block, type_block).for_each(&mut *for_each); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/probe.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/probe.rs index 84edb510237d6..796a37137e0de 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/probe.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/probe.rs @@ -872,11 +872,11 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> { fn push_candidate(&mut self, candidate: Candidate<'db>, is_inherent: bool) { let is_accessible = if is_inherent { - let candidate_id = match candidate.item { + let candidate_id: AssocItemId = match candidate.item { CandidateId::FunctionId(id) => id.into(), CandidateId::ConstId(id) => id.into(), }; - let visibility = self.db().assoc_visibility(candidate_id); + let visibility = candidate_id.assoc_visibility(self.db()); self.ctx.resolver.is_visible(self.db(), visibility) } else { true diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index b59d6c1cfbe77..7a6cbb8ca3739 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -1100,7 +1100,9 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { let [arg] = args else { return Err(MirEvalError::InternalError("cttz arg is not provided".into())); }; - let result = u128::from_le_bytes(pad16(arg.get(self)?, false)).trailing_zeros(); + let arg: &[u8] = arg.get(self)?; + let bit_count = arg.len() as u32 * 8; + let result = u128::from_le_bytes(pad16(arg, false)).trailing_zeros().min(bit_count); destination .write_from_bytes(self, &(result as u128).to_le_bytes()[0..destination.size]) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index d1277762eb14a..ab7e6df3f5156 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -1404,11 +1404,14 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { expr_id: ExprId, ) -> Result<'db, ()> { if let Expr::Field { expr, name } = &self.store[expr_id] { - if let TyKind::Tuple(..) = self.expr_ty_after_adjustments(*expr).kind() { + if let TyKind::Tuple(tys) = self.expr_ty_after_adjustments(*expr).kind() { let index = name.as_tuple_index().ok_or(MirLowerError::TypeError("named field on tuple"))? as u32; - *place = place.project(ProjectionElem::Field(FieldIndex(index))) + if tys.get(index as usize).is_none() { + return Err(MirLowerError::TypeError("tuple field index out of range")); + } + *place = place.project(ProjectionElem::Field(FieldIndex(index))); } else { let field = self .infer diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs index f273a823ba187..66b51a0e95b51 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -137,7 +137,8 @@ impl<'db> MirLowerCtx<'_, 'db> { } Pat::Wild => (current, current_else), Pat::Tuple { args, ellipsis } => { - let subst = match self.infer.pat_ty(pattern).kind() { + let place_ty = cond_place.ty(&self.result, &self.infcx, self.env).ty; + let subst = match place_ty.kind() { TyKind::Tuple(s) => s, _ => { return Err(MirLowerError::TypeError( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/tests.rs index 8e10284cc1f8a..d8f7d549d6bff 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/tests.rs @@ -108,3 +108,29 @@ pub struct AssocTy { "#, ); } + +#[test] +fn borrowck_tuple_field_projection_recovery_does_not_panic() { + check_borrowck( + r#" +//- minicore: sized +fn tuple_field() { + let t = (1,); + let x = t.1; +} + "#, + ); +} + +#[test] +fn borrowck_alias_projection_recovery_does_not_panic() { + check_borrowck( + r#" +//- minicore: sized +trait Tr { type A; } +fn alias(x: T::A) { + let (a, b) = x; +} + "#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs index 970941ce5afe8..d7036d1056e6a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs @@ -43,7 +43,7 @@ impl Default for TestDB { crates_map: Default::default(), nonce: Nonce::new(), }; - hir_def::db::set_expand_proc_attr_macros(&mut this, true); + hir_def::set_expand_proc_attr_macros(&mut this, true); // This needs to be here otherwise `CrateGraphBuilder` panics. set_all_crates_with_durability(&mut this, std::iter::empty(), Durability::HIGH); _ = base_db::LibraryRoots::builder(Default::default()) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs index 9ffe38e74969e..febd2a833a6a7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs @@ -25,7 +25,7 @@ use hir_def::{ src::HasSource, type_ref::TypeRefId, }; -use hir_expand::{FileRange, InFile, db::ExpandDatabase}; +use hir_expand::{FileRange, InFile}; use itertools::Itertools; use rustc_hash::FxHashMap; use stdx::format_to; @@ -278,7 +278,7 @@ fn expr_node( ) -> Option> { Some(match body_source_map.expr_syntax(expr) { Ok(sp) => { - let root = db.parse_or_expand(sp.file_id); + let root = sp.file_id.parse_or_expand(db); sp.map(|ptr| ptr.to_node(&root).syntax().clone()) } Err(SyntheticSyntax) => return None, @@ -292,7 +292,7 @@ fn pat_node( ) -> Option> { Some(match body_source_map.pat_syntax(pat) { Ok(sp) => { - let root = db.parse_or_expand(sp.file_id); + let root = sp.file_id.parse_or_expand(db); sp.map(|ptr| ptr.to_node(&root).syntax().clone()) } Err(SyntheticSyntax) => return None, @@ -306,7 +306,7 @@ fn type_node( ) -> Option> { Some(match body_source_map.type_syntax(type_ref) { Ok(sp) => { - let root = db.parse_or_expand(sp.file_id); + let root = sp.file_id.parse_or_expand(db); sp.map(|ptr| ptr.to_node(&root).syntax().clone()) } Err(SyntheticSyntax) => return None, @@ -349,7 +349,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { if let Some((binding_id, syntax_ptr)) = self_param { let ty = &inference_result.type_of_binding[binding_id]; if let Some(syntax_ptr) = syntax_ptr { - let root = db.parse_or_expand(syntax_ptr.file_id); + let root = syntax_ptr.file_id.parse_or_expand(&db); let node = syntax_ptr.map(|ptr| ptr.to_node(&root).syntax().clone()); types.push((node, ty.as_ref())); } @@ -361,7 +361,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { } let node = match source_map.pat_syntax(pat) { Ok(sp) => { - let root = db.parse_or_expand(sp.file_id); + let root = sp.file_id.parse_or_expand(&db); sp.map(|ptr| ptr.to_node(&root).syntax().clone()) } Err(SyntheticSyntax) => continue, @@ -375,7 +375,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { for (expr, ty) in inference_result.type_of_expr.iter() { let node = match source_map.expr_syntax(expr) { Ok(sp) => { - let root = db.parse_or_expand(sp.file_id); + let root = sp.file_id.parse_or_expand(&db); sp.map(|ptr| ptr.to_node(&root).syntax().clone()) } Err(SyntheticSyntax) => continue, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs index 4c26b191208ca..3432d47b2f54c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs @@ -34,7 +34,7 @@ fn foo() -> i32 { "source_root_crates", "crate_local_def_map", "file_item_tree_query", - "ast_id_map", + "HirFileId::ast_id_map_", "parse", "real_span_map", "InferenceResult::for_body_", @@ -78,7 +78,7 @@ fn foo() -> i32 { expect_test::expect![[r#" [ "parse", - "ast_id_map", + "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", "AttrFlags::query_", @@ -123,7 +123,7 @@ fn baz() -> i32 { "source_root_crates", "crate_local_def_map", "file_item_tree_query", - "ast_id_map", + "HirFileId::ast_id_map_", "parse", "real_span_map", "InferenceResult::for_body_", @@ -194,7 +194,7 @@ fn baz() -> i32 { expect_test::expect![[r#" [ "parse", - "ast_id_map", + "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", "AttrFlags::query_", @@ -247,7 +247,7 @@ $0", "source_root_crates", "crate_local_def_map", "file_item_tree_query", - "ast_id_map", + "HirFileId::ast_id_map_", "parse", "real_span_map", "TraitImpls::for_crate_", @@ -284,7 +284,7 @@ pub struct NewStruct { expect_test::expect![[r#" [ "parse", - "ast_id_map", + "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", "crate_local_def_map", @@ -322,7 +322,7 @@ $0", "source_root_crates", "crate_local_def_map", "file_item_tree_query", - "ast_id_map", + "HirFileId::ast_id_map_", "parse", "real_span_map", "TraitImpls::for_crate_", @@ -360,7 +360,7 @@ pub enum SomeEnum { expect_test::expect![[r#" [ "parse", - "ast_id_map", + "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", "crate_local_def_map", @@ -398,7 +398,7 @@ $0", "source_root_crates", "crate_local_def_map", "file_item_tree_query", - "ast_id_map", + "HirFileId::ast_id_map_", "parse", "real_span_map", "TraitImpls::for_crate_", @@ -433,7 +433,7 @@ fn bar() -> f32 { expect_test::expect![[r#" [ "parse", - "ast_id_map", + "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", "crate_local_def_map", @@ -475,7 +475,7 @@ $0", "source_root_crates", "crate_local_def_map", "file_item_tree_query", - "ast_id_map", + "HirFileId::ast_id_map_", "parse", "real_span_map", "TraitImpls::for_crate_", @@ -518,7 +518,7 @@ impl SomeStruct { expect_test::expect![[r#" [ "parse", - "ast_id_map", + "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", "crate_local_def_map", @@ -576,7 +576,7 @@ fn main() { "source_root_crates", "crate_local_def_map", "file_item_tree_query", - "ast_id_map", + "HirFileId::ast_id_map_", "parse", "real_span_map", "TraitItems::query_with_diagnostics_", @@ -671,7 +671,7 @@ fn main() { expect_test::expect![[r#" [ "parse", - "ast_id_map", + "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", "crate_local_def_map", diff --git a/src/tools/rust-analyzer/crates/hir/src/db.rs b/src/tools/rust-analyzer/crates/hir/src/db.rs index b8f271108e63e..28af06a0ec9cc 100644 --- a/src/tools/rust-analyzer/crates/hir/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir/src/db.rs @@ -1,8 +1,7 @@ -//! Re-exports various subcrates databases so that the calling code can depend -//! only on `hir`. This breaks abstraction boundary a bit, it would be cool if -//! we didn't do that. +//! Re-exports various subcrates' databases and queries so that the calling code +//! can depend only on `hir`. This breaks abstraction boundary a bit, it would +//! be cool if we didn't do that. //! //! But we need this for at least LRU caching at the query level. -pub use hir_def::db::{DefDatabase, set_expand_proc_attr_macros}; -pub use hir_expand::db::ExpandDatabase; +pub use hir_def::{file_item_tree, set_expand_proc_attr_macros}; pub use hir_ty::db::HirDatabase; diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index c551cfac79958..cfb967f486247 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -1013,7 +1013,7 @@ impl<'db> AnyDiagnostic<'db> { } InferenceDiagnostic::PathDiagnostic { node, diag } => { let source = expr_or_pat_syntax(*node)?; - let syntax = source.value.to_node(&db.parse_or_expand(source.file_id)); + let syntax = source.value.to_node(&source.file_id.parse_or_expand(db)); let path = match_ast! { match (syntax.syntax()) { ast::RecordExpr(it) => it.path()?, @@ -1316,7 +1316,7 @@ impl<'db> AnyDiagnostic<'db> { Some(match diag { TyLoweringDiagnostic::PathDiagnostic { source, diag } => { let source = Self::type_syntax(*source, source_map)?; - let syntax = source.value.to_node(&db.parse_or_expand(source.file_id)); + let syntax = source.value.to_node(&source.file_id.parse_or_expand(db)); let ast::Type::PathType(syntax) = syntax else { return None }; Self::path_diagnostic(diag, source.with_value(syntax.path()?))? } diff --git a/src/tools/rust-analyzer/crates/hir/src/has_source.rs b/src/tools/rust-analyzer/crates/hir/src/has_source.rs index 9bff8bda3a96d..9248aaec02097 100644 --- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/has_source.rs @@ -297,7 +297,7 @@ impl HasSource for Param<'_> { let (_, source_map) = ExpressionStore::with_source_map(db, owner.expression_store_owner(db)); let ast @ InFile { file_id, value } = source_map.expr_syntax(expr_id).ok()?; - let root = db.parse_or_expand(file_id); + let root = file_id.parse_or_expand(db); match value.to_node(&root) { Either::Left(ast::Expr::ClosureExpr(it)) => it .param_list()? diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 8d21b351e42cd..fc04ea1f4978e 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -46,7 +46,7 @@ use std::{ }; use arrayvec::ArrayVec; -use base_db::{CrateDisplayName, CrateOrigin, LangCrateOrigin, all_crates}; +use base_db::{CrateDisplayName, CrateOrigin, LangCrateOrigin, SourceDatabase, all_crates}; use either::Either; use hir_def::{ AdtId, AssocItemId, AssocItemLoc, BuiltinDeriveImplId, CallableDefId, ConstId, ConstParamId, @@ -115,7 +115,7 @@ use syntax::{ }; use triomphe::Arc; -use crate::db::{DefDatabase, HirDatabase}; +use crate::db::HirDatabase; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum PredicateEvaluationStatus { @@ -294,7 +294,7 @@ impl Crate { self.id .transitive_deps(db) .into_iter() - .filter_map(|krate| db.crate_notable_traits(krate)) + .filter_map(|krate| hir_def::crate_notable_traits(db, krate)) .flatten() } @@ -325,7 +325,7 @@ impl Crate { pub fn query_external_importables( self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, query: import_map::Query, ) -> impl Iterator, Complete)> { let _p = tracing::info_span!("query_external_importables").entered(); @@ -813,7 +813,7 @@ impl Module { expr_store_diagnostics(db, acc, source_map); let (variants, diagnostics) = e.id.enum_variants_with_diagnostics(db); let file = e.id.lookup(db).id.file_id; - let ast_id_map = db.ast_id_map(file); + let ast_id_map = file.ast_id_map(db); for diag in diagnostics { acc.push( InactiveCode { @@ -883,7 +883,7 @@ impl Module { .iter() .for_each(|&(_ast, call_id)| macro_call_diagnostics(db, call_id, acc)); - let ast_id_map = db.ast_id_map(file_id); + let ast_id_map = file_id.ast_id_map(db); for diag in impl_id.impl_items_with_diagnostics(db).1.iter() { emit_def_diagnostic(db, acc, diag, edition, loc.container.krate(db)); @@ -1109,7 +1109,7 @@ impl Module { /// this module, if possible. pub fn find_path( self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, item: impl Into, cfg: FindPathConfig, ) -> Option { @@ -1127,7 +1127,7 @@ impl Module { /// this module, if possible. This is used for returning import paths for use-statements. pub fn find_use_path( self, - db: &dyn DefDatabase, + db: &dyn SourceDatabase, item: impl Into, prefix_kind: PrefixKind, cfg: FindPathConfig, @@ -1159,7 +1159,7 @@ fn macro_call_diagnostics<'db>( macro_call_id: MacroCallId, acc: &mut Vec>, ) { - let Some(e) = db.parse_macro_expansion_error(macro_call_id) else { + let Some(e) = macro_call_id.parse_macro_expansion_error(db) else { return; }; let ValueResult { value: parse_errors, err } = e; @@ -1170,7 +1170,7 @@ fn macro_call_diagnostics<'db>( let RenderedExpandError { message, error, kind } = err.render_to_string(db); if Some(err.span().anchor.file_id) == file_id.file_id().map(|it| it.span_file_id(db)) { range.value = err.span().range - + db.ast_id_map(file_id).get_erased(err.span().anchor.ast_id).text_range().start(); + + file_id.ast_id_map(db).get_erased(err.span().anchor.ast_id).text_range().start(); } acc.push(MacroError { range, message, error, kind }.into()); } @@ -1187,10 +1187,10 @@ fn emit_macro_def_diagnostics<'db>( acc: &mut Vec>, m: Macro, ) { - let id = db.macro_def(m.id); + let id = m.id.definition(db); let krate = id.krate; if let hir_expand::MacroDefKind::Declarative(ast, _) = id.kind - && let expander = db.decl_macro_expander(krate, ast) + && let expander = ast.decl_macro_expander(db, krate) && let Some(e) = expander.mac.err() { let edition = krate.data(db).edition; @@ -1260,7 +1260,7 @@ fn emit_def_diagnostic_<'db>( } DefDiagnosticKind::UnconfiguredCode { ast_id, cfg, opts } => { - let ast_id_map = db.ast_id_map(ast_id.file_id); + let ast_id_map = ast_id.file_id.ast_id_map(db); let ptr = ast_id_map.get_erased(ast_id.value); acc.push( InactiveCode { @@ -2827,7 +2827,7 @@ impl SelfParam { impl HasVisibility for Function { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { match self.id { - AnyFunctionId::FunctionId(id) => db.assoc_visibility(id.into()), + AnyFunctionId::FunctionId(id) => AssocItemId::from(id).assoc_visibility(db), AnyFunctionId::BuiltinDeriveImplMethod { .. } => Visibility::Public, } } @@ -2929,7 +2929,7 @@ impl Const { impl HasVisibility for Const { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { - db.assoc_visibility(self.id.into()) + AssocItemId::from(self.id).assoc_visibility(db) } } @@ -3159,7 +3159,7 @@ impl TypeAlias { impl HasVisibility for TypeAlias { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { - db.assoc_visibility(self.id.into()) + AssocItemId::from(self.id).assoc_visibility(db) } } @@ -3622,7 +3622,7 @@ fn as_assoc_item<'db, ID, DEF, LOC>( id: ID, ) -> Option where - ID: Lookup>, + ID: Lookup>, DEF: From, LOC: AstIdNode, { @@ -3638,7 +3638,7 @@ fn as_extern_assoc_item<'db, ID, DEF, LOC>( id: ID, ) -> Option where - ID: Lookup>, + ID: Lookup>, DEF: From, LOC: AstIdNode, { @@ -4715,7 +4715,7 @@ impl Impl { &mut |impls| extend_with_impls(Either::Left(impls.for_self_ty(&simplified_ty))), ); iter::successors(module.block(db), |block| block.loc(db).module.block(db)) - .filter_map(|block| TraitImpls::for_block(db, block).as_deref()) + .filter_map(|block| TraitImpls::for_block(db, block)) .for_each(|impls| impls.for_self_ty(&simplified_ty, &mut extend_with_impls)); for &krate in &*all_crates(db) { TraitImpls::for_crate(db, krate) diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index dcbd6c37af52d..ba488b8af35e5 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -26,7 +26,6 @@ use hir_expand::{ EditionedFileId, ExpandResult, FileRange, HirFileId, InMacroFile, MacroCallId, attrs::AstPathExt, builtin::{BuiltinFnLikeExpander, EagerExpander}, - db::ExpandDatabase, files::{FileRangeWrapper, HirFileRange, InRealFile}, mod_path::{ModPath, PathKind}, name::AsName, @@ -550,7 +549,7 @@ impl<'db> SemanticsImpl<'db> { } pub fn parse_or_expand(&self, file_id: HirFileId) -> SyntaxNode { - let node = self.db.parse_or_expand(file_id); + let node = file_id.parse_or_expand(self.db); self.cache(node.clone(), file_id); node } @@ -564,7 +563,7 @@ impl<'db> SemanticsImpl<'db> { } pub fn expand(&self, file_id: MacroCallId) -> ExpandResult { - let res = self.db.parse_macro_expansion(file_id).as_ref().map(|it| it.0.syntax_node()); + let res = file_id.parse_macro_expansion(self.db).as_ref().map(|it| it.0.syntax_node()); self.cache(res.value.clone(), file_id.into()); res } @@ -661,7 +660,7 @@ impl<'db> SemanticsImpl<'db> { .into_iter() .map(|call| { let file_id = call?.left()?; - let ExpandResult { value, err } = self.db.parse_macro_expansion(file_id); + let ExpandResult { value, err } = file_id.parse_macro_expansion(self.db); let root_node = value.0.syntax_node(); self.cache(root_node.clone(), file_id.into()); Some(ExpandResult { value: root_node, err: err.clone() }) @@ -690,7 +689,7 @@ impl<'db> SemanticsImpl<'db> { pub fn derive_helpers_in_scope(&self, adt: &ast::Adt) -> Option> { let sa = self.analyze_no_infer(adt.syntax())?; - let id = self.db.ast_id_map(sa.file_id).ast_id(adt); + let id = sa.file_id.ast_id_map(self.db).ast_id(adt); let result = sa .resolver .def_map() @@ -713,7 +712,7 @@ impl<'db> SemanticsImpl<'db> { })?; let attr_name = attr.path().and_then(|it| it.as_single_name_ref())?.as_name(); let sa = self.analyze_no_infer(adt.syntax())?; - let id = self.db.ast_id_map(sa.file_id).ast_id(&adt); + let id = sa.file_id.ast_id_map(self.db).ast_id(&adt); let res: Vec<_> = sa .resolver .def_map() @@ -739,12 +738,7 @@ impl<'db> SemanticsImpl<'db> { token_to_map: SyntaxToken, ) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> { let macro_file = self.to_def(actual_macro_call)?; - hir_expand::db::expand_speculative( - self.db, - macro_file, - speculative_args.syntax(), - token_to_map, - ) + self.speculative_expand_raw(macro_file, speculative_args.syntax(), token_to_map) } pub fn speculative_expand_raw( @@ -753,7 +747,7 @@ impl<'db> SemanticsImpl<'db> { speculative_args: &SyntaxNode, token_to_map: SyntaxToken, ) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> { - hir_expand::db::expand_speculative(self.db, macro_file, speculative_args, token_to_map) + macro_file.expand_speculative(self.db, speculative_args, token_to_map) } /// Expand the macro call with a different item as the input, mapping the `token_to_map` down into the @@ -766,12 +760,7 @@ impl<'db> SemanticsImpl<'db> { ) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> { let macro_call = self.wrap_node_infile(actual_macro_call.clone()); let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(macro_call.as_ref()))?; - hir_expand::db::expand_speculative( - self.db, - macro_call_id, - speculative_args.syntax(), - token_to_map, - ) + self.speculative_expand_raw(macro_call_id, speculative_args.syntax(), token_to_map) } pub fn speculative_expand_derive_as_pseudo_attr_macro( @@ -789,12 +778,7 @@ impl<'db> SemanticsImpl<'db> { ) .map(|(_, it, _)| it) })?; - hir_expand::db::expand_speculative( - self.db, - macro_call_id, - speculative_args.syntax(), - token_to_map, - ) + self.speculative_expand_raw(macro_call_id, speculative_args.syntax(), token_to_map) } /// Checks if renaming `renamed` to `new_name` may introduce conflicts with other locals, @@ -1002,7 +986,8 @@ impl<'db> SemanticsImpl<'db> { else { return tok.into(); }; - let span = self.db.real_span_map(tok.file_id).span_for_range(tok.value.text_range()); + let span = + HirFileId::from(tok.file_id).span_map(self.db).span_for_range(tok.value.text_range()); let Some(InMacroFile { file_id, value: mut mapped_tokens }) = self.with_ctx(|ctx| { Some( ctx.cache @@ -1254,7 +1239,7 @@ impl<'db> SemanticsImpl<'db> { let _p = tracing::info_span!("descend_into_macros_impl").entered(); let db = self.db; - let span = db.span_map(file_id).span_for_range(token.text_range()); + let span = file_id.span_map(db).span_for_range(token.text_range()); // Process the expansion of a call, pushing all tokens with our span in the expansion back onto our stack let process_expansion_for_token = @@ -1498,7 +1483,7 @@ impl<'db> SemanticsImpl<'db> { self.analyze_impl(InFile::new(expansion, &parent), None, false) })? .resolver; - let id = db.ast_id_map(expansion).ast_id(&adt); + let id = expansion.ast_id_map(db).ast_id(&adt); let helpers = resolver .def_map() .derive_helpers_in_scope(InFile::new(expansion, id))?; @@ -1979,8 +1964,7 @@ impl<'db> SemanticsImpl<'db> { } pub fn resolve_macro_call_arm(&self, macro_call: &ast::MacroCall) -> Option { - let file_id = self.to_def(macro_call)?; - self.db.parse_macro_expansion(file_id).value.1.matched_arm + self.to_def(macro_call)?.expansion_span_map(self.db).matched_arm } pub fn get_unsafe_ops(&self, def: ExpressionStoreOwner) -> FxHashSet { @@ -2619,7 +2603,7 @@ fn macro_call_to_macro_id( ctx: &mut SourceToDefCtx<'_, '_>, macro_call_id: MacroCallId, ) -> Option { - let db: &dyn ExpandDatabase = ctx.db; + let db = ctx.db; let loc = macro_call_id.loc(db); match loc.def.ast_id() { diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs index 97c5a451ab6b8..bca8c8c503dfd 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs @@ -4,6 +4,7 @@ //! This module allows one to go in the opposite direction: start with a syntax //! node for a *child*, and get its hir. +use base_db::SourceDatabase; use either::Either; use hir_expand::HirFileId; use span::AstIdNode; @@ -13,7 +14,6 @@ use hir_def::{ AdtId, AssocItemId, AstIdLoc, DefWithBodyId, EnumId, FieldId, GenericDefId, ImplId, LifetimeParamId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, TypeOrConstParamId, VariantId, - db::DefDatabase, dyn_map::{ DynMap, keys::{self, Key}, @@ -26,16 +26,16 @@ use hir_def::{ }; pub(crate) trait ChildBySource { - fn child_by_source(&self, db: &dyn DefDatabase, file_id: HirFileId) -> DynMap { + fn child_by_source(&self, db: &dyn SourceDatabase, file_id: HirFileId) -> DynMap { let mut res = DynMap::default(); self.child_by_source_to(db, &mut res, file_id); res } - fn child_by_source_to(&self, db: &dyn DefDatabase, map: &mut DynMap, file_id: HirFileId); + fn child_by_source_to(&self, db: &dyn SourceDatabase, map: &mut DynMap, file_id: HirFileId); } impl ChildBySource for TraitId { - fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { + fn child_by_source_to(&self, db: &dyn SourceDatabase, res: &mut DynMap, file_id: HirFileId) { let data = self.trait_items(db); data.macro_calls().filter(|(ast_id, _)| ast_id.file_id == file_id).for_each( @@ -61,7 +61,7 @@ impl ChildBySource for TraitId { } impl ChildBySource for ImplId { - fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { + fn child_by_source_to(&self, db: &dyn SourceDatabase, res: &mut DynMap, file_id: HirFileId) { let data = self.impl_items(db); data.macro_calls().filter(|(ast_id, _)| ast_id.file_id == file_id).for_each( |(ast_id, call_id)| { @@ -86,7 +86,7 @@ impl ChildBySource for ImplId { } impl ChildBySource for ModuleId { - fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { + fn child_by_source_to(&self, db: &dyn SourceDatabase, res: &mut DynMap, file_id: HirFileId) { let def_map = self.def_map(db); let module_data = &def_map[*self]; module_data.scope.child_by_source_to(db, res, file_id); @@ -94,7 +94,7 @@ impl ChildBySource for ModuleId { } impl ChildBySource for ItemScope { - fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { + fn child_by_source_to(&self, db: &dyn SourceDatabase, res: &mut DynMap, file_id: HirFileId) { self.declarations().for_each(|item| add_module_def(db, res, file_id, item)); self.impls().for_each(|imp| insert_item_loc(db, res, file_id, imp, keys::IMPL)); self.extern_blocks().for_each(|extern_block| { @@ -139,7 +139,7 @@ impl ChildBySource for ItemScope { }, ); fn add_module_def( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, map: &mut DynMap, file_id: HirFileId, item: ModuleDefId, @@ -177,7 +177,7 @@ impl ChildBySource for ItemScope { } impl ChildBySource for VariantId { - fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, _: HirFileId) { + fn child_by_source_to(&self, db: &dyn SourceDatabase, res: &mut DynMap, _: HirFileId) { let arena_map = self.child_source(db); let arena_map = arena_map.as_ref(); let parent = *self; @@ -194,13 +194,13 @@ impl ChildBySource for VariantId { } impl ChildBySource for EnumId { - fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { + fn child_by_source_to(&self, db: &dyn SourceDatabase, res: &mut DynMap, file_id: HirFileId) { let loc = &self.lookup(db); if file_id != loc.id.file_id { return; } - let ast_id_map = db.ast_id_map(loc.id.file_id); + let ast_id_map = loc.id.file_id.ast_id_map(db); self.enum_variants(db).variants.values().for_each(|&(variant, _)| { res[keys::ENUM_VARIANT].insert(ast_id_map.get(variant.lookup(db).id.value), variant); @@ -214,7 +214,7 @@ impl ChildBySource for EnumId { } impl ChildBySource for DefWithBodyId { - fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { + fn child_by_source_to(&self, db: &dyn SourceDatabase, res: &mut DynMap, file_id: HirFileId) { let (body, sm) = Body::with_source_map(db, *self); if let &DefWithBodyId::VariantId(v) = self { VariantId::EnumVariantId(v).child_by_source_to(db, res, file_id) @@ -234,7 +234,7 @@ impl ChildBySource for DefWithBodyId { } impl ChildBySource for GenericDefId { - fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { + fn child_by_source_to(&self, db: &dyn SourceDatabase, res: &mut DynMap, file_id: HirFileId) { let (gfile_id, generic_params_list) = self.file_id_and_params_of(db); if gfile_id != file_id { return; @@ -277,13 +277,13 @@ impl ChildBySource for GenericDefId { } fn insert_item_loc( - db: &dyn DefDatabase, + db: &dyn SourceDatabase, res: &mut DynMap, file_id: HirFileId, id: ID, key: Key, ) where - ID: Lookup + 'static, + ID: Lookup + 'static, Data: AstIdLoc, N: AstIdNode + 'static, { @@ -293,7 +293,12 @@ fn insert_item_loc( } } -fn add_assoc_item(db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId, item: AssocItemId) { +fn add_assoc_item( + db: &dyn SourceDatabase, + res: &mut DynMap, + file_id: HirFileId, + item: AssocItemId, +) { match item { AssocItemId::FunctionId(func) => insert_item_loc(db, res, file_id, func, keys::FUNCTION), AssocItemId::ConstId(konst) => insert_item_loc(db, res, file_id, konst, keys::CONST), diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs index 8118730f24e14..f7528d3db10b2 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs @@ -149,10 +149,10 @@ impl<'db> SourceToDefCache<'db> { return m; } self.included_file_cache.insert(file, None); - for &crate_id in relevant_crates(db, file.file_id(db)).iter() { - db.include_macro_invoc(crate_id).iter().for_each(|&(macro_call_id, file_id)| { + for &crate_id in relevant_crates(db, file.file_id(db)) { + for &(macro_call_id, file_id) in hir_def::include_macro_invoc(db, crate_id) { self.included_file_cache.insert(file_id, Some(macro_call_id)); - }); + } } self.included_file_cache.get(&file).copied().flatten() } @@ -184,7 +184,7 @@ impl SourceToDefCtx<'_, '_> { self.cache.file_to_def_cache.entry(file).or_insert_with(|| { let mut mods = SmallVec::new(); - for &crate_id in relevant_crates(self.db, file).iter() { + for &crate_id in relevant_crates(self.db, file) { // Note: `mod` declarations in block modules cannot be supported here let crate_def_map = crate_def_map(self.db, crate_id); let n_mods = mods.len(); @@ -192,8 +192,7 @@ impl SourceToDefCtx<'_, '_> { mods.extend(modules(file)); if mods.len() == n_mods { mods.extend( - self.db - .include_macro_invoc(crate_id) + hir_def::include_macro_invoc(self.db, crate_id) .iter() .filter(|&&(_, file_id)| file_id.file_id(self.db) == file) .flat_map(|&(macro_call_id, file_id)| { diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index fc03f82135df5..21830f9d0d78e 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -1366,7 +1366,7 @@ impl<'db> SourceAnalyzer<'db> { }, ); if let Some(adt) = adt { - let ast_id = db.ast_id_map(self.file_id).ast_id(&adt); + let ast_id = self.file_id.ast_id_map(db).ast_id(&adt); if let Some(helpers) = self .resolver .def_map() @@ -1427,11 +1427,10 @@ impl<'db> SourceAnalyzer<'db> { let ty = if let Some(expr) = ast::Expr::cast(parent.clone()) { let expr_id = self.expr_id(expr)?; self.infer()?.type_of_expr_or_pat(expr_id)? - } else if let Some(pat) = ast::Pat::cast(parent) { + } else { + let pat = ast::Pat::cast(parent)?; let pat_id = self.pat_id(&pat)?; self.infer()?.expr_or_pat_ty(pat_id) - } else { - return None; }; let (subst, expected_resolution) = match ty.kind() { TyKind::Adt(adt_def, subst) => { @@ -2108,7 +2107,7 @@ pub(crate) fn name_hygiene(db: &dyn HirDatabase, name: InFile<&SyntaxNode>) -> H let Some(macro_file) = name.file_id.macro_file() else { return HygieneId::ROOT; }; - let span_map = db.expansion_span_map(macro_file); + let span_map = macro_file.expansion_span_map(db); let ctx = span_map.span_at(name.value.text_range().start()).ctx; HygieneId::new(ctx.opaque_and_semiopaque(db)) } diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs index c4040c1c0099b..021a20ae1b71e 100644 --- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs +++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs @@ -7,7 +7,6 @@ use either::Either; use hir_def::{ AdtId, AssocItemId, AstIdLoc, Complete, DefWithBodyId, ExternCrateId, HasModule, ImplId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, - db::DefDatabase, expr_store::Body, item_scope::{ImportId, ImportOrExternCrate, ImportOrGlob}, nameres::crate_def_map, @@ -410,7 +409,7 @@ impl<'a> SymbolCollector<'a> { ); self.with_container_name(impl_name.as_deref().map(Symbol::intern), |s| { for &(ref name, assoc_item_id) in &impl_id.impl_items(self.db).items { - if s.collect_pub_only && s.db.assoc_visibility(assoc_item_id) != Visibility::Public + if s.collect_pub_only && assoc_item_id.assoc_visibility(s.db) != Visibility::Public { continue; } @@ -460,7 +459,7 @@ impl<'a> SymbolCollector<'a> { trait_do_not_complete: Option, ) -> Complete where - L: Lookup + Into, + L: Lookup + Into, ::Data: HasSource, <::Data as HasSource>::Value: HasName, { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs index 1e8fb51a3e18a..6e07f5f99238f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -2704,4 +2704,23 @@ impl Drop for Foo { "#, ); } + + #[test] + fn issue_10326() { + check_assist( + add_missing_impl_members, + r#" +trait A { fn a(&self) -> &T; } +trait B {} +impl<'a, T: B> A for T {$0}"#, + r#" +trait A { fn a(&self) -> &T; } +trait B {} +impl<'a, T: B> A for T { + fn a(&self) -> &(dyn 'a + B) { + ${0:todo!()} + } +}"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 632fe0d72cfa5..8e39cfc49c166 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -573,7 +573,7 @@ fn resolve_tuple_of_enum_def( }) }) .collect::>>() - .and_then(|list| if list.is_empty() { None } else { Some(list) }) + .filter(|list| !list.is_empty()) } fn resolve_array_of_enum_def( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/change_visibility.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/change_visibility.rs index f17197a75055a..18d7faeb2b029 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/change_visibility.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/change_visibility.rs @@ -67,14 +67,13 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> { } check_is_not_variant(&field)?; (vis_offset(field.syntax()), field_name.syntax().text_range()) - } else if let Some(field) = ctx.find_node_at_offset::() { + } else { + let field = ctx.find_node_at_offset::()?; if field.visibility().is_some() { return None; } check_is_not_variant(&field)?; (vis_offset(field.syntax()), field.syntax().text_range()) - } else { - return None; }; acc.add( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs index 86dbf20facb6c..0bd9d1a23aeff 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs @@ -72,13 +72,11 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_, '_>) - let node = if ctx.has_empty_selection() { if let Some(t) = ctx.token_at_offset().find(|it| it.kind() == T![;]) { t.parent().and_then(ast::ExprStmt::cast)?.syntax().clone() - } else if let Some(expr) = ancestors_at_offset(ctx.source_file().syntax(), ctx.offset()) - .next() - .and_then(ast::Expr::cast) - { - expr.syntax().ancestors().find_map(valid_target_expr(ctx))?.syntax().clone() } else { - return None; + let expr = ancestors_at_offset(ctx.source_file().syntax(), ctx.offset()) + .next() + .and_then(ast::Expr::cast)?; + expr.syntax().ancestors().find_map(valid_target_expr(ctx))?.syntax().clone() } } else { match ctx.covering_element() { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs index 867eaf4c2987f..53e77b49474c4 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs @@ -141,7 +141,7 @@ impl Method { }; let variant_name = variant.name()?; - let fn_name = format!("is_{}", &to_lower_snake_case(&variant_name.text())); + let fn_name = format!("is_{}", to_lower_snake_case(&variant_name.text())); Some(Method { pattern_suffix, fn_name, variant_name }) } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs index 4cdc801ec19d6..8a194ae02bff0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs @@ -219,7 +219,7 @@ impl Method { fn new(variant: &ast::Variant, fn_name_prefix: &str) -> Option { use itertools::Itertools as _; let variant_name = variant.name()?; - let fn_name = format!("{fn_name_prefix}_{}", &to_lower_snake_case(&variant_name.text())); + let fn_name = format!("{fn_name_prefix}_{}", to_lower_snake_case(&variant_name.text())); match variant.kind() { ast::StructKind::Record(record) => { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs index 14dd4061e72f5..3c3fde80f99e7 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs @@ -491,7 +491,7 @@ fn get_fn_target( let mut file = ctx.vfs_file_id(); let target = match target_module { Some(target_module) => { - let (in_file, target) = next_space_for_fn_in_module(ctx.db(), target_module); + let (in_file, target) = next_space_for_fn_in_module(ctx.db(), target_module)?; file = in_file; target } @@ -1310,7 +1310,7 @@ fn next_space_for_fn_after_call_site(expr: ast::CallableExpr) -> Option (FileId, GeneratedFunctionTarget) { +) -> Option<(FileId, GeneratedFunctionTarget)> { let module_source = target_module.definition_source(db); let file = module_source.file_id.original_file(db); let assist_item = match &module_source.value { @@ -1318,14 +1318,13 @@ fn next_space_for_fn_in_module( Some(last_item) => GeneratedFunctionTarget::AfterItem(last_item.syntax().clone()), None => GeneratedFunctionTarget::AfterItem(it.syntax().clone()), }, - hir::ModuleSource::Module(it) => match it.item_list().and_then(|it| it.items().last()) { - Some(last_item) => GeneratedFunctionTarget::AfterItem(last_item.syntax().clone()), - None => { - let item_list = - it.item_list().expect("module definition source should have an item list"); - GeneratedFunctionTarget::InEmptyItemList(item_list.syntax().clone()) + hir::ModuleSource::Module(it) => { + let item_list = it.item_list()?; + match item_list.items().last() { + Some(last_item) => GeneratedFunctionTarget::AfterItem(last_item.syntax().clone()), + None => GeneratedFunctionTarget::InEmptyItemList(item_list.syntax().clone()), } - }, + } hir::ModuleSource::BlockExpr(it) => { if let Some(last_item) = it.statements().take_while(|stmt| matches!(stmt, ast::Stmt::Item(_))).last() @@ -1337,7 +1336,7 @@ fn next_space_for_fn_in_module( } }; - (file.file_id(db), assist_item) + Some((file.file_id(db), assist_item)) } #[derive(Clone, Copy)] @@ -2459,6 +2458,20 @@ pub(crate) fn bar() { ) } + #[test] + fn add_function_not_applicable_in_unresolved_module() { + check_assist_not_applicable( + generate_function, + r" +mod foo; + +fn main() { + foo::bar$0(); +} +", + ) + } + #[test] fn add_function_with_return_type() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs index a14b30db42896..438966a1d67dd 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs @@ -1,11 +1,7 @@ use std::collections::BTreeSet; use either::Either; -use hir::{ - FileRange, PathResolution, Semantics, TypeInfo, - db::{ExpandDatabase, HirDatabase}, - sym, -}; +use hir::{FileRange, PathResolution, Semantics, TypeInfo, db::HirDatabase, sym}; use ide_db::{ EditionedFileId, FxHashMap, RootDatabase, base_db::Crate, @@ -352,7 +348,7 @@ fn inline( let file_id = sema.hir_file_for(fn_body.syntax()); let body_to_clone = if let Some(macro_file) = file_id.macro_file() { cov_mark::hit!(inline_call_defined_in_macro); - let span_map = sema.db.expansion_span_map(macro_file); + let span_map = macro_file.expansion_span_map(sema.db); let body_prettified = prettify_macro_expansion(sema.db, fn_body.syntax().clone(), span_map, *krate); if let Some(body) = ast::BlockExpr::cast(body_prettified) { body } else { fn_body.clone() } @@ -496,7 +492,7 @@ fn inline( let param_ty = param_ty.clone().map(|param_ty| { let file_id = sema.hir_file_for(param_ty.syntax()); if let Some(macro_file) = file_id.macro_file() { - let span_map = sema.db.expansion_span_map(macro_file); + let span_map = macro_file.expansion_span_map(sema.db); let param_ty_prettified = prettify_macro_expansion( sema.db, param_ty.syntax().clone(), diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs index f4ac75d2290dd..5a185637df4ef 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs @@ -1,4 +1,3 @@ -use hir::db::ExpandDatabase; use ide_db::syntax_helpers::prettify_macro_expansion; use syntax::ast::{self, AstNode, edit::IndentLevel}; @@ -58,7 +57,7 @@ pub(crate) fn inline_macro(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Op text_range, |builder| { let expanded = ctx.sema.parse_or_expand(macro_call.into()); - let span_map = ctx.sema.db.expansion_span_map(macro_call); + let span_map = macro_call.expansion_span_map(ctx.sema.db); // Don't call `prettify_macro_expansion()` outside the actual assist action; it does some heavy rowan tree manipulation, // which can be very costly for big macros when it is done *even without the assist being invoked*. let expanded = prettify_macro_expansion(ctx.db(), expanded, span_map, target_crate_id); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs index c0356337057ba..2d3b1b05400c3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs @@ -824,6 +824,17 @@ mod top { } use top::{a::A, b::{B as D, B as C}}; +", + ); + } + + #[test] + fn test_merge_with_trailing_path_separator() { + check_assist_not_applicable( + merge_imports, + r" +use foo::bar; +use foo::$0; ", ); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_underscore.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_underscore.rs index 1ccdcda52d976..1b65e78378f23 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_underscore.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_underscore.rs @@ -37,7 +37,8 @@ pub(crate) fn remove_underscore(acc: &mut Assists, ctx: &AssistContext<'_, '_>) _ => return None, }; (text.to_owned(), name_ref.syntax().text_range(), def) - } else if let Some(name_ref) = ctx.find_node_at_offset::() { + } else { + let name_ref = ctx.find_node_at_offset::()?; let text = name_ref.text(); if !text.starts_with('_') { return None; @@ -48,8 +49,6 @@ pub(crate) fn remove_underscore(acc: &mut Assists, ctx: &AssistContext<'_, '_>) _ => return None, }; (text.to_owned(), name_ref.syntax().text_range(), def) - } else { - return None; }; if !def.usages(&ctx.sema).at_least_one() { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs index 36ee300ca9acf..9a61163e87e71 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs @@ -1,4 +1,3 @@ -use hir::db::ExpandDatabase; use itertools::Itertools; use std::iter::successors; @@ -512,7 +511,7 @@ fn pretty_pat_inside_macro( let pretty_node = hir::prettify_macro_expansion( db, pat, - db.expansion_span_map(file_id), + file_id.expansion_span_map(db), scope.module().krate(db).into(), ); ast::Pat::cast(pretty_node) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs index 2c4fb5f405a77..344beb32ae0e9 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -5,7 +5,7 @@ use std::slice; pub(crate) use gen_trait_fn_body::gen_trait_fn_body; use hir::{ HasAttrs as HirHasAttrs, HirDisplay, InFile, ModuleDef, PathResolution, Semantics, - db::{ExpandDatabase, HirDatabase}, + db::HirDatabase, }; use ide_db::{ RootDatabase, @@ -241,7 +241,7 @@ pub fn add_trait_assoc_items_to_impl( .map(|InFile { file_id, value: original_item }| { let mut cloned_item = { if let Some(macro_file) = file_id.macro_file() { - let span_map = sema.db.expansion_span_map(macro_file); + let span_map = macro_file.expansion_span_map(sema.db); let item_prettified = prettify_macro_expansion( sema.db, original_item.syntax().clone(), diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs index c165a32082dfc..a705bca63fbc5 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs @@ -31,7 +31,7 @@ //! } //! ``` -use hir::{MacroCallId, Name, db::ExpandDatabase}; +use hir::{MacroCallId, Name}; use ide_db::text_edit::TextEdit; use ide_db::{ SymbolKind, documentation::HasDocs, path_transform::PathTransform, @@ -265,6 +265,7 @@ fn get_transformed_assoc_item( ctx: &CompletionContext<'_, '_>, assoc_item: ast::AssocItem, impl_def: hir::Impl, + macro_file: Option, ) -> Option { let trait_ = impl_def.trait_(ctx.db)?; let source_scope = &ctx.sema.scope(assoc_item.syntax())?; @@ -278,7 +279,16 @@ fn get_transformed_assoc_item( let assoc_item = ast::AssocItem::cast(transform.apply(assoc_item.syntax()))?; let (editor, assoc_item) = SyntaxEditor::with_ast_node(&assoc_item); assoc_item.remove_attrs_and_docs(&editor); - ast::AssocItem::cast(editor.finish().new_root().clone()) + let transformed = editor.finish().new_root().clone(); + + let prettied = if let Some(macro_file) = macro_file { + let span_map = macro_file.expansion_span_map(ctx.db); + prettify_macro_expansion(ctx.db, transformed, span_map, ctx.krate.into()) + } else { + transformed + }; + + ast::AssocItem::cast(prettied) } /// Transform a relevant associated item to inline generics from the impl, remove attrs and docs, etc. @@ -383,7 +393,9 @@ fn add_type_alias_impl( if let Some(source) = ctx.sema.source(type_alias) { let assoc_item = ast::AssocItem::TypeAlias(source.value); - if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) { + if let Some(transformed_item) = + get_transformed_assoc_item(ctx, assoc_item, impl_def, source.file_id.macro_file()) + { let transformed_ty = match transformed_item { ast::AssocItem::TypeAlias(ty) => ty, _ => unreachable!(), @@ -458,14 +470,15 @@ fn add_const_impl( && let Some(source) = ctx.sema.source(const_) { let assoc_item = ast::AssocItem::Const(source.value); - if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) { + if let Some(transformed_item) = + get_transformed_assoc_item(ctx, assoc_item, impl_def, source.file_id.macro_file()) + { let transformed_const = match transformed_item { ast::AssocItem::Const(const_) => const_, _ => unreachable!(), }; - let label = - make_const_compl_syntax(ctx, &transformed_const, source.file_id.macro_file()); + let label = make_const_compl_syntax(&transformed_const); let replacement = format!("{label} "); let mut item = @@ -488,17 +501,8 @@ fn add_const_impl( } } -fn make_const_compl_syntax( - ctx: &CompletionContext<'_, '_>, - const_: &ast::Const, - macro_file: Option, -) -> SmolStr { - let const_ = if let Some(macro_file) = macro_file { - let span_map = ctx.db.expansion_span_map(macro_file); - prettify_macro_expansion(ctx.db, const_.syntax().clone(), span_map, ctx.krate.into()) - } else { - const_.syntax().clone() - }; +fn make_const_compl_syntax(const_: &ast::Const) -> SmolStr { + let const_ = const_.syntax(); let start = const_.text_range().start(); let const_end = const_.text_range().end(); @@ -511,7 +515,7 @@ fn make_const_compl_syntax( let len = end - start; let range = TextRange::new(0.into(), len); - let syntax = const_.text().slice(range).to_string(); + let syntax = const_.text().slice(range).to_smolstr(); format_smolstr!("{} =", syntax.trim_end()) } @@ -522,7 +526,7 @@ fn function_declaration( macro_file: Option, ) -> String { let node = if let Some(macro_file) = macro_file { - let span_map = ctx.db.expansion_span_map(macro_file); + let span_map = macro_file.expansion_span_map(ctx.db); prettify_macro_expansion(ctx.db, node.syntax().clone(), span_map, ctx.krate.into()) } else { node.syntax().clone() @@ -537,9 +541,10 @@ fn function_declaration( .map_or(end, |f| f.text_range().start()); let len = end - start; - let syntax = node.text().slice(..len).to_string(); + let mut syntax = node.text().slice(..len).to_string(); + syntax.truncate(syntax.trim_end().len()); - syntax.trim_end().to_owned() + syntax } #[cfg(test)] @@ -1364,6 +1369,44 @@ impl Foo for Test { $0 } } +"#, + ); + + check_edit( + "type T", + r#" +macro_rules! noop { + ($($item: item)*) => { + $($item)* + } +} + +noop! { + trait Foo { + type T where Self: Sized; + } +} + +impl Foo for () { + $0 +} +"#, + r#" +macro_rules! noop { + ($($item: item)*) => { + $($item)* + } +} + +noop! { + trait Foo { + type T where Self: Sized; + } +} + +impl Foo for () { + type T = $0 where Self: Sized; +} "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs index 540089cf91052..5a3a3ac39cb2f 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs @@ -8,6 +8,7 @@ use ide_db::{ RootDatabase, SnippetCap, documentation::{Documentation, HasDocs}, imports::insert_use::ImportScope, + source_change::SnippetEdit, syntax_helpers::suggest_name::NameGenerator, text_edit::TextEdit, ty_filter::TryEnum, @@ -401,7 +402,7 @@ fn get_receiver_text( // The receiver texts should be interpreted as-is, as they are expected to be // normal Rust expressions. - escape_snippet_bits(&mut text); + SnippetEdit::escape_snippet_bits(&mut text); return text; fn indent_of_tail_line(text: &str) -> usize { @@ -411,15 +412,6 @@ fn get_receiver_text( } } -/// Escapes `\` and `$` so that they don't get interpreted as snippet-specific constructs. -/// -/// Note that we don't need to escape the other characters that can be escaped, -/// because they wouldn't be treated as snippet-specific constructs without '$'. -fn escape_snippet_bits(text: &mut String) { - stdx::replace(text, '\\', "\\\\"); - stdx::replace(text, '$', "\\$"); -} - fn receiver_accessor(receiver: &ast::Expr) -> ast::Expr { receiver .syntax() diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs index 3b22e8a266e73..76eddc558bdb5 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs @@ -18,14 +18,13 @@ use ide_db::{ SnippetCap, + source_change::SnippetEdit, syntax_helpers::format_string_exprs::{Arg, parse_format_exprs, with_placeholders}, }; use syntax::{AstToken, ast}; use crate::{ - Completions, - completions::postfix::{build_postfix_snippet_builder, escape_snippet_bits}, - context::CompletionContext, + Completions, completions::postfix::build_postfix_snippet_builder, context::CompletionContext, }; /// Mapping ("postfix completion item" => "macro to use") @@ -57,10 +56,10 @@ pub(crate) fn add_format_like_completions( if let Ok((mut out, mut exprs)) = parse_format_exprs(receiver_text.text()) { // Escape any snippet bits in the out text and any of the exprs. - escape_snippet_bits(&mut out); + SnippetEdit::escape_snippet_bits(&mut out); for arg in &mut exprs { if let Arg::Ident(text) | Arg::Expr(text) = arg { - escape_snippet_bits(text) + SnippetEdit::escape_snippet_bits(text) } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs index 16e89bd0de5a7..598e6763c7ee0 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs @@ -1,4 +1,5 @@ //! Complete fields in record literals and patterns. +use hir::{HasContainer, ItemContainer}; use ide_db::SymbolKind; use syntax::{ SmolStr, T, @@ -98,9 +99,13 @@ pub(crate) fn add_default_update( let impls_default_trait = default_trait .zip(ty) .is_some_and(|(default_trait, ty)| ty.original.impls_trait(ctx.db, default_trait, &[])); + let in_own_default_impl = + ty.zip(ctx.containing_function).is_some_and(|(ty, f)| ty.original == f.ret_type(ctx.db) + && matches!(f.container(ctx.db), ItemContainer::Impl(impl_) if impl_.trait_(ctx.db) == default_trait)); let ends_of_record_list = next_non_trivia_token(ctx.token.clone()).is_none_or(|it| it.kind() == T!['}']); - if impls_default_trait && ends_of_record_list { + + if impls_default_trait && !in_own_default_impl && ends_of_record_list { // FIXME: This should make use of scope_def like completions so we get all the other goodies // that is we should handle this like actually completing the default function let completion_text = "..Default::default()"; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs b/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs index 67ca9db2304fb..ee47c84708b46 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs @@ -181,10 +181,7 @@ fn import_edits( }; let mut res = Vec::with_capacity(requires.len()); for import in requires { - match resolve(import) { - Some(first) => res.extend(first), - None => return None, - } + res.extend(resolve(import)?) } Some(res) } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs index 45db8ecfc6a5f..dc162774a0a64 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs @@ -1280,10 +1280,10 @@ fn no_inherent_candidates_proposed() { check( r#" mod baz { - pub trait DefDatabase { + pub trait SourceDatabase { fn method1(&self); } - pub trait HirDatabase: DefDatabase { + pub trait HirDatabase: SourceDatabase { fn method2(&self); } } @@ -1299,10 +1299,10 @@ mod bar { check( r#" mod baz { - pub trait DefDatabase { + pub trait SourceDatabase { fn method1(&self); } - pub trait HirDatabase: DefDatabase { + pub trait HirDatabase: SourceDatabase { fn method2(&self); } } @@ -1318,10 +1318,10 @@ mod bar { check( r#" mod baz { - pub trait DefDatabase { + pub trait SourceDatabase { fn method1(&self); } - pub trait HirDatabase: DefDatabase { + pub trait HirDatabase: SourceDatabase { fn method2(&self); } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs index aecf8eb651e1a..99de630489474 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs @@ -234,6 +234,23 @@ fn main() { ); } +#[test] +fn in_own_default_impl() { + cov_mark::check!(functional_update_field); + check( + r#" + //- minicore:default + struct Foo { foo1: u32, foo2: u32 } + impl Default for Foo { + fn default() -> Self { Self { foo1: 0, $0 } + } + "#, + expect![[r#" + fd foo2 u32 + "#]], + ); +} + #[test] fn functional_update_one_dot() { cov_mark::check!(functional_update_one_dot); diff --git a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs index 7a3c466daa50c..713de3262bd0b 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs @@ -118,66 +118,6 @@ impl RootDatabase { // hir::db::TypeAliasImplTraitsQuery // hir::db::ValueTyQuery - // // DefDatabase - // hir::db::AttrsQuery - // hir::db::BlockDefMapQuery - // hir::db::BlockItemTreeQuery - // hir::db::BlockItemTreeWithSourceMapQuery - // hir::db::BodyQuery - // hir::db::BodyWithSourceMapQuery - // hir::db::ConstDataQuery - // hir::db::ConstVisibilityQuery - // hir::db::CrateDefMapQuery - // hir::db::CrateLangItemsQuery - // hir::db::CrateNotableTraitsQuery - // hir::db::CrateSupportsNoStdQuery - // hir::db::EnumDataQuery - // hir::db::ExpandProcAttrMacrosQuery - // hir::db::ExprScopesQuery - // hir::db::ExternCrateDeclDataQuery - // hir::db::FieldVisibilitiesQuery - // hir::db::FieldsAttrsQuery - // hir::db::FieldsAttrsSourceMapQuery - // hir::db::FileItemTreeQuery - // hir::db::FileItemTreeWithSourceMapQuery - // hir::db::FunctionDataQuery - // hir::db::FunctionVisibilityQuery - // hir::db::GenericParamsQuery - // hir::db::GenericParamsWithSourceMapQuery - // hir::db::ImplItemsWithDiagnosticsQuery - // hir::db::ImportMapQuery - // hir::db::IncludeMacroInvocQuery - // hir::db::InternAnonymousConstQuery - // hir::db::InternBlockQuery - // hir::db::InternConstQuery - // hir::db::InternEnumQuery - // hir::db::InternExternBlockQuery - // hir::db::InternExternCrateQuery - // hir::db::InternFunctionQuery - // hir::db::InternImplQuery - // hir::db::InternInTypeConstQuery - // hir::db::InternMacro2Query - // hir::db::InternMacroRulesQuery - // hir::db::InternProcMacroQuery - // hir::db::InternStaticQuery - // hir::db::InternStructQuery - // hir::db::InternTraitAliasQuery - // hir::db::InternTraitQuery - // hir::db::InternTypeAliasQuery - // hir::db::InternUnionQuery - // hir::db::InternUseQuery - // hir::db::LangItemQuery - // hir::db::Macro2DataQuery - // hir::db::MacroDefQuery - // hir::db::MacroRulesDataQuery - // hir::db::NotableTraitsInDepsQuery - // hir::db::ProcMacroDataQuery - // hir::db::StaticDataQuery - // hir::db::TraitAliasDataQuery - // hir::db::TraitItemsWithDiagnosticsQuery - // hir::db::TypeAliasDataQuery - // hir::db::VariantDataWithDiagnosticsQuery - // // InternDatabase // hir::db::InternFunctionQuery // hir::db::InternStructQuery @@ -195,19 +135,6 @@ impl RootDatabase { // hir::db::InternProcMacroQuery // hir::db::InternMacroRulesQuery - // // ExpandDatabase - // hir::db::AstIdMapQuery - // hir::db::DeclMacroExpanderQuery - // hir::db::ExpandProcMacroQuery - // hir::db::InternMacroCallQuery - // hir::db::InternSyntaxContextQuery - // hir::db::MacroArgQuery - // hir::db::ParseMacroExpansionErrorQuery - // hir::db::ParseMacroExpansionQuery - // hir::db::ProcMacroSpanQuery - // hir::db::ProcMacrosQuery - // hir::db::RealSpanMapQuery - // // LineIndexDatabase // crate::LineIndexQuery diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs index 9b68c27ae3443..17fae61da6131 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs @@ -827,7 +827,10 @@ fn split_prefix( make.use_tree(self_path, None, use_tree.rename(), false) } } else { - let suffix_segments = path.segments().skip(prefix.segments().count()); + let suffix_segments: Vec<_> = path.segments().skip(prefix.segments().count()).collect(); + if suffix_segments.is_empty() { + return None; + } let suffix_path = make.path_from_segments(suffix_segments, false); make.use_tree( suffix_path, diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs index 661f0cff8e135..101046cf54436 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs @@ -151,7 +151,7 @@ impl<'a> PathTransform<'a> { prettify_macro_expansion( db, node, - db.expansion_span_map(file_id), + file_id.expansion_span_map(db), self.target_scope.module().krate(db).into(), ) } @@ -415,16 +415,18 @@ impl Ctx<'_> { editor.replace(path.syntax(), qualified.clone().syntax()); } else if let Some(path_ty) = ast::PathType::cast(parent) { let old = path_ty.syntax(); + let needs_paren = old.parent().is_some_and(|it| subst.needs_parens_in(&it)); + let subst = + if needs_paren { make.ty_paren(subst.clone()) } else { subst.clone() }; if old.parent().is_some() { - editor.replace(old, subst.clone().syntax()); + editor.replace(old, subst.syntax()); } else { let start = path_ty.syntax().first_child().map(NodeOrToken::Node)?; let end = path_ty.syntax().last_child().map(NodeOrToken::Node)?; editor.replace_all( start..=end, subst - .clone() .syntax() .children() .map(NodeOrToken::Node) diff --git a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs index 07bf294405394..1a3fc0f358c1a 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs @@ -210,6 +210,15 @@ impl SnippetEdit { pub fn into_edit_ranges(self) -> Vec<(u32, TextRange)> { self.0 } + + /// Escapes `\` and `$` so that they don't get interpreted as snippet-specific constructs. + /// + /// Note that we don't need to escape the other characters that can be escaped, + /// because they wouldn't be treated as snippet-specific constructs without '$'. + pub fn escape_snippet_bits(text: &mut String) { + stdx::replace(text, '\\', "\\\\"); + stdx::replace(text, '$', "\\$"); + } } pub struct SourceChangeBuilder { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs index 15920595a8271..42bfc7fe4b21a 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs @@ -447,10 +447,9 @@ fn name_of_type<'db>( name } else if let Some((inner_ty, _)) = ty.as_reference() { return name_of_type(&inner_ty, db, edition); - } else if let Some(inner_ty) = ty.as_slice() { - return Some(sequence_name(Some(&inner_ty), db, edition)); } else { - return None; + let inner_ty = ty.as_slice()?; + return Some(sequence_name(Some(&inner_ty), db, edition)); }; normalize(&name, edition) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs index bda3f9bf0ad04..888f55cea777e 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs @@ -1,4 +1,4 @@ -use hir::{CaseType, InFile, db::ExpandDatabase}; +use hir::{CaseType, InFile}; use ide_db::{assists::Assist, defs::NameClass, rename::RenameDefinition}; use syntax::AstNode; @@ -37,7 +37,7 @@ pub(crate) fn incorrect_case( } fn fixes(ctx: &DiagnosticsContext<'_, '_>, d: &hir::IncorrectCase) -> Option> { - let root = ctx.sema.db.parse_or_expand(d.file); + let root = d.file.parse_or_expand(ctx.sema.db); let name_node = d.ident.to_node(&root); let def = NameClass::classify(&ctx.sema, &name_node)?.defined()?; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs index fe71707f078e7..2030be436887a 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -1,8 +1,6 @@ use either::Either; use hir::{ - AssocItem, FindPathConfig, HasVisibility, HirDisplay, InFile, Type, - db::{ExpandDatabase, HirDatabase}, - sym, + AssocItem, FindPathConfig, HasVisibility, HirDisplay, InFile, Type, db::HirDatabase, sym, }; use ide_db::{ FxHashMap, @@ -65,7 +63,7 @@ fn fixes(ctx: &DiagnosticsContext<'_, '_>, d: &hir::MissingFields) -> Option, d: &hir::MissingUnsafe) -> Option, d: &hir::NeedMut) -> Option { - let root = ctx.sema.db.parse_or_expand(d.span.file_id); + let root = d.span.file_id.parse_or_expand(ctx.sema.db); let node = d.span.value.to_node(&root); let mut span = d.span; if let Some(parent) = node.parent() diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs index 3dd6744b05bdb..f6fe83177fba9 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs @@ -1,5 +1,5 @@ use either::Either; -use hir::{HasSource, HirDisplay, Semantics, VariantId, db::ExpandDatabase}; +use hir::{HasSource, HirDisplay, Semantics, VariantId}; use ide_db::text_edit::TextEdit; use ide_db::{EditionedFileId, RootDatabase, source_change::SourceChange}; use syntax::{ @@ -32,7 +32,7 @@ pub(crate) fn no_such_field(ctx: &DiagnosticsContext<'_, '_>, d: &hir::NoSuchFie fn fixes(ctx: &DiagnosticsContext<'_, '_>, d: &hir::NoSuchField) -> Option> { // FIXME: quickfix for pattern - let root = ctx.sema.db.parse_or_expand(d.field.file_id); + let root = d.field.file_id.parse_or_expand(ctx.sema.db); match &d.field.value.to_node(&root) { Either::Left(node) => { if let Some(private_field) = d.private { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs index b5a47e508e14d..7e431f3ff4a86 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs @@ -1,4 +1,4 @@ -use hir::{FileRange, db::ExpandDatabase, diagnostics::RemoveTrailingReturn}; +use hir::{FileRange, diagnostics::RemoveTrailingReturn}; use ide_db::text_edit::TextEdit; use ide_db::{assists::Assist, source_change::SourceChange}; use syntax::{AstNode, ast}; @@ -37,7 +37,7 @@ pub(crate) fn remove_trailing_return( } fn fixes(ctx: &DiagnosticsContext<'_, '_>, d: &RemoveTrailingReturn) -> Option> { - let root = ctx.sema.db.parse_or_expand(d.return_expr.file_id); + let root = d.return_expr.file_id.parse_or_expand(ctx.sema.db); let return_expr = d.return_expr.value.to_node(&root); let stmt = return_expr.syntax().parent().and_then(ast::ExprStmt::cast); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs index aa7b57e2928f8..337b05e21f71a 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs @@ -1,4 +1,4 @@ -use hir::{db::ExpandDatabase, diagnostics::RemoveUnnecessaryElse}; +use hir::diagnostics::RemoveUnnecessaryElse; use ide_db::text_edit::TextEdit; use ide_db::{assists::Assist, source_change::SourceChange}; use itertools::Itertools; @@ -41,7 +41,7 @@ pub(crate) fn remove_unnecessary_else( } fn fixes(ctx: &DiagnosticsContext<'_, '_>, d: &RemoveUnnecessaryElse) -> Option> { - let root = ctx.sema.db.parse_or_expand(d.if_expr.file_id); + let root = d.if_expr.file_id.parse_or_expand(ctx.sema.db); let if_expr = d.if_expr.value.to_node(&root); let if_expr = ctx.sema.original_ast_node(if_expr)?; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs index f974c55023135..e67d86b8a212a 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs @@ -1,4 +1,4 @@ -use hir::{InFile, db::ExpandDatabase}; +use hir::InFile; use ide_db::source_change::SourceChange; use ide_db::text_edit::TextEdit; use syntax::{ @@ -29,7 +29,7 @@ fn fixes( ctx: &DiagnosticsContext<'_, '_>, d: &hir::ReplaceFilterMapNextWithFindMap, ) -> Option> { - let root = ctx.sema.db.parse_or_expand(d.file); + let root = d.file.parse_or_expand(ctx.sema.db); let next_expr = d.next_expr.to_node(&root); let next_call = ast::MethodCallExpr::cast(next_expr.syntax().clone())?; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs index ee972f2d1dc69..9374688d0ec6f 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs @@ -1,4 +1,4 @@ -use hir::{HasSource, HirDisplay, db::ExpandDatabase}; +use hir::{HasSource, HirDisplay}; use ide_db::text_edit::TextRange; use ide_db::{ assists::{Assist, AssistId}, @@ -82,7 +82,7 @@ fn quickfix_for_redundant_assoc_item( let file_id = d.file_id.file_id()?; let add_assoc_item_def = |builder: &mut SourceChangeBuilder| -> Option<()> { let db = ctx.sema.db; - let root = db.parse_or_expand(d.file_id); + let root = d.file_id.parse_or_expand(db); // don't modify trait def in outer crate let impl_def = d.impl_.to_node(&root); let current_crate = ctx.sema.scope(impl_def.syntax())?.krate(); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs index da6fc20c3e65f..295f37ab1d6b3 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs @@ -1,5 +1,5 @@ use either::Either; -use hir::{CallableKind, ClosureStyle, HirDisplay, InFile, db::ExpandDatabase}; +use hir::{CallableKind, ClosureStyle, HirDisplay, InFile}; use ide_db::{ famous_defs::FamousDefs, source_change::{SourceChange, SourceChangeBuilder}, @@ -75,6 +75,7 @@ fn fixes(ctx: &DiagnosticsContext<'_, '_>, d: &hir::TypeMismatch<'_>) -> Option< remove_semicolon(ctx, d, expr_ptr, &mut fixes); str_ref_to_owned(ctx, d, expr_ptr, &mut fixes); add_await(ctx, d, expr_ptr, &mut fixes); + array_length(ctx, d, expr_ptr, &mut fixes); } if fixes.is_empty() { None } else { Some(fixes) } @@ -151,7 +152,7 @@ fn add_missing_ok_or_some( expr_ptr: &InFile>, acc: &mut Vec, ) -> Option<()> { - let root = ctx.db().parse_or_expand(expr_ptr.file_id); + let root = expr_ptr.file_id.parse_or_expand(ctx.db()); let expr = expr_ptr.value.to_node(&root); let hir::FileRange { file_id, range: expr_range } = ctx.sema.original_range_opt(expr.syntax())?; @@ -246,7 +247,7 @@ fn remove_unnecessary_wrapper( acc: &mut Vec, ) -> Option<()> { let db = ctx.db(); - let root = db.parse_or_expand(expr_ptr.file_id); + let root = expr_ptr.file_id.parse_or_expand(db); let expr = expr_ptr.value.to_node(&root); // FIXME: support inside MacroCall? let expr = ctx.sema.original_ast_node(expr)?; @@ -327,7 +328,7 @@ fn remove_semicolon( expr_ptr: &InFile>, acc: &mut Vec, ) -> Option<()> { - let root = ctx.db().parse_or_expand(expr_ptr.file_id); + let root = expr_ptr.file_id.parse_or_expand(ctx.db()); let expr = expr_ptr.value.to_node(&root); if !d.actual.is_unit() { return None; @@ -365,7 +366,7 @@ fn str_ref_to_owned( return None; } - let root = ctx.db().parse_or_expand(expr_ptr.file_id); + let root = expr_ptr.file_id.parse_or_expand(ctx.db()); let expr = expr_ptr.value.to_node(&root); let hir::FileRange { file_id, range } = ctx.sema.original_range_opt(expr.syntax())?; @@ -391,7 +392,7 @@ fn add_await( return None; } - let root = ctx.db().parse_or_expand(expr_ptr.file_id); + let root = expr_ptr.file_id.parse_or_expand(ctx.db()); let expr = expr_ptr.value.to_node(&root); let hir::FileRange { file_id, range } = ctx.sema.original_range_opt(expr.syntax())?; @@ -402,6 +403,59 @@ fn add_await( Some(()) } +fn array_length( + ctx: &DiagnosticsContext<'_, '_>, + d: &hir::TypeMismatch<'_>, + expr_ptr: &InFile>, + acc: &mut Vec, +) -> Option<()> { + let (ty1, expected) = d.expected.as_array(ctx.db())?; + let (ty2, actual) = d.actual.as_array(ctx.db())?; + + if !ty1.could_unify_with(ctx.db(), &ty2) || expected == actual { + return None; + } + + let root = expr_ptr.file_id.parse_or_expand(ctx.db()); + let expr = expr_ptr.value.to_node(&root); + let container = skip_transparent(expr).syntax().parent()?; + let ty = syntax::match_ast! { + match container { + ast::LetStmt(it) => it.ty()?, + ast::Static(it) => it.ty()?, + ast::Const(it) => it.ty()?, + _ => return None, + } + }; + let ast::Type::ArrayType(ty) = ty else { return None }; + let len = ty.const_arg()?.expr()?; + let hir::FileRange { range: len_range, .. } = ctx.sema.original_range_opt(len.syntax())?; + let hir::FileRange { range, file_id } = ctx.sema.original_range_opt(&container)?; + + let edit = TextEdit::replace(len_range, actual.to_string()); + let source_change = SourceChange::from_text_edit(file_id.file_id(ctx.db()), edit); + let label = &format!("Change array length to {actual}"); + acc.push(fix("array_length", label, source_change, range)); + + fn skip_transparent(mut expr: Expr) -> Expr { + while let Some(parent) = expr.syntax().parent() { + if let Some(it) = ast::StmtList::cast(parent.clone()) + && it.statements().next().is_none() + && let Some(parent) = it.syntax().parent().and_then(Expr::cast) + { + expr = parent; + } else if let Some(parent) = ast::ParenExpr::cast(parent) { + expr = parent.into(); + } else { + break; + } + } + expr + } + + Some(()) +} + #[cfg(test)] mod tests { use crate::tests::{ @@ -1460,6 +1514,61 @@ identity! { ); } + #[test] + fn array_length() { + check_fix( + r#" +const VALS: [i32; 2$0] = [1, 2, 3]; + "#, + r#" +const VALS: [i32; 3] = [1, 2, 3]; + "#, + ); + + check_fix( + r#" +static VALS: [i32; 2$0] = [1, 2, 3]; + "#, + r#" +static VALS: [i32; 3] = [1, 2, 3]; + "#, + ); + + check_fix( + r#" +static VALS: [i32; 2$0] = {[1, 2, 3]}; + "#, + r#" +static VALS: [i32; 3] = {[1, 2, 3]}; + "#, + ); + + // Convenient trigger range + check_fix( + r#" +static VALS: [i32; 2] = [$01, 2, 3]; + "#, + r#" +static VALS: [i32; 3] = [1, 2, 3]; + "#, + ); + + check_fix( + r#" +macro_rules! identity { ($($t:tt)*) => ($($t)*) } +identity! { + const VALS: [i32; 2$0] = [1, 2, 3]; +} + "#, + r#" +macro_rules! identity { ($($t:tt)*) => ($($t)*) } +identity! { + const VALS: [i32; 3] = [1, 2, 3]; +} + "#, + ); + } + #[test] fn type_mismatch_range_adjustment() { cov_mark::check!(type_mismatch_range_adjustment); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs index e000d6388ae69..4c59482961a0b 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs @@ -2,7 +2,6 @@ use std::ops::Not; use hir::{ ClosureStyle, FindPathConfig, HirDisplay, - db::ExpandDatabase, term_search::{TermSearchConfig, TermSearchCtx, term_search}, }; use ide_db::text_edit::TextEdit; @@ -46,7 +45,7 @@ pub(crate) fn typed_hole<'db>( fn fixes<'db>(ctx: &DiagnosticsContext<'_, 'db>, d: &hir::TypedHole<'db>) -> Option> { let db = ctx.sema.db; - let root = db.parse_or_expand(d.expr.file_id); + let root = d.expr.file_id.parse_or_expand(db); let (original_range, _) = d.expr.as_ref().map(|it| it.to_node(&root)).syntax().original_file_range_opt(db)?; let scope = ctx.sema.scope(d.expr.value.to_node(&root).syntax())?; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs index 78e13677cfb1d..682a8130a8822 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs @@ -1,5 +1,5 @@ use either::Either; -use hir::{Adt, FileRange, HasSource, HirDisplay, InFile, Struct, Union, db::ExpandDatabase}; +use hir::{Adt, FileRange, HasSource, HirDisplay, InFile, Struct, Union}; use ide_db::text_edit::TextEdit; use ide_db::{ assists::{Assist, AssistId}, @@ -64,7 +64,7 @@ fn fixes(ctx: &DiagnosticsContext<'_, '_>, d: &hir::UnresolvedField<'_>) -> Opti // FIXME: Add Snippet Support fn field_fix(ctx: &DiagnosticsContext<'_, '_>, d: &hir::UnresolvedField<'_>) -> Option { // Get the FileRange of the invalid field access - let root = ctx.sema.db.parse_or_expand(d.expr.file_id); + let root = d.expr.file_id.parse_or_expand(ctx.sema.db); let expr = d.expr.value.to_node(&root).left()?; let error_range = ctx.sema.original_range_opt(expr.syntax())?; @@ -266,7 +266,7 @@ fn method_fix( ctx: &DiagnosticsContext<'_, '_>, expr_ptr: &InFile>>, ) -> Option { - let root = ctx.sema.db.parse_or_expand(expr_ptr.file_id); + let root = expr_ptr.file_id.parse_or_expand(ctx.sema.db); let expr = expr_ptr.value.to_node(&root); let FileRange { range, file_id } = ctx.sema.original_range_opt(expr.syntax())?; Some(Assist { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs index 01929a5144719..853e9d9f5692d 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs @@ -1,4 +1,4 @@ -use hir::{FileRange, HirDisplay, InFile, db::ExpandDatabase}; +use hir::{FileRange, HirDisplay, InFile}; use ide_db::text_edit::TextEdit; use ide_db::{ assists::{Assist, AssistId}, @@ -82,7 +82,7 @@ fn field_fix( return None; } let expr_ptr = &d.expr; - let root = ctx.sema.db.parse_or_expand(expr_ptr.file_id); + let root = expr_ptr.file_id.parse_or_expand(ctx.sema.db); let expr = expr_ptr.value.to_node(&root); let (file_id, range) = match expr.left()? { ast::Expr::MethodCallExpr(mcall) => { @@ -118,7 +118,7 @@ fn assoc_func_fix( let db = ctx.sema.db; let expr_ptr = &d.expr; - let root = db.parse_or_expand(expr_ptr.file_id); + let root = expr_ptr.file_id.parse_or_expand(db); let expr: ast::Expr = expr_ptr.value.to_node(&root).left()?; let call = ast::MethodCallExpr::cast(expr.syntax().clone())?; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs index 1e0e9105d88b5..d5f2697bd2188 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs @@ -1,4 +1,3 @@ -use hir::db::ExpandDatabase; use ide_db::{assists::Assist, base_db::AnchoredPathBuf, source_change::FileSystemEdit}; use itertools::Itertools; use syntax::AstNode; @@ -33,7 +32,7 @@ pub(crate) fn unresolved_module( } fn fixes(ctx: &DiagnosticsContext<'_, '_>, d: &hir::UnresolvedModule) -> Option> { - let root = ctx.sema.db.parse_or_expand(d.decl.file_id); + let root = d.decl.file_id.parse_or_expand(ctx.sema.db); let unresolved_module = d.decl.value.to_node(&root); Some( d.candidates diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_must_use.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_must_use.rs index e8d0717c91c2f..2173dc9c0addb 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_must_use.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_must_use.rs @@ -126,6 +126,141 @@ fn main() { x = produces(); let _ = x; } +"#, + ); + } + + #[test] + fn block_tail_expression_in_stmt_position() { + check_diagnostics( + r#" +#[must_use] +fn produces() -> i32 { 0 } +fn main() { + { + produces() + //^^^^^^^^^^ warn: unused return value that must be used + }; +} +"#, + ); + } + + #[test] + fn unsafe_block_tail_expression_in_stmt_position() { + check_diagnostics( + r#" +#[must_use] +unsafe fn produces() -> i32 { 0 } +fn main() { + unsafe { + produces() + //^^^^^^^^^^ warn: unused return value that must be used + }; +} +"#, + ); + } + + #[test] + fn nested_block_tail_expression() { + check_diagnostics( + r#" +#[must_use] +fn produces() -> i32 { 0 } +fn main() { + { + { + produces() + //^^^^^^^^^^ warn: unused return value that must be used + } + }; +} +"#, + ); + } + + #[test] + fn no_warning_when_block_tail_is_bound() { + check_diagnostics( + r#" +#[must_use] +fn produces() -> i32 { 0 } +fn main() { + let _x = { + produces() + }; +} +"#, + ); + } + + #[test] + fn if_branches_in_stmt_position() { + check_diagnostics( + r#" +#[must_use] +fn produces() -> i32 { 0 } +fn main() { + if true { + produces() + //^^^^^^^^^^ warn: unused return value that must be used + } else { + produces() + //^^^^^^^^^^ warn: unused return value that must be used + }; +} +"#, + ); + } + + #[test] + fn match_arms_in_stmt_position() { + check_diagnostics( + r#" +#[must_use] +fn produces() -> i32 { 0 } +fn main() { + match 0 { + 0 => produces(), + //^^^^^^^^^^ warn: unused return value that must be used + _ => produces(), + //^^^^^^^^^^ warn: unused return value that must be used + }; +} +"#, + ); + } + + #[test] + fn const_block_in_stmt_position() { + check_diagnostics( + r#" +#[must_use] +const fn produces() -> i32 { 0 } +fn main() { + const { + produces() + //^^^^^^^^^^ warn: unused return value that must be used + }; +} +"#, + ); + } + + #[test] + fn must_use_type_through_block() { + check_diagnostics( + r#" +#[must_use] +struct Important; +fn produces() -> Important { Important } +fn main() { + { + produces() + //^^^^^^^^^^ warn: unused return value that must be used + }; +} "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs index e26e3dbc1d8ac..8d8ed9acaa0fc 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs @@ -117,10 +117,7 @@ mod tests; use std::sync::LazyLock; -use hir::{ - Crate, DisplayTarget, InFile, MacroCallIdExt, Semantics, db::ExpandDatabase, - diagnostics::AnyDiagnostic, -}; +use hir::{Crate, DisplayTarget, InFile, MacroCallIdExt, Semantics, diagnostics::AnyDiagnostic}; use ide_db::{ FileId, FileRange, FxHashMap, FxHashSet, RootDatabase, Severity, SnippetCap, assists::{Assist, AssistId, AssistResolveStrategy, ExprFillDefaultMode}, @@ -618,7 +615,7 @@ fn handle_diag_from_macros( node: &InFile, ) -> bool { let Some(macro_file) = node.file_id.macro_file() else { return true }; - let span_map = sema.db.expansion_span_map(macro_file); + let span_map = macro_file.expansion_span_map(sema.db); let mut spans = span_map.spans_for_range(node.text_range()); if spans.any(|span| { span.ctx.outer_expn(sema.db).is_some_and(|expansion| { diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs index 16287a439c358..6bf4e72f200b7 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs @@ -15,7 +15,7 @@ use crate::{Match, SsrMatches, fragments, resolving::ResolvedRule}; /// template. Placeholders in the template will have been substituted with whatever they matched to /// in the original code. pub(crate) fn matches_to_edit<'db>( - db: &'db dyn hir::db::ExpandDatabase, + db: &'db dyn ide_db::base_db::SourceDatabase, matches: &SsrMatches, file_src: &str, rules: &[ResolvedRule<'db>], @@ -24,7 +24,7 @@ pub(crate) fn matches_to_edit<'db>( } fn matches_to_edit_at_offset<'db>( - db: &'db dyn hir::db::ExpandDatabase, + db: &'db dyn ide_db::base_db::SourceDatabase, matches: &SsrMatches, file_src: &str, relative_start: TextSize, @@ -41,7 +41,7 @@ fn matches_to_edit_at_offset<'db>( } struct ReplacementRenderer<'a, 'db> { - db: &'db dyn hir::db::ExpandDatabase, + db: &'db dyn ide_db::base_db::SourceDatabase, match_info: &'a Match, file_src: &'a str, rules: &'a [ResolvedRule<'db>], @@ -59,7 +59,7 @@ struct ReplacementRenderer<'a, 'db> { } fn render_replace<'db>( - db: &'db dyn hir::db::ExpandDatabase, + db: &'db dyn ide_db::base_db::SourceDatabase, match_info: &Match, file_src: &str, rules: &[ResolvedRule<'db>], diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs index c2b3a3d8d6893..6c34b97a39a37 100644 --- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs +++ b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs @@ -1,4 +1,3 @@ -use hir::db::ExpandDatabase; use hir::{ExpandResult, InFile, Semantics}; use ide_db::{ FileId, RootDatabase, base_db::Crate, helpers::pick_best_token, @@ -67,7 +66,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option< .count(); let ExpandResult { err, value: expansion } = expansions.get(idx)?.clone()?; let expansion_file_id = sema.hir_file_for(&expansion).macro_file()?; - let expansion_span_map = db.expansion_span_map(expansion_file_id); + let expansion_span_map = expansion_file_id.expansion_span_map(db); let mut expansion = format( db, SyntaxKind::MACRO_ITEMS, @@ -159,7 +158,7 @@ fn expand_macro_recur( } let file_id = sema.hir_file_for(&expanded).macro_file().expect("expansion must produce a macro file"); - let expansion_span_map = sema.db.expansion_span_map(file_id); + let expansion_span_map = file_id.expansion_span_map(sema.db); result_span_map.merge( TextRange::at(offset_in_original_node, macro_call.syntax().text_range().len()), expanded.text_range().len(), diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index 032a431586a33..b6d1689437ff1 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -367,7 +367,6 @@ fn try_lookup_include_path( kind: None, container_name: None, description: None, - docs: None, }) } diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs index 9fc89e90f2aa3..db5464a1fe93a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs +++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs @@ -1,8 +1,9 @@ use std::iter; -use hir::{EditionedFileId, FilePosition, FileRange, HirFileId, InFile, Semantics, db}; +use hir::{EditionedFileId, FilePosition, FileRange, HirFileId, InFile, Semantics}; use ide_db::{ FxHashMap, FxHashSet, RootDatabase, + base_db::SourceDatabase, defs::{Definition, IdentClass}, helpers::pick_best_token, search::{FileReference, ReferenceCategory, SearchScope}, @@ -676,7 +677,7 @@ fn find_defs(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> FxHashSe } fn original_frange( - db: &dyn db::ExpandDatabase, + db: &dyn SourceDatabase, file_id: HirFileId, text_range: Option, ) -> Option { diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index da4f185d75641..fe94e169ed9a9 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -6,7 +6,6 @@ use hir::{ Adt, AsAssocItem, AsExternAssocItem, CaptureKind, DisplayTarget, DropGlue, DynCompatibilityViolation, HasCrate, HasSource, HirDisplay, Layout, LayoutError, MethodViolationCode, Name, Semantics, Symbol, Trait, Type, TypeInfo, Variant, - db::ExpandDatabase, }; use ide_db::{ RootDatabase, @@ -543,7 +542,7 @@ pub(super) fn definition( let source = it.source(db)?; let mut body = source.value.body()?.syntax().clone(); if let Some(macro_file) = source.file_id.macro_file() { - let span_map = db.expansion_span_map(macro_file); + let span_map = macro_file.expansion_span_map(db); body = prettify_macro_expansion(db, body, span_map, it.krate(db).into()); } if env::var_os("RA_DEV").is_some() { @@ -575,7 +574,7 @@ pub(super) fn definition( let source = it.source(db)?; let mut body = source.value.body()?.syntax().clone(); if let Some(macro_file) = source.file_id.macro_file() { - let span_map = db.expansion_span_map(macro_file); + let span_map = macro_file.expansion_span_map(db); body = prettify_macro_expansion(db, body, span_map, it.krate(db).into()); } if env::var_os("RA_DEV").is_some() { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs index 49d7d454dfe77..c6c8806ac9894 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs @@ -139,7 +139,8 @@ pub(super) fn hints( _ => return None, } } - } else if let Some(mac) = ast::MacroCall::cast(node.clone()) { + } else { + let mac = ast::MacroCall::cast(node.clone())?; let last_token = mac.syntax().last_token()?; if last_token.kind() != T![;] && last_token.kind() != SyntaxKind::R_CURLY { return None; @@ -150,8 +151,6 @@ pub(super) fn hints( format!("{}!", mac.path()?), mac.path().and_then(|it| it.segment()).map(|it| it.syntax().text_range()), ) - } else { - return None; }; if let Some(mut next) = closing_token.next_token() { diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs index 24031429db88f..fd6c8263f9d8c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs +++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs @@ -12,7 +12,7 @@ use ide_db::{ FileId, FileRange, RootDatabase, SymbolKind, base_db::{CrateOrigin, LangCrateOrigin, all_crates}, defs::{Definition, find_std_module}, - documentation::{Documentation, HasDocs}, + documentation::HasDocs, famous_defs::FamousDefs, ra_fixture::UpmapFromRaFixture, }; @@ -50,7 +50,6 @@ pub struct NavigationTarget { pub kind: Option, pub container_name: Option, pub description: Option, - pub docs: Option>, /// In addition to a `name` field, a `NavigationTarget` may also be aliased /// In such cases we want a `NavigationTarget` to be accessible by its alias pub alias: Option, @@ -69,7 +68,7 @@ impl fmt::Debug for NavigationTarget { f.field("file_id", &self.file_id).field("full_range", &self.full_range); opt!(focus_range); f.field("name", &self.name); - opt!(kind container_name description docs); + opt!(kind container_name description); f.finish() } } @@ -106,7 +105,6 @@ impl UpmapFromRaFixture for NavigationTarget { virtual_file_id, real_file_id, )?, - docs: self.docs.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?, alias: self.alias.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?, }) } @@ -156,7 +154,6 @@ impl NavigationTarget { full_range, SymbolKind::Module, ); - res.docs = module.docs(db).map(Documentation::into_owned); res.description = Some( module.display(db, module.krate(db).to_display_target(db)).to_string(), ); @@ -233,7 +230,6 @@ impl NavigationTarget { focus_range, container_name: None, description: None, - docs: None, alias: None, } } @@ -294,7 +290,6 @@ impl<'db> TryToNav for FileSymbol<'db> { } hir::ModuleDef::BuiltinType(_) => None, }, - docs: None, } }), ) @@ -458,7 +453,6 @@ where D::KIND, ) .map(|mut res| { - res.docs = self.docs(db).map(Documentation::into_owned); res.description = Some(self.display(db, self.krate(db).to_display_target(db)).to_string()); res.container_name = self.container_name(db); @@ -545,7 +539,6 @@ impl TryToNav for hir::ExternCrateDecl { SymbolKind::CrateRoot, ); - res.docs = self.docs(db).map(Documentation::into_owned); res.description = Some(self.display(db, krate.to_display_target(db)).to_string()); res.container_name = container_name(db, *self); res @@ -567,7 +560,6 @@ impl TryToNav for hir::Field { FieldSource::Named(it) => { NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field).map( |mut res| { - res.docs = self.docs(db).map(Documentation::into_owned); res.description = Some(self.display(db, krate.to_display_target(db)).to_string()); res @@ -601,17 +593,11 @@ impl TryToNav for hir::Macro { Either::Left(it) => it, Either::Right(it) => it, }; - Some( - NavigationTarget::from_named( - db, - src.as_ref().with_value(name_owner), - self.kind(db).into(), - ) - .map(|mut res| { - res.docs = self.docs(db).map(Documentation::into_owned); - res - }), - ) + Some(NavigationTarget::from_named( + db, + src.as_ref().with_value(name_owner), + self.kind(db).into(), + )) } } @@ -683,7 +669,6 @@ impl ToNav for LocalSource { focus_range, container_name: None, description: None, - docs: None, } }, ) @@ -715,7 +700,6 @@ impl TryToNav for hir::Label { focus_range, container_name: None, description: None, - docs: None, }, )) } @@ -755,7 +739,6 @@ impl TryToNav for hir::TypeParam { focus_range, container_name: None, description: None, - docs: None, }, )) } @@ -789,7 +772,6 @@ impl TryToNav for hir::LifetimeParam { focus_range, container_name: None, description: None, - docs: None, }, )) } @@ -822,7 +804,6 @@ impl TryToNav for hir::ConstParam { focus_range, container_name: None, description: None, - docs: None, }, )) } @@ -847,7 +828,6 @@ impl TryToNav for hir::InlineAsmOperand { focus_range, container_name: None, description: None, - docs: None, }, )) } diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs index 60750608a5b49..ce4e5cf97fb24 100644 --- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs +++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs @@ -545,7 +545,6 @@ fn module_def_doctest(sema: &Semantics<'_, RootDatabase>, def: Definition) -> Op .call_site(); nav.focus_range = None; nav.description = None; - nav.docs = None; nav.kind = None; let res = Runnable { use_name_in_title: false, diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs index a49a85fe7804a..b06079d8acd13 100644 --- a/src/tools/rust-analyzer/crates/ide/src/typing.rs +++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs @@ -326,10 +326,8 @@ fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option { // Make sure dot is a part of call chain let receiver = if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) { field_expr.expr()? - } else if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent.clone()) { - method_call_expr.receiver()? } else { - return None; + ast::MethodCallExpr::cast(parent.clone())?.receiver()? }; let receiver_is_multiline = receiver.syntax().text().find_char('\n').is_some(); diff --git a/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs b/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs index 7d04594a5bf8d..4e3c491418754 100644 --- a/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs +++ b/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs @@ -1,7 +1,7 @@ //! Handles the `Enter` key press, including comment continuation and //! indentation in brace-delimited constructs. -use ide_db::{FilePosition, RootDatabase}; +use ide_db::{FilePosition, RootDatabase, source_change::SnippetEdit}; use syntax::{ AstNode, SmolStr, SourceFile, SyntaxKind::*, @@ -113,7 +113,8 @@ fn on_enter_in_braces(l_curly: SyntaxToken, position: FilePosition) -> Option String { return String::new(); }; let file_id = sema.attach_first_edition(file_id); - db.file_item_tree(file_id.into(), krate.into()).pretty_print(db, file_id.edition(db)) + hir::db::file_item_tree(db, file_id.into(), krate.into()).pretty_print(db, file_id.edition(db)) } diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index 96c95ec277cc6..fb082d3209b1e 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -11,16 +11,15 @@ extern crate rustc_driver as _; use std::{any::Any, collections::hash_map::Entry, mem, path::Path, sync}; use crossbeam_channel::{Receiver, unbounded}; -use hir_expand::{ - db::ExpandDatabase, - proc_macro::{ - ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind, ProcMacroLoadResult, - ProcMacrosBuilder, - }, +use hir_expand::proc_macro::{ + ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind, ProcMacroLoadResult, + ProcMacrosBuilder, }; use ide_db::{ ChangeWithProcMacros, FxHashMap, RootDatabase, - base_db::{CrateGraphBuilder, Env, ProcMacroLoadingError, SourceRoot, SourceRootId}, + base_db::{ + CrateGraphBuilder, Env, ProcMacroLoadingError, SourceDatabase, SourceRoot, SourceRootId, + }, prime_caches, }; use itertools::Itertools; @@ -569,7 +568,7 @@ struct Expander(proc_macro_api::ProcMacro); impl ProcMacroExpander for Expander { fn expand( &self, - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, subtree: &tt::TopSubtree, attrs: Option<&tt::TopSubtree>, env: &Env, @@ -659,7 +658,7 @@ impl ProcMacroExpander for Expander { let call_site_file = macro_call_loc.kind.file_id(); - let resolved = db.resolve_span(current_span); + let resolved = hir_expand::resolve_span(db, current_span); current_ctx = macro_call_loc.ctxt; current_span = Span { @@ -676,7 +675,7 @@ impl ProcMacroExpander for Expander { } } - let resolved = db.resolve_span(current_span); + let resolved = hir_expand::resolve_span(db, current_span); Ok(SubResponse::SpanSourceResult { file_id: resolved.file_id.span_file_id(db).as_u32(), @@ -705,8 +704,8 @@ impl ProcMacroExpander for Expander { let call_site_ast_id = macro_call_loc.kind.erased_ast_id(); if let Some(editioned_file_id) = call_site_file.file_id() { - let range = db - .ast_id_map(editioned_file_id.into()) + let range = hir_expand::HirFileId::from(editioned_file_id) + .ast_id_map(db) .get_erased(call_site_ast_id) .text_range(); @@ -749,7 +748,7 @@ impl ProcMacroExpander for Expander { } fn resolve_sub_span( - db: &dyn ExpandDatabase, + db: &dyn SourceDatabase, file_id: u32, ast_id: u32, range: TextRange, @@ -761,7 +760,7 @@ fn resolve_sub_span( anchor: SpanAnchor { file_id: editioned_file_id, ast_id }, ctx: SyntaxContext::root(editioned_file_id.edition()), }; - db.resolve_span(span) + hir_expand::resolve_span(db, span) } #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol.rs index 75c3bf8d35bb3..f070b1c9a3342 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol.rs @@ -56,7 +56,7 @@ pub fn run_conversation( return Ok(BidirectionalMessage::Response(response)); } BidirectionalMessage::SubRequest(sr) => { - // TODO: Avoid `AssertUnwindSafe` by making the callback `UnwindSafe` once `ExpandDatabase` + // TODO: Avoid `AssertUnwindSafe` by making the callback `UnwindSafe` once `SourceDatabase` // becomes unwind-safe (currently blocked by `parking_lot::RwLock` in the VFS). let resp = match catch_unwind(AssertUnwindSafe(|| callback(sr))) { Ok(Ok(resp)) => BidirectionalMessage::SubResponse(resp), diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs index 149f6e44f9bea..7b2e209b8e038 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs @@ -78,9 +78,9 @@ pub enum ProcMacroKind { Bang, } -/// A handle to an external process which load dylibs with macros (.so or .dll) +/// A handle to proc-macro server process pool which load dylibs with macros (.so or .dll) /// and runs actual macro expansion functions. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ProcMacroClient { /// Currently, the proc macro process expands all procedural macros sequentially. /// diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs index a8ddb216f0e41..2cb6817fb9167 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs @@ -84,7 +84,7 @@ pub struct Foo { GROUP [] 1 1 1 IDENT 1 doc PUNCT 1 = [alone] - LITER 1 Str / The domain where this federated instance is running + LITER 1 Str The domain where this federated instance is running PUNCT 1 # [joint] GROUP [] 1 1 1 IDENT 1 helper @@ -120,7 +120,7 @@ pub struct Foo { GROUP [] 1 1 1 IDENT 1 doc PUNCT 1 = [alone] - LITER 1 Str / The domain where this federated instance is running + LITER 1 Str The domain where this federated instance is running PUNCT 1 # [joint] GROUP [] 1 1 1 IDENT 1 helper @@ -156,7 +156,7 @@ pub struct Foo { GROUP [] 42:Root[0000, 0]@0..0#0 42:Root[0000, 0]@0..0#0 42:Root[0000, 0]@0..0#0 IDENT 42:Root[0000, 0]@0..0#0 doc PUNCT 42:Root[0000, 0]@0..0#0 = [alone] - LITER 42:Root[0000, 0]@75..130#0 Str / The domain where this federated instance is running + LITER 42:Root[0000, 0]@75..130#0 Str The domain where this federated instance is running PUNCT 42:Root[0000, 0]@135..136#0 # [joint] GROUP [] 42:Root[0000, 0]@136..137#0 42:Root[0000, 0]@157..158#0 42:Root[0000, 0]@136..158#0 IDENT 42:Root[0000, 0]@137..143#0 helper @@ -192,7 +192,7 @@ pub struct Foo { GROUP [] 42:Root[0000, 0]@0..0#0 42:Root[0000, 0]@0..0#0 42:Root[0000, 0]@0..0#0 IDENT 42:Root[0000, 0]@0..0#0 doc PUNCT 42:Root[0000, 0]@0..0#0 = [alone] - LITER 42:Root[0000, 0]@75..130#0 Str / The domain where this federated instance is running + LITER 42:Root[0000, 0]@75..130#0 Str The domain where this federated instance is running PUNCT 42:Root[0000, 0]@135..136#0 # [joint] GROUP [] 42:Root[0000, 0]@136..137#0 42:Root[0000, 0]@157..158#0 42:Root[0000, 0]@136..158#0 IDENT 42:Root[0000, 0]@137..143#0 helper diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/token_stream.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/token_stream.rs index 2358f6963c79e..5201bb6aeb86b 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/token_stream.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/token_stream.rs @@ -1,761 +1,767 @@ -//! The proc-macro server token stream implementation. - -use core::fmt; -use std::{mem, sync::Arc}; - -use intern::Symbol; -use rustc_lexer::{DocStyle, LiteralKind}; -use rustc_proc_macro::Delimiter; - -use crate::bridge::{DelimSpan, Group, Ident, LitKind, Literal, Punct, TokenTree}; - -/// Trait for allowing tests to parse tokenstreams with dynamic span ranges -pub(crate) trait SpanLike { - fn derive_ranged(&self, range: std::ops::Range) -> Self; -} - -#[derive(Clone)] -pub struct TokenStream(pub(crate) Arc>>); - -impl Default for TokenStream { - fn default() -> Self { - Self(Default::default()) - } -} - -impl TokenStream { - pub fn new(tts: Vec>) -> TokenStream { - TokenStream(Arc::new(tts)) - } - - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - pub fn len(&self) -> usize { - self.0.len() - } - - pub fn iter(&self) -> TokenStreamIter<'_, S> { - TokenStreamIter::new(self) - } - - pub fn as_single_group(&self) -> Option<&Group> { - match &**self.0 { - [TokenTree::Group(group)] => Some(group), - _ => None, - } - } - - pub(crate) fn from_str(s: &str, span: S) -> Result - where - S: SpanLike + Copy, - { - let mut groups = Vec::new(); - groups.push((rustc_proc_macro::Delimiter::None, 0..0, vec![])); - let mut offset = 0; - let mut tokens = rustc_lexer::tokenize(s, rustc_lexer::FrontmatterAllowed::No).peekable(); - while let Some(token) = tokens.next() { - let range = offset..offset + token.len as usize; - offset += token.len as usize; - - let mut is_joint = || { - tokens.peek().is_some_and(|token| { - matches!( - token.kind, - rustc_lexer::TokenKind::RawLifetime - | rustc_lexer::TokenKind::GuardedStrPrefix - | rustc_lexer::TokenKind::Lifetime { .. } - | rustc_lexer::TokenKind::Semi - | rustc_lexer::TokenKind::Comma - | rustc_lexer::TokenKind::Dot - | rustc_lexer::TokenKind::OpenParen - | rustc_lexer::TokenKind::CloseParen - | rustc_lexer::TokenKind::OpenBrace - | rustc_lexer::TokenKind::CloseBrace - | rustc_lexer::TokenKind::OpenBracket - | rustc_lexer::TokenKind::CloseBracket - | rustc_lexer::TokenKind::At - | rustc_lexer::TokenKind::Pound - | rustc_lexer::TokenKind::Tilde - | rustc_lexer::TokenKind::Question - | rustc_lexer::TokenKind::Colon - | rustc_lexer::TokenKind::Dollar - | rustc_lexer::TokenKind::Eq - | rustc_lexer::TokenKind::Bang - | rustc_lexer::TokenKind::Lt - | rustc_lexer::TokenKind::Gt - | rustc_lexer::TokenKind::Minus - | rustc_lexer::TokenKind::And - | rustc_lexer::TokenKind::Or - | rustc_lexer::TokenKind::Plus - | rustc_lexer::TokenKind::Star - | rustc_lexer::TokenKind::Slash - | rustc_lexer::TokenKind::Percent - | rustc_lexer::TokenKind::Caret - ) - }) - }; - - let Some((open_delim, _, tokenstream)) = groups.last_mut() else { - return Err("Unbalanced delimiters".to_owned()); - }; - match token.kind { - rustc_lexer::TokenKind::OpenParen => { - groups.push((rustc_proc_macro::Delimiter::Parenthesis, range, vec![])) - } - rustc_lexer::TokenKind::CloseParen if *open_delim != Delimiter::Parenthesis => { - return if *open_delim == Delimiter::None { - Err("Unexpected ')'".to_owned()) - } else { - Err("Expected ')'".to_owned()) - }; - } - rustc_lexer::TokenKind::CloseParen => { - let (delimiter, open_range, stream) = groups.pop().unwrap(); - groups.last_mut().ok_or_else(|| "Unbalanced delimiters".to_owned())?.2.push( - TokenTree::Group(Group { - delimiter, - stream: if stream.is_empty() { - None - } else { - Some(TokenStream::new(stream)) - }, - span: DelimSpan { - entire: span.derive_ranged(open_range.start..range.end), - open: span.derive_ranged(open_range), - close: span.derive_ranged(range), - }, - }), - ); - } - rustc_lexer::TokenKind::OpenBrace => { - groups.push((rustc_proc_macro::Delimiter::Brace, range, vec![])) - } - rustc_lexer::TokenKind::CloseBrace if *open_delim != Delimiter::Brace => { - return if *open_delim == Delimiter::None { - Err("Unexpected '}'".to_owned()) - } else { - Err("Expected '}'".to_owned()) - }; - } - rustc_lexer::TokenKind::CloseBrace => { - let (delimiter, open_range, stream) = groups.pop().unwrap(); - groups.last_mut().ok_or_else(|| "Unbalanced delimiters".to_owned())?.2.push( - TokenTree::Group(Group { - delimiter, - stream: if stream.is_empty() { - None - } else { - Some(TokenStream::new(stream)) - }, - span: DelimSpan { - entire: span.derive_ranged(open_range.start..range.end), - open: span.derive_ranged(open_range), - close: span.derive_ranged(range), - }, - }), - ); - } - rustc_lexer::TokenKind::OpenBracket => { - groups.push((rustc_proc_macro::Delimiter::Bracket, range, vec![])) - } - rustc_lexer::TokenKind::CloseBracket if *open_delim != Delimiter::Bracket => { - return if *open_delim == Delimiter::None { - Err("Unexpected ']'".to_owned()) - } else { - Err("Expected ']'".to_owned()) - }; - } - rustc_lexer::TokenKind::CloseBracket => { - let (delimiter, open_range, stream) = groups.pop().unwrap(); - groups.last_mut().ok_or_else(|| "Unbalanced delimiters".to_owned())?.2.push( - TokenTree::Group(Group { - delimiter, - stream: if stream.is_empty() { - None - } else { - Some(TokenStream::new(stream)) - }, - span: DelimSpan { - entire: span.derive_ranged(open_range.start..range.end), - open: span.derive_ranged(open_range), - close: span.derive_ranged(range), - }, - }), - ); - } - rustc_lexer::TokenKind::LineComment { doc_style: None } - | rustc_lexer::TokenKind::BlockComment { doc_style: None, terminated: _ } => { - continue; - } - rustc_lexer::TokenKind::LineComment { doc_style: Some(doc_style) } => { - let text = &s[range.start + 2..range.end]; - tokenstream.push(TokenTree::Punct(Punct { ch: b'#', joint: false, span })); - if doc_style == DocStyle::Inner { - tokenstream.push(TokenTree::Punct(Punct { ch: b'!', joint: false, span })); - } - tokenstream.push(TokenTree::Group(Group { - delimiter: Delimiter::Bracket, - stream: Some(TokenStream::new(vec![ - TokenTree::Ident(Ident { - sym: Symbol::intern("doc"), - is_raw: false, - span, - }), - TokenTree::Punct(Punct { ch: b'=', joint: false, span }), - TokenTree::Literal(Literal { - kind: LitKind::Str, - symbol: Symbol::intern(&text.escape_debug().to_string()), - suffix: None, - span: span.derive_ranged(range), - }), - ])), - span: DelimSpan { open: span, close: span, entire: span }, - })); - } - rustc_lexer::TokenKind::BlockComment { doc_style: Some(doc_style), terminated } => { - let text = - &s[range.start + 2..if terminated { range.end - 2 } else { range.end }]; - tokenstream.push(TokenTree::Punct(Punct { ch: b'#', joint: false, span })); - if doc_style == DocStyle::Inner { - tokenstream.push(TokenTree::Punct(Punct { ch: b'!', joint: false, span })); - } - tokenstream.push(TokenTree::Group(Group { - delimiter: Delimiter::Bracket, - stream: Some(TokenStream::new(vec![ - TokenTree::Ident(Ident { - sym: Symbol::intern("doc"), - is_raw: false, - span, - }), - TokenTree::Punct(Punct { ch: b'=', joint: false, span }), - TokenTree::Literal(Literal { - kind: LitKind::Str, - symbol: Symbol::intern(&text.escape_debug().to_string()), - suffix: None, - span: span.derive_ranged(range), - }), - ])), - span: DelimSpan { open: span, close: span, entire: span }, - })); - } - rustc_lexer::TokenKind::Whitespace => continue, - rustc_lexer::TokenKind::Frontmatter { .. } => unreachable!(), - rustc_lexer::TokenKind::Unknown => { - return Err(format!("Unknown token: `{}`", &s[range])); - } - rustc_lexer::TokenKind::UnknownPrefix => { - return Err(format!("Unknown prefix: `{}`", &s[range])); - } - rustc_lexer::TokenKind::UnknownPrefixLifetime => { - return Err(format!("Unknown lifetime prefix: `{}`", &s[range])); - } - // FIXME: Error on edition >= 2024 ... I dont think the proc-macro server can fetch editions currently - // and whose edition is this? - rustc_lexer::TokenKind::GuardedStrPrefix => { - tokenstream.push(TokenTree::Punct(Punct { - ch: s.as_bytes()[range.start], - joint: true, - span: span.derive_ranged(range.start..range.start + 1), - })); - tokenstream.push(TokenTree::Punct(Punct { - ch: s.as_bytes()[range.start + 1], - joint: is_joint(), - span: span.derive_ranged(range.start + 1..range.end), - })) - } - rustc_lexer::TokenKind::Ident => tokenstream.push(TokenTree::Ident(Ident { - sym: Symbol::intern(&s[range.clone()]), - is_raw: false, - span: span.derive_ranged(range), - })), - rustc_lexer::TokenKind::InvalidIdent => { - return Err(format!("Invalid identifier: `{}`", &s[range])); - } - rustc_lexer::TokenKind::RawIdent => { - let range = range.start + 2..range.end; - tokenstream.push(TokenTree::Ident(Ident { - sym: Symbol::intern(&s[range.clone()]), - is_raw: true, - span: span.derive_ranged(range), - })) - } - rustc_lexer::TokenKind::Literal { kind, suffix_start } => { - tokenstream.push(TokenTree::Literal(literal_from_lexer( - &s[range.clone()], - span.derive_ranged(range), - kind, - suffix_start, - ))) - } - rustc_lexer::TokenKind::RawLifetime => { - let range = range.start + 1 + 2..range.end; - tokenstream.push(TokenTree::Punct(Punct { - ch: b'\'', - joint: true, - span: span.derive_ranged(range.start..range.start + 1), - })); - tokenstream.push(TokenTree::Ident(Ident { - sym: Symbol::intern(&s[range.clone()]), - is_raw: true, - span: span.derive_ranged(range), - })) - } - rustc_lexer::TokenKind::Lifetime { starts_with_number } => { - if starts_with_number { - return Err("Lifetime cannot start with a number".to_owned()); - } - let range = range.start + 1..range.end; - tokenstream.push(TokenTree::Punct(Punct { - ch: b'\'', - joint: true, - span: span.derive_ranged(range.start..range.start + 1), - })); - tokenstream.push(TokenTree::Ident(Ident { - sym: Symbol::intern(&s[range.clone()]), - is_raw: false, - span: span.derive_ranged(range), - })) - } - rustc_lexer::TokenKind::Semi => tokenstream.push(TokenTree::Punct(Punct { - ch: b';', - joint: is_joint(), - span: span.derive_ranged(range), - })), - rustc_lexer::TokenKind::Comma => tokenstream.push(TokenTree::Punct(Punct { - ch: b',', - joint: is_joint(), - span: span.derive_ranged(range), - })), - rustc_lexer::TokenKind::Dot => tokenstream.push(TokenTree::Punct(Punct { - ch: b'.', - joint: is_joint(), - span: span.derive_ranged(range), - })), - rustc_lexer::TokenKind::At => tokenstream.push(TokenTree::Punct(Punct { - ch: b'@', - joint: is_joint(), - span: span.derive_ranged(range), - })), - rustc_lexer::TokenKind::Pound => tokenstream.push(TokenTree::Punct(Punct { - ch: b'#', - joint: is_joint(), - span: span.derive_ranged(range), - })), - rustc_lexer::TokenKind::Tilde => tokenstream.push(TokenTree::Punct(Punct { - ch: b'~', - joint: is_joint(), - span: span.derive_ranged(range), - })), - rustc_lexer::TokenKind::Question => tokenstream.push(TokenTree::Punct(Punct { - ch: b'?', - joint: is_joint(), - span: span.derive_ranged(range), - })), - rustc_lexer::TokenKind::Colon => tokenstream.push(TokenTree::Punct(Punct { - ch: b':', - joint: is_joint(), - span: span.derive_ranged(range), - })), - rustc_lexer::TokenKind::Dollar => tokenstream.push(TokenTree::Punct(Punct { - ch: b'$', - joint: is_joint(), - span: span.derive_ranged(range), - })), - rustc_lexer::TokenKind::Eq => tokenstream.push(TokenTree::Punct(Punct { - ch: b'=', - joint: is_joint(), - span: span.derive_ranged(range), - })), - rustc_lexer::TokenKind::Bang => tokenstream.push(TokenTree::Punct(Punct { - ch: b'!', - joint: is_joint(), - span: span.derive_ranged(range), - })), - rustc_lexer::TokenKind::Lt => tokenstream.push(TokenTree::Punct(Punct { - ch: b'<', - joint: is_joint(), - span: span.derive_ranged(range), - })), - rustc_lexer::TokenKind::Gt => tokenstream.push(TokenTree::Punct(Punct { - ch: b'>', - joint: is_joint(), - span: span.derive_ranged(range), - })), - rustc_lexer::TokenKind::Minus => tokenstream.push(TokenTree::Punct(Punct { - ch: b'-', - joint: is_joint(), - span: span.derive_ranged(range), - })), - rustc_lexer::TokenKind::And => tokenstream.push(TokenTree::Punct(Punct { - ch: b'&', - joint: is_joint(), - span: span.derive_ranged(range), - })), - rustc_lexer::TokenKind::Or => tokenstream.push(TokenTree::Punct(Punct { - ch: b'|', - joint: is_joint(), - span: span.derive_ranged(range), - })), - rustc_lexer::TokenKind::Plus => tokenstream.push(TokenTree::Punct(Punct { - ch: b'+', - joint: is_joint(), - span: span.derive_ranged(range), - })), - rustc_lexer::TokenKind::Star => tokenstream.push(TokenTree::Punct(Punct { - ch: b'*', - joint: is_joint(), - span: span.derive_ranged(range), - })), - rustc_lexer::TokenKind::Slash => tokenstream.push(TokenTree::Punct(Punct { - ch: b'/', - joint: is_joint(), - span: span.derive_ranged(range), - })), - rustc_lexer::TokenKind::Caret => tokenstream.push(TokenTree::Punct(Punct { - ch: b'^', - joint: is_joint(), - span: span.derive_ranged(range), - })), - rustc_lexer::TokenKind::Percent => tokenstream.push(TokenTree::Punct(Punct { - ch: b'%', - joint: is_joint(), - span: span.derive_ranged(range), - })), - rustc_lexer::TokenKind::Eof => break, - } - } - if let Some((Delimiter::None, _, tokentrees)) = groups.pop() - && groups.is_empty() - { - Ok(TokenStream::new(tokentrees)) - } else { - Err("Mismatched token groups".to_owned()) - } - } -} - -impl fmt::Display for TokenStream { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let mut emit_whitespace = false; - for tt in self.0.iter() { - display_token_tree(tt, &mut emit_whitespace, f)?; - } - Ok(()) - } -} - -fn display_token_tree( - tt: &TokenTree, - emit_whitespace: &mut bool, - f: &mut std::fmt::Formatter<'_>, -) -> std::fmt::Result { - if mem::take(emit_whitespace) { - write!(f, " ")?; - } - match tt { - TokenTree::Group(Group { delimiter, stream, span: _ }) => { - write!( - f, - "{}", - match delimiter { - rustc_proc_macro::Delimiter::Parenthesis => "(", - rustc_proc_macro::Delimiter::Brace => "{", - rustc_proc_macro::Delimiter::Bracket => "[", - rustc_proc_macro::Delimiter::None => "", - } - )?; - if let Some(stream) = stream { - write!(f, "{stream}")?; - } - write!( - f, - "{}", - match delimiter { - rustc_proc_macro::Delimiter::Parenthesis => ")", - rustc_proc_macro::Delimiter::Brace => "}", - rustc_proc_macro::Delimiter::Bracket => "]", - rustc_proc_macro::Delimiter::None => "", - } - )?; - } - TokenTree::Punct(Punct { ch, joint, span: _ }) => { - *emit_whitespace = !*joint; - write!(f, "{}", *ch as char)?; - } - TokenTree::Ident(Ident { sym, is_raw, span: _ }) => { - if *is_raw { - write!(f, "r#")?; - } - write!(f, "{sym}")?; - *emit_whitespace = true; - } - TokenTree::Literal(lit) => { - display_fmt_literal(lit, f)?; - let joint = match lit.kind { - LitKind::Str - | LitKind::StrRaw(_) - | LitKind::ByteStr - | LitKind::ByteStrRaw(_) - | LitKind::CStr - | LitKind::CStrRaw(_) => true, - _ => false, - }; - *emit_whitespace = !joint; - } - } - Ok(()) -} - -pub fn literal_to_string(literal: &Literal) -> String { - let mut buf = String::new(); - display_fmt_literal(literal, &mut buf).unwrap(); - buf -} - -fn display_fmt_literal(literal: &Literal, f: &mut impl std::fmt::Write) -> fmt::Result { - match literal.kind { - LitKind::Byte => write!(f, "b'{}'", literal.symbol), - LitKind::Char => write!(f, "'{}'", literal.symbol), - LitKind::Integer | LitKind::Float | LitKind::ErrWithGuar => { - write!(f, "{}", literal.symbol) - } - LitKind::Str => write!(f, "\"{}\"", literal.symbol), - LitKind::ByteStr => write!(f, "b\"{}\"", literal.symbol), - LitKind::CStr => write!(f, "c\"{}\"", literal.symbol), - LitKind::StrRaw(num_of_hashes) => { - let num_of_hashes = num_of_hashes as usize; - write!( - f, - r#"r{0:# { - let num_of_hashes = num_of_hashes as usize; - write!( - f, - r#"br{0:# { - let num_of_hashes = num_of_hashes as usize; - write!( - f, - r#"cr{0:# fmt::Debug for TokenStream { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - debug_token_stream(self, 0, f) - } -} - -fn debug_token_stream( - ts: &TokenStream, - depth: usize, - f: &mut std::fmt::Formatter<'_>, -) -> std::fmt::Result { - for tt in ts.0.iter() { - debug_token_tree(tt, depth, f)?; - } - Ok(()) -} - -fn debug_token_tree( - tt: &TokenTree, - depth: usize, - f: &mut std::fmt::Formatter<'_>, -) -> std::fmt::Result { - write!(f, "{:indent$}", "", indent = depth * 2)?; - match tt { - TokenTree::Group(Group { delimiter, stream, span }) => { - writeln!( - f, - "GROUP {}{} {:#?} {:#?} {:#?}", - match delimiter { - rustc_proc_macro::Delimiter::Parenthesis => "(", - rustc_proc_macro::Delimiter::Brace => "{", - rustc_proc_macro::Delimiter::Bracket => "[", - rustc_proc_macro::Delimiter::None => "$", - }, - match delimiter { - rustc_proc_macro::Delimiter::Parenthesis => ")", - rustc_proc_macro::Delimiter::Brace => "}", - rustc_proc_macro::Delimiter::Bracket => "]", - rustc_proc_macro::Delimiter::None => "$", - }, - span.open, - span.close, - span.entire, - )?; - if let Some(stream) = stream { - debug_token_stream(stream, depth + 1, f)?; - } - return Ok(()); - } - TokenTree::Punct(Punct { ch, joint, span }) => write!( - f, - "PUNCT {span:#?} {} {}", - *ch as char, - if *joint { "[joint]" } else { "[alone]" } - )?, - TokenTree::Ident(Ident { sym, is_raw, span }) => { - write!(f, "IDENT {span:#?} ")?; - if *is_raw { - write!(f, "r#")?; - } - write!(f, "{sym}")?; - } - TokenTree::Literal(Literal { kind, symbol, suffix, span }) => write!( - f, - "LITER {span:#?} {kind:?} {symbol}{}", - match suffix { - Some(suffix) => suffix.clone(), - None => Symbol::intern(""), - } - )?, - } - writeln!(f) -} - -impl TokenStream { - /// Push `tt` onto the end of the stream, possibly gluing it to the last - /// token. Uses `make_mut` to maximize efficiency. - pub(crate) fn push_tree(&mut self, tt: TokenTree) { - let vec_mut = Arc::make_mut(&mut self.0); - vec_mut.push(tt); - } - - /// Push `stream` onto the end of the stream, possibly gluing the first - /// token tree to the last token. (No other token trees will be glued.) - /// Uses `make_mut` to maximize efficiency. - pub(crate) fn push_stream(&mut self, stream: TokenStream) { - let vec_mut = Arc::make_mut(&mut self.0); - - let stream_iter = stream.0.iter().cloned(); - - vec_mut.extend(stream_iter); - } -} - -impl FromIterator> for TokenStream { - fn from_iter>>(iter: I) -> Self { - TokenStream::new(iter.into_iter().collect::>>()) - } -} - -#[derive(Clone)] -pub struct TokenStreamIter<'t, S> { - stream: &'t TokenStream, - index: usize, -} - -impl<'t, S> TokenStreamIter<'t, S> { - fn new(stream: &'t TokenStream) -> Self { - TokenStreamIter { stream, index: 0 } - } -} - -impl<'t, S> Iterator for TokenStreamIter<'t, S> { - type Item = &'t TokenTree; - - fn next(&mut self) -> Option<&'t TokenTree> { - self.stream.0.get(self.index).map(|tree| { - self.index += 1; - tree - }) - } -} - -pub(super) fn literal_from_lexer( - s: &str, - span: Span, - kind: rustc_lexer::LiteralKind, - suffix_start: u32, -) -> Literal { - let (kind, start_offset, end_offset) = match kind { - LiteralKind::Int { .. } => (LitKind::Integer, 0, 0), - LiteralKind::Float { .. } => (LitKind::Float, 0, 0), - LiteralKind::Char { terminated } => (LitKind::Char, 1, terminated as usize), - LiteralKind::Byte { terminated } => (LitKind::Byte, 2, terminated as usize), - LiteralKind::Str { terminated } => (LitKind::Str, 1, terminated as usize), - LiteralKind::ByteStr { terminated } => (LitKind::ByteStr, 2, terminated as usize), - LiteralKind::CStr { terminated } => (LitKind::CStr, 2, terminated as usize), - LiteralKind::RawStr { n_hashes } => ( - LitKind::StrRaw(n_hashes.unwrap_or_default()), - 2 + n_hashes.unwrap_or_default() as usize, - 1 + n_hashes.unwrap_or_default() as usize, - ), - LiteralKind::RawByteStr { n_hashes } => ( - LitKind::ByteStrRaw(n_hashes.unwrap_or_default()), - 3 + n_hashes.unwrap_or_default() as usize, - 1 + n_hashes.unwrap_or_default() as usize, - ), - LiteralKind::RawCStr { n_hashes } => ( - LitKind::CStrRaw(n_hashes.unwrap_or_default()), - 3 + n_hashes.unwrap_or_default() as usize, - 1 + n_hashes.unwrap_or_default() as usize, - ), - }; - - let (lit, suffix) = s.split_at(suffix_start as usize); - let lit = &lit[start_offset..lit.len() - end_offset]; - let suffix = match suffix { - "" | "_" => None, - suffix => Some(Symbol::intern(suffix)), - }; - - Literal { kind, symbol: Symbol::intern(lit), suffix, span } -} - -impl SpanLike for crate::SpanId { - fn derive_ranged(&self, _: std::ops::Range) -> Self { - *self - } -} - -impl SpanLike for () { - fn derive_ranged(&self, _: std::ops::Range) -> Self { - *self - } -} - -impl SpanLike for crate::Span { - fn derive_ranged(&self, range: std::ops::Range) -> Self { - crate::Span { - range: span::TextRange::new( - span::TextSize::new(range.start as u32), - span::TextSize::new(range.end as u32), - ), - anchor: self.anchor, - ctx: self.ctx, - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn ts_to_string() { - let token_stream = - TokenStream::from_str("{} () [] <> ;/., \"gfhdgfuiofghd\" 0f32 r#\"dff\"# 'r#lt", ()) - .unwrap(); - assert_eq!(token_stream.to_string(), "{}()[]<> ;/., \"gfhdgfuiofghd\"0f32 r#\"dff\"#'r#lt"); - } -} +//! The proc-macro server token stream implementation. + +use core::fmt; +use std::{mem, sync::Arc}; + +use intern::Symbol; +use rustc_lexer::{DocStyle, LiteralKind}; +use rustc_proc_macro::Delimiter; + +use crate::bridge::{DelimSpan, Group, Ident, LitKind, Literal, Punct, TokenTree}; + +/// Trait for allowing tests to parse tokenstreams with dynamic span ranges +pub(crate) trait SpanLike { + fn derive_ranged(&self, range: std::ops::Range) -> Self; +} + +#[derive(Clone)] +pub struct TokenStream(pub(crate) Arc>>); + +impl Default for TokenStream { + fn default() -> Self { + Self(Default::default()) + } +} + +impl TokenStream { + pub fn new(tts: Vec>) -> TokenStream { + TokenStream(Arc::new(tts)) + } + + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + pub fn len(&self) -> usize { + self.0.len() + } + + pub fn iter(&self) -> TokenStreamIter<'_, S> { + TokenStreamIter::new(self) + } + + pub fn as_single_group(&self) -> Option<&Group> { + match &**self.0 { + [TokenTree::Group(group)] => Some(group), + _ => None, + } + } + + pub(crate) fn from_str(s: &str, span: S) -> Result + where + S: SpanLike + Copy, + { + let mut groups = Vec::new(); + groups.push((rustc_proc_macro::Delimiter::None, 0..0, vec![])); + let mut offset = 0; + let mut tokens = rustc_lexer::tokenize(s, rustc_lexer::FrontmatterAllowed::No).peekable(); + while let Some(token) = tokens.next() { + let range = offset..offset + token.len as usize; + offset += token.len as usize; + + let mut is_joint = || { + tokens.peek().is_some_and(|token| { + matches!( + token.kind, + rustc_lexer::TokenKind::RawLifetime + | rustc_lexer::TokenKind::GuardedStrPrefix + | rustc_lexer::TokenKind::Lifetime { .. } + | rustc_lexer::TokenKind::Semi + | rustc_lexer::TokenKind::Comma + | rustc_lexer::TokenKind::Dot + | rustc_lexer::TokenKind::OpenParen + | rustc_lexer::TokenKind::CloseParen + | rustc_lexer::TokenKind::OpenBrace + | rustc_lexer::TokenKind::CloseBrace + | rustc_lexer::TokenKind::OpenBracket + | rustc_lexer::TokenKind::CloseBracket + | rustc_lexer::TokenKind::At + | rustc_lexer::TokenKind::Pound + | rustc_lexer::TokenKind::Tilde + | rustc_lexer::TokenKind::Question + | rustc_lexer::TokenKind::Colon + | rustc_lexer::TokenKind::Dollar + | rustc_lexer::TokenKind::Eq + | rustc_lexer::TokenKind::Bang + | rustc_lexer::TokenKind::Lt + | rustc_lexer::TokenKind::Gt + | rustc_lexer::TokenKind::Minus + | rustc_lexer::TokenKind::And + | rustc_lexer::TokenKind::Or + | rustc_lexer::TokenKind::Plus + | rustc_lexer::TokenKind::Star + | rustc_lexer::TokenKind::Slash + | rustc_lexer::TokenKind::Percent + | rustc_lexer::TokenKind::Caret + ) + }) + }; + + let Some((open_delim, _, tokenstream)) = groups.last_mut() else { + return Err("Unbalanced delimiters".to_owned()); + }; + match token.kind { + rustc_lexer::TokenKind::OpenParen => { + groups.push((rustc_proc_macro::Delimiter::Parenthesis, range, vec![])) + } + rustc_lexer::TokenKind::CloseParen if *open_delim != Delimiter::Parenthesis => { + return if *open_delim == Delimiter::None { + Err("Unexpected ')'".to_owned()) + } else { + Err("Expected ')'".to_owned()) + }; + } + rustc_lexer::TokenKind::CloseParen => { + let (delimiter, open_range, stream) = groups.pop().unwrap(); + groups.last_mut().ok_or_else(|| "Unbalanced delimiters".to_owned())?.2.push( + TokenTree::Group(Group { + delimiter, + stream: if stream.is_empty() { + None + } else { + Some(TokenStream::new(stream)) + }, + span: DelimSpan { + entire: span.derive_ranged(open_range.start..range.end), + open: span.derive_ranged(open_range), + close: span.derive_ranged(range), + }, + }), + ); + } + rustc_lexer::TokenKind::OpenBrace => { + groups.push((rustc_proc_macro::Delimiter::Brace, range, vec![])) + } + rustc_lexer::TokenKind::CloseBrace if *open_delim != Delimiter::Brace => { + return if *open_delim == Delimiter::None { + Err("Unexpected '}'".to_owned()) + } else { + Err("Expected '}'".to_owned()) + }; + } + rustc_lexer::TokenKind::CloseBrace => { + let (delimiter, open_range, stream) = groups.pop().unwrap(); + groups.last_mut().ok_or_else(|| "Unbalanced delimiters".to_owned())?.2.push( + TokenTree::Group(Group { + delimiter, + stream: if stream.is_empty() { + None + } else { + Some(TokenStream::new(stream)) + }, + span: DelimSpan { + entire: span.derive_ranged(open_range.start..range.end), + open: span.derive_ranged(open_range), + close: span.derive_ranged(range), + }, + }), + ); + } + rustc_lexer::TokenKind::OpenBracket => { + groups.push((rustc_proc_macro::Delimiter::Bracket, range, vec![])) + } + rustc_lexer::TokenKind::CloseBracket if *open_delim != Delimiter::Bracket => { + return if *open_delim == Delimiter::None { + Err("Unexpected ']'".to_owned()) + } else { + Err("Expected ']'".to_owned()) + }; + } + rustc_lexer::TokenKind::CloseBracket => { + let (delimiter, open_range, stream) = groups.pop().unwrap(); + groups.last_mut().ok_or_else(|| "Unbalanced delimiters".to_owned())?.2.push( + TokenTree::Group(Group { + delimiter, + stream: if stream.is_empty() { + None + } else { + Some(TokenStream::new(stream)) + }, + span: DelimSpan { + entire: span.derive_ranged(open_range.start..range.end), + open: span.derive_ranged(open_range), + close: span.derive_ranged(range), + }, + }), + ); + } + rustc_lexer::TokenKind::LineComment { doc_style: None } + | rustc_lexer::TokenKind::BlockComment { doc_style: None, terminated: _ } => { + continue; + } + rustc_lexer::TokenKind::LineComment { doc_style: Some(doc_style) } => { + let text = &s[range.start + 3..range.end]; + tokenstream.push(TokenTree::Punct(Punct { ch: b'#', joint: false, span })); + if doc_style == DocStyle::Inner { + tokenstream.push(TokenTree::Punct(Punct { ch: b'!', joint: false, span })); + } + tokenstream.push(TokenTree::Group(Group { + delimiter: Delimiter::Bracket, + stream: Some(TokenStream::new(vec![ + TokenTree::Ident(Ident { + sym: Symbol::intern("doc"), + is_raw: false, + span, + }), + TokenTree::Punct(Punct { ch: b'=', joint: false, span }), + TokenTree::Literal(Literal { + kind: LitKind::Str, + symbol: Symbol::intern(&text.escape_debug().to_string()), + suffix: None, + span: span.derive_ranged(range), + }), + ])), + span: DelimSpan { open: span, close: span, entire: span }, + })); + } + rustc_lexer::TokenKind::BlockComment { doc_style: Some(doc_style), terminated } => { + let text = + &s[range.start + 3..if terminated { range.end - 2 } else { range.end }]; + tokenstream.push(TokenTree::Punct(Punct { ch: b'#', joint: false, span })); + if doc_style == DocStyle::Inner { + tokenstream.push(TokenTree::Punct(Punct { ch: b'!', joint: false, span })); + } + tokenstream.push(TokenTree::Group(Group { + delimiter: Delimiter::Bracket, + stream: Some(TokenStream::new(vec![ + TokenTree::Ident(Ident { + sym: Symbol::intern("doc"), + is_raw: false, + span, + }), + TokenTree::Punct(Punct { ch: b'=', joint: false, span }), + TokenTree::Literal(Literal { + kind: LitKind::Str, + symbol: Symbol::intern(&text.escape_debug().to_string()), + suffix: None, + span: span.derive_ranged(range), + }), + ])), + span: DelimSpan { open: span, close: span, entire: span }, + })); + } + rustc_lexer::TokenKind::Whitespace => continue, + rustc_lexer::TokenKind::Frontmatter { .. } => unreachable!(), + rustc_lexer::TokenKind::Unknown => { + return Err(format!("Unknown token: `{}`", &s[range])); + } + rustc_lexer::TokenKind::UnknownPrefix => { + return Err(format!("Unknown prefix: `{}`", &s[range])); + } + rustc_lexer::TokenKind::UnknownPrefixLifetime => { + return Err(format!("Unknown lifetime prefix: `{}`", &s[range])); + } + // FIXME: Error on edition >= 2024 ... I dont think the proc-macro server can fetch editions currently + // and whose edition is this? + rustc_lexer::TokenKind::GuardedStrPrefix => { + tokenstream.push(TokenTree::Punct(Punct { + ch: s.as_bytes()[range.start], + joint: true, + span: span.derive_ranged(range.start..range.start + 1), + })); + tokenstream.push(TokenTree::Punct(Punct { + ch: s.as_bytes()[range.start + 1], + joint: is_joint(), + span: span.derive_ranged(range.start + 1..range.end), + })) + } + rustc_lexer::TokenKind::Ident => tokenstream.push(TokenTree::Ident(Ident { + sym: Symbol::intern(&s[range.clone()]), + is_raw: false, + span: span.derive_ranged(range), + })), + rustc_lexer::TokenKind::InvalidIdent => { + return Err(format!("Invalid identifier: `{}`", &s[range])); + } + rustc_lexer::TokenKind::RawIdent => { + let range = range.start + 2..range.end; + tokenstream.push(TokenTree::Ident(Ident { + sym: Symbol::intern(&s[range.clone()]), + is_raw: true, + span: span.derive_ranged(range), + })) + } + rustc_lexer::TokenKind::Literal { kind, suffix_start } => { + tokenstream.push(TokenTree::Literal(literal_from_lexer( + &s[range.clone()], + span.derive_ranged(range), + kind, + suffix_start, + ))) + } + rustc_lexer::TokenKind::RawLifetime => { + let range = range.start + 1 + 2..range.end; + tokenstream.push(TokenTree::Punct(Punct { + ch: b'\'', + joint: true, + span: span.derive_ranged(range.start..range.start + 1), + })); + tokenstream.push(TokenTree::Ident(Ident { + sym: Symbol::intern(&s[range.clone()]), + is_raw: true, + span: span.derive_ranged(range), + })) + } + rustc_lexer::TokenKind::Lifetime { starts_with_number } => { + if starts_with_number { + return Err("Lifetime cannot start with a number".to_owned()); + } + let range = range.start + 1..range.end; + tokenstream.push(TokenTree::Punct(Punct { + ch: b'\'', + joint: true, + span: span.derive_ranged(range.start..range.start + 1), + })); + tokenstream.push(TokenTree::Ident(Ident { + sym: Symbol::intern(&s[range.clone()]), + is_raw: false, + span: span.derive_ranged(range), + })) + } + rustc_lexer::TokenKind::Semi => tokenstream.push(TokenTree::Punct(Punct { + ch: b';', + joint: is_joint(), + span: span.derive_ranged(range), + })), + rustc_lexer::TokenKind::Comma => tokenstream.push(TokenTree::Punct(Punct { + ch: b',', + joint: is_joint(), + span: span.derive_ranged(range), + })), + rustc_lexer::TokenKind::Dot => tokenstream.push(TokenTree::Punct(Punct { + ch: b'.', + joint: is_joint(), + span: span.derive_ranged(range), + })), + rustc_lexer::TokenKind::At => tokenstream.push(TokenTree::Punct(Punct { + ch: b'@', + joint: is_joint(), + span: span.derive_ranged(range), + })), + rustc_lexer::TokenKind::Pound => tokenstream.push(TokenTree::Punct(Punct { + ch: b'#', + joint: is_joint(), + span: span.derive_ranged(range), + })), + rustc_lexer::TokenKind::Tilde => tokenstream.push(TokenTree::Punct(Punct { + ch: b'~', + joint: is_joint(), + span: span.derive_ranged(range), + })), + rustc_lexer::TokenKind::Question => tokenstream.push(TokenTree::Punct(Punct { + ch: b'?', + joint: is_joint(), + span: span.derive_ranged(range), + })), + rustc_lexer::TokenKind::Colon => tokenstream.push(TokenTree::Punct(Punct { + ch: b':', + joint: is_joint(), + span: span.derive_ranged(range), + })), + rustc_lexer::TokenKind::Dollar => tokenstream.push(TokenTree::Punct(Punct { + ch: b'$', + joint: is_joint(), + span: span.derive_ranged(range), + })), + rustc_lexer::TokenKind::Eq => tokenstream.push(TokenTree::Punct(Punct { + ch: b'=', + joint: is_joint(), + span: span.derive_ranged(range), + })), + rustc_lexer::TokenKind::Bang => tokenstream.push(TokenTree::Punct(Punct { + ch: b'!', + joint: is_joint(), + span: span.derive_ranged(range), + })), + rustc_lexer::TokenKind::Lt => tokenstream.push(TokenTree::Punct(Punct { + ch: b'<', + joint: is_joint(), + span: span.derive_ranged(range), + })), + rustc_lexer::TokenKind::Gt => tokenstream.push(TokenTree::Punct(Punct { + ch: b'>', + joint: is_joint(), + span: span.derive_ranged(range), + })), + rustc_lexer::TokenKind::Minus => tokenstream.push(TokenTree::Punct(Punct { + ch: b'-', + joint: is_joint(), + span: span.derive_ranged(range), + })), + rustc_lexer::TokenKind::And => tokenstream.push(TokenTree::Punct(Punct { + ch: b'&', + joint: is_joint(), + span: span.derive_ranged(range), + })), + rustc_lexer::TokenKind::Or => tokenstream.push(TokenTree::Punct(Punct { + ch: b'|', + joint: is_joint(), + span: span.derive_ranged(range), + })), + rustc_lexer::TokenKind::Plus => tokenstream.push(TokenTree::Punct(Punct { + ch: b'+', + joint: is_joint(), + span: span.derive_ranged(range), + })), + rustc_lexer::TokenKind::Star => tokenstream.push(TokenTree::Punct(Punct { + ch: b'*', + joint: is_joint(), + span: span.derive_ranged(range), + })), + rustc_lexer::TokenKind::Slash => tokenstream.push(TokenTree::Punct(Punct { + ch: b'/', + joint: is_joint(), + span: span.derive_ranged(range), + })), + rustc_lexer::TokenKind::Caret => tokenstream.push(TokenTree::Punct(Punct { + ch: b'^', + joint: is_joint(), + span: span.derive_ranged(range), + })), + rustc_lexer::TokenKind::Percent => tokenstream.push(TokenTree::Punct(Punct { + ch: b'%', + joint: is_joint(), + span: span.derive_ranged(range), + })), + rustc_lexer::TokenKind::Eof => break, + } + } + if let Some((Delimiter::None, _, tokentrees)) = groups.pop() + && groups.is_empty() + { + Ok(TokenStream::new(tokentrees)) + } else { + Err("Mismatched token groups".to_owned()) + } + } +} + +impl fmt::Display for TokenStream { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut emit_whitespace = false; + for tt in self.0.iter() { + display_token_tree(tt, &mut emit_whitespace, f)?; + } + Ok(()) + } +} + +fn display_token_tree( + tt: &TokenTree, + emit_whitespace: &mut bool, + f: &mut std::fmt::Formatter<'_>, +) -> std::fmt::Result { + if mem::take(emit_whitespace) { + write!(f, " ")?; + } + match tt { + TokenTree::Group(Group { delimiter, stream, span: _ }) => { + write!( + f, + "{}", + match delimiter { + rustc_proc_macro::Delimiter::Parenthesis => "(", + rustc_proc_macro::Delimiter::Brace => "{", + rustc_proc_macro::Delimiter::Bracket => "[", + rustc_proc_macro::Delimiter::None => "", + } + )?; + if let Some(stream) = stream { + write!(f, "{stream}")?; + } + write!( + f, + "{}", + match delimiter { + rustc_proc_macro::Delimiter::Parenthesis => ")", + rustc_proc_macro::Delimiter::Brace => "}", + rustc_proc_macro::Delimiter::Bracket => "]", + rustc_proc_macro::Delimiter::None => "", + } + )?; + } + TokenTree::Punct(Punct { ch, joint, span: _ }) => { + *emit_whitespace = !*joint; + write!(f, "{}", *ch as char)?; + } + TokenTree::Ident(Ident { sym, is_raw, span: _ }) => { + if *is_raw { + write!(f, "r#")?; + } + write!(f, "{sym}")?; + *emit_whitespace = true; + } + TokenTree::Literal(lit) => { + display_fmt_literal(lit, f)?; + let joint = match lit.kind { + LitKind::Str + | LitKind::StrRaw(_) + | LitKind::ByteStr + | LitKind::ByteStrRaw(_) + | LitKind::CStr + | LitKind::CStrRaw(_) => true, + _ => false, + }; + *emit_whitespace = !joint; + } + } + Ok(()) +} + +pub fn literal_to_string(literal: &Literal) -> String { + let mut buf = String::new(); + display_fmt_literal(literal, &mut buf).unwrap(); + buf +} + +fn display_fmt_literal(literal: &Literal, f: &mut impl std::fmt::Write) -> fmt::Result { + match literal.kind { + LitKind::Byte => write!(f, "b'{}'", literal.symbol), + LitKind::Char => write!(f, "'{}'", literal.symbol), + LitKind::Integer | LitKind::Float | LitKind::ErrWithGuar => { + write!(f, "{}", literal.symbol) + } + LitKind::Str => write!(f, "\"{}\"", literal.symbol), + LitKind::ByteStr => write!(f, "b\"{}\"", literal.symbol), + LitKind::CStr => write!(f, "c\"{}\"", literal.symbol), + LitKind::StrRaw(num_of_hashes) => { + let num_of_hashes = num_of_hashes as usize; + write!( + f, + r#"r{0:# { + let num_of_hashes = num_of_hashes as usize; + write!( + f, + r#"br{0:# { + let num_of_hashes = num_of_hashes as usize; + write!( + f, + r#"cr{0:# fmt::Debug for TokenStream { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + debug_token_stream(self, 0, f) + } +} + +fn debug_token_stream( + ts: &TokenStream, + depth: usize, + f: &mut std::fmt::Formatter<'_>, +) -> std::fmt::Result { + for tt in ts.0.iter() { + debug_token_tree(tt, depth, f)?; + } + Ok(()) +} + +fn debug_token_tree( + tt: &TokenTree, + depth: usize, + f: &mut std::fmt::Formatter<'_>, +) -> std::fmt::Result { + write!(f, "{:indent$}", "", indent = depth * 2)?; + match tt { + TokenTree::Group(Group { delimiter, stream, span }) => { + writeln!( + f, + "GROUP {}{} {:#?} {:#?} {:#?}", + match delimiter { + rustc_proc_macro::Delimiter::Parenthesis => "(", + rustc_proc_macro::Delimiter::Brace => "{", + rustc_proc_macro::Delimiter::Bracket => "[", + rustc_proc_macro::Delimiter::None => "$", + }, + match delimiter { + rustc_proc_macro::Delimiter::Parenthesis => ")", + rustc_proc_macro::Delimiter::Brace => "}", + rustc_proc_macro::Delimiter::Bracket => "]", + rustc_proc_macro::Delimiter::None => "$", + }, + span.open, + span.close, + span.entire, + )?; + if let Some(stream) = stream { + debug_token_stream(stream, depth + 1, f)?; + } + return Ok(()); + } + TokenTree::Punct(Punct { ch, joint, span }) => write!( + f, + "PUNCT {span:#?} {} {}", + *ch as char, + if *joint { "[joint]" } else { "[alone]" } + )?, + TokenTree::Ident(Ident { sym, is_raw, span }) => { + write!(f, "IDENT {span:#?} ")?; + if *is_raw { + write!(f, "r#")?; + } + write!(f, "{sym}")?; + } + TokenTree::Literal(Literal { kind, symbol, suffix, span }) => write!( + f, + "LITER {span:#?} {kind:?} {symbol}{}", + match suffix { + Some(suffix) => suffix.clone(), + None => Symbol::intern(""), + } + )?, + } + writeln!(f) +} + +impl TokenStream { + /// Push `tt` onto the end of the stream, possibly gluing it to the last + /// token. Uses `make_mut` to maximize efficiency. + pub(crate) fn push_tree(&mut self, tt: TokenTree) { + let vec_mut = Arc::make_mut(&mut self.0); + vec_mut.push(tt); + } + + /// Push `stream` onto the end of the stream, possibly gluing the first + /// token tree to the last token. (No other token trees will be glued.) + /// Uses `make_mut` to maximize efficiency. + pub(crate) fn push_stream(&mut self, stream: TokenStream) { + let vec_mut = Arc::make_mut(&mut self.0); + + let stream_iter = stream.0.iter().cloned(); + + vec_mut.extend(stream_iter); + } +} + +impl FromIterator> for TokenStream { + fn from_iter>>(iter: I) -> Self { + TokenStream::new(iter.into_iter().collect::>>()) + } +} + +#[derive(Clone)] +pub struct TokenStreamIter<'t, S> { + stream: &'t TokenStream, + index: usize, +} + +impl<'t, S> TokenStreamIter<'t, S> { + fn new(stream: &'t TokenStream) -> Self { + TokenStreamIter { stream, index: 0 } + } +} + +impl<'t, S> Iterator for TokenStreamIter<'t, S> { + type Item = &'t TokenTree; + + fn next(&mut self) -> Option<&'t TokenTree> { + self.stream.0.get(self.index).map(|tree| { + self.index += 1; + tree + }) + } +} + +pub(super) fn literal_from_lexer( + s: &str, + span: Span, + kind: rustc_lexer::LiteralKind, + suffix_start: u32, +) -> Literal { + let (kind, start_offset, end_offset) = match kind { + LiteralKind::Int { .. } => (LitKind::Integer, 0, 0), + LiteralKind::Float { .. } => (LitKind::Float, 0, 0), + LiteralKind::Char { terminated } => (LitKind::Char, 1, terminated as usize), + LiteralKind::Byte { terminated } => (LitKind::Byte, 2, terminated as usize), + LiteralKind::Str { terminated } => (LitKind::Str, 1, terminated as usize), + LiteralKind::ByteStr { terminated } => (LitKind::ByteStr, 2, terminated as usize), + LiteralKind::CStr { terminated } => (LitKind::CStr, 2, terminated as usize), + LiteralKind::RawStr { n_hashes } => ( + LitKind::StrRaw(n_hashes.unwrap_or_default()), + 2 + n_hashes.unwrap_or_default() as usize, + 1 + n_hashes.unwrap_or_default() as usize, + ), + LiteralKind::RawByteStr { n_hashes } => ( + LitKind::ByteStrRaw(n_hashes.unwrap_or_default()), + 3 + n_hashes.unwrap_or_default() as usize, + 1 + n_hashes.unwrap_or_default() as usize, + ), + LiteralKind::RawCStr { n_hashes } => ( + LitKind::CStrRaw(n_hashes.unwrap_or_default()), + 3 + n_hashes.unwrap_or_default() as usize, + 1 + n_hashes.unwrap_or_default() as usize, + ), + }; + + let (lit, suffix) = s.split_at(suffix_start as usize); + let lit = &lit[start_offset..lit.len() - end_offset]; + let suffix = match suffix { + "" | "_" => None, + suffix => Some(Symbol::intern(suffix)), + }; + + Literal { kind, symbol: Symbol::intern(lit), suffix, span } +} + +impl SpanLike for crate::SpanId { + fn derive_ranged(&self, _: std::ops::Range) -> Self { + *self + } +} + +impl SpanLike for () { + fn derive_ranged(&self, _: std::ops::Range) -> Self { + *self + } +} + +impl SpanLike for crate::Span { + fn derive_ranged(&self, range: std::ops::Range) -> Self { + crate::Span { + range: span::TextRange::new( + span::TextSize::new(range.start as u32), + span::TextSize::new(range.end as u32), + ), + anchor: self.anchor, + ctx: self.ctx, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn ts_to_string() { + let token_stream = + TokenStream::from_str("{} () [] <> ;/., \"gfhdgfuiofghd\" 0f32 r#\"dff\"# 'r#lt", ()) + .unwrap(); + assert_eq!(token_stream.to_string(), "{}()[]<> ;/., \"gfhdgfuiofghd\"0f32 r#\"dff\"#'r#lt"); + } + + #[test] + fn doc_comment_from_str() { + let token_stream = TokenStream::from_str("/// foo", ()).unwrap(); + assert_eq!(token_stream.to_string(), r#"# [doc = " foo"]"#); + } +} diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs index 336350653b48f..9f84f632d5e44 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs @@ -477,13 +477,19 @@ impl WorkspaceBuildScripts { cmd.arg("--lockfile-path"); cmd.arg(lockfile_copy.path.as_str()); } - LockfileUsage::WithEnvVar => { + LockfileUsage::WithEnvVarUnstable => { cmd.arg("-Zlockfile-path"); cmd.env( "CARGO_RESOLVER_LOCKFILE_PATH", lockfile_copy.path.as_os_str(), ); } + LockfileUsage::WithEnvVar => { + cmd.env( + "CARGO_RESOLVER_LOCKFILE_PATH", + lockfile_copy.path.as_os_str(), + ); + } } } } diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs index 39d1a82518bf0..defd9f96ab5fb 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs @@ -145,7 +145,9 @@ pub(crate) struct LockfileCopy { pub(crate) enum LockfileUsage { /// Rust [1.82.0, 1.95.0). `cargo --lockfile-path ` WithFlag, - /// Rust >= 1.95.0. `CARGO_RESOLVER_LOCKFILE_PATH= cargo ` + /// Rust [1.95.0, 1.97.0). `CARGO_RESOLVER_LOCKFILE_PATH= cargo -Zlockfile-path ` + WithEnvVarUnstable, + /// Rust >= 1.97.0. `CARGO_RESOLVER_LOCKFILE_PATH= cargo ` WithEnvVar, } @@ -162,7 +164,7 @@ pub(crate) fn make_lockfile_copy( build: semver::BuildMetadata::EMPTY, }; - const MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH_ENV: semver::Version = + const MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH_ENV_UNSTABLE: semver::Version = semver::Version { major: 1, minor: 95, @@ -171,8 +173,20 @@ pub(crate) fn make_lockfile_copy( build: semver::BuildMetadata::EMPTY, }; + const MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH_ENV: semver::Version = + semver::Version { + major: 1, + minor: 97, + patch: 0, + pre: semver::Prerelease::EMPTY, + build: semver::BuildMetadata::EMPTY, + }; + let usage = if *toolchain_version >= MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH_ENV { LockfileUsage::WithEnvVar + } else if *toolchain_version >= MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH_ENV_UNSTABLE + { + LockfileUsage::WithEnvVarUnstable } else if *toolchain_version >= MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH_FLAG { LockfileUsage::WithFlag } else { diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs index 004d62967a49d..97375fe9ddd1a 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs @@ -771,10 +771,13 @@ impl FetchMetadata { other_options.push("--lockfile-path".to_owned()); other_options.push(lockfile_copy.path.to_string()); } - LockfileUsage::WithEnvVar => { + LockfileUsage::WithEnvVarUnstable => { other_options.push("-Zlockfile-path".to_owned()); command.env("CARGO_RESOLVER_LOCKFILE_PATH", lockfile_copy.path.as_os_str()); } + LockfileUsage::WithEnvVar => { + command.env("CARGO_RESOLVER_LOCKFILE_PATH", lockfile_copy.path.as_os_str()); + } } using_lockfile_copy = true; } diff --git a/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs b/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs index 37b8da8b42a7a..810737a1dfd14 100644 --- a/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs +++ b/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs @@ -89,32 +89,16 @@ enum QueryKind { #[derive(Default, Debug, Clone)] struct Cycle { - cycle_fn: Option<(syn::Ident, Path)>, - cycle_initial: Option<(syn::Ident, Path)>, cycle_result: Option<(syn::Ident, Path)>, } impl Parse for Cycle { fn parse(input: ParseStream<'_>) -> syn::Result { let options = Punctuated::::parse_terminated(input)?; - let mut cycle_fn = None; - let mut cycle_initial = None; let mut cycle_result = None; for option in options { let name = option.name.to_string(); match &*name { - "cycle_fn" => { - if cycle_fn.is_some() { - return Err(syn::Error::new_spanned(&option.name, "duplicate option")); - } - cycle_fn = Some((option.name, option.value)); - } - "cycle_initial" => { - if cycle_initial.is_some() { - return Err(syn::Error::new_spanned(&option.name, "duplicate option")); - } - cycle_initial = Some((option.name, option.value)); - } "cycle_result" => { if cycle_result.is_some() { return Err(syn::Error::new_spanned(&option.name, "duplicate option")); @@ -124,12 +108,12 @@ impl Parse for Cycle { _ => { return Err(syn::Error::new_spanned( &option.name, - "unknown cycle option. Accepted values: `cycle_result`, `cycle_fn`, `cycle_initial`", + "unknown cycle option. Accepted values: `cycle_result`", )); } } } - return Ok(Self { cycle_fn, cycle_initial, cycle_result }); + return Ok(Self { cycle_result }); struct Option { name: syn::Ident, diff --git a/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs b/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs index 62dced54d023e..96e8ca5758f6e 100644 --- a/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs +++ b/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs @@ -32,13 +32,8 @@ impl ToTokens for TrackedQuery { let options = self .cycle .as_ref() - .map(|Cycle { cycle_fn, cycle_initial, cycle_result }| { - let cycle_fn = cycle_fn.as_ref().map(|(ident, path)| quote!(#ident=#path)); - let cycle_initial = - cycle_initial.as_ref().map(|(ident, path)| quote!(#ident=#path)); - let cycle_result = cycle_result.as_ref().map(|(ident, path)| quote!(#ident=#path)); - let options = cycle_fn.into_iter().chain(cycle_initial).chain(cycle_result); - quote!(#(#options),*) + .map(|Cycle { cycle_result }| { + cycle_result.as_ref().map(|(ident, path)| quote!(#ident=#path)) }) .into_iter(); let annotation = quote!(#[salsa_macros::tracked( #(#options),* )]); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml index dd8649e09529c..ae0c9571210ac 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml @@ -29,7 +29,7 @@ ide-completion.workspace = true indexmap.workspace = true itertools.workspace = true scip = "0.7.1" -lsp-types = { version = "0.4.0", package = "gen-lsp-types", features=["url"] } +lsp-types = { version = "0.10.0", package = "gen-lsp-types", features = ["url"] } parking_lot = "0.12.4" xflags = "0.3.2" oorandom = "11.1.5" diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index 1a036c3b99195..ae9a0cf094cae 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -12,8 +12,7 @@ use std::{ use cfg::{CfgAtom, CfgDiff}; use hir::{ Adt, AssocItem, Crate, DefWithBody, FindPathConfig, GenericDef, HasCrate, HasSource, - HirDisplay, ModuleDef, Name, Variant, crate_lang_items, - db::{DefDatabase, ExpandDatabase, HirDatabase}, + HirDisplay, ModuleDef, Name, Variant, crate_lang_items, db::HirDatabase, }; use hir_def::{ DefWithBodyId, ExpressionStoreOwnerId, GenericDefId, SyntheticSyntax, @@ -151,26 +150,26 @@ impl flags::AnalysisStats { // measure workspace/project code if !source_root.is_library || self.with_deps { let length = db.file_text(file_id).text(db).lines().count(); - let item_stats = db - .file_item_tree( - EditionedFileId::current_edition(db, file_id).into(), - krate.into(), - ) - .item_tree_stats() - .into(); + let item_stats = hir::db::file_item_tree( + db, + EditionedFileId::current_edition(db, file_id).into(), + krate.into(), + ) + .item_tree_stats() + .into(); workspace_loc += length; workspace_item_trees += 1; workspace_item_stats += item_stats; } else { let length = db.file_text(file_id).text(db).lines().count(); - let item_stats = db - .file_item_tree( - EditionedFileId::current_edition(db, file_id).into(), - krate.into(), - ) - .item_tree_stats() - .into(); + let item_stats = hir::db::file_item_tree( + db, + EditionedFileId::current_edition(db, file_id).into(), + krate.into(), + ) + .item_tree_stats() + .into(); dep_loc += length; dep_item_trees += 1; @@ -1503,7 +1502,7 @@ fn location_csv_expr(db: &RootDatabase, vfs: &Vfs, sm: &BodySourceMap, expr_id: Ok(s) => s, Err(SyntheticSyntax) => return "synthetic,,".to_owned(), }; - let root = db.parse_or_expand(src.file_id); + let root = src.file_id.parse_or_expand(db); let node = src.map(|e| e.to_node(&root).syntax().clone()); let original_range = node.as_ref().original_file_range_rooted(db); let path = vfs.file_path(original_range.file_id.file_id(db)); @@ -1519,7 +1518,7 @@ fn location_csv_pat(db: &RootDatabase, vfs: &Vfs, sm: &BodySourceMap, pat_id: Pa Ok(s) => s, Err(SyntheticSyntax) => return "synthetic,,".to_owned(), }; - let root = db.parse_or_expand(src.file_id); + let root = src.file_id.parse_or_expand(db); let node = src.map(|e| e.to_node(&root).syntax().clone()); let original_range = node.as_ref().original_file_range_rooted(db); let path = vfs.file_path(original_range.file_id.file_id(db)); @@ -1538,7 +1537,7 @@ fn expr_syntax_range<'a>( ) -> Option<(&'a VfsPath, LineCol, LineCol)> { let src = sm.expr_syntax(expr_id); if let Ok(src) = src { - let root = db.parse_or_expand(src.file_id); + let root = src.file_id.parse_or_expand(db); let node = src.map(|e| e.to_node(&root).syntax().clone()); let original_range = node.as_ref().original_file_range_rooted(db); let path = vfs.file_path(original_range.file_id.file_id(db)); @@ -1559,7 +1558,7 @@ fn pat_syntax_range<'a>( ) -> Option<(&'a VfsPath, LineCol, LineCol)> { let src = sm.pat_syntax(pat_id); if let Ok(src) = src { - let root = db.parse_or_expand(src.file_id); + let root = src.file_id.parse_or_expand(db); let node = src.map(|e| e.to_node(&root).syntax().clone()); let original_range = node.as_ref().original_file_range_rooted(db); let path = vfs.file_path(original_range.file_id.file_id(db)); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 552fb079c2b8a..f464a2487507e 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -395,7 +395,7 @@ config_data! { /// /// Controls how many independent `proc-macro-srv` processes rust-analyzer /// runs in parallel to handle macro expansion. - procMacro_processes: NumProcesses = NumProcesses::Concrete(1), + procMacro_processes: NumProcesses = NumProcesses::Concrete(2), /// Internal config, path to proc-macro server executable. procMacro_server: Option = None, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs index 889d20a184b25..fdeb75bcef888 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs @@ -60,7 +60,7 @@ pub(crate) struct DiagnosticCollection { #[derive(Debug, Clone)] pub(crate) struct Fix { // Fixes may be triggerable from multiple ranges. - pub(crate) ranges: SmallVec<[lsp_types::Range; 1]>, + pub(crate) ranges: SmallVec<[lsp_types::Range; 2]>, pub(crate) action: lsp_ext::CodeAction, } @@ -181,11 +181,12 @@ impl DiagnosticCollection { } } - if let Some(fix) = fix { + if let Some(mut fix) = fix { let check_fixes = Arc::make_mut(&mut self.check_fixes); if check_fixes.len() <= flycheck_id { check_fixes.resize_with(flycheck_id + 1, Default::default); } + fix.ranges.push(diagnostic.range); check_fixes[flycheck_id] .entry(package_id.clone()) .or_default() @@ -362,7 +363,7 @@ pub(crate) fn convert_diagnostic( href: lsp_types::Uri::parse(&d.code.url()).unwrap(), }), source: Some("rust-analyzer".to_owned()), - message: d.message, + message: lsp_types::Message::String(d.message), related_information: None, tags: d.unused.then(|| vec![lsp_types::DiagnosticTag::Unnecessary]), data: None, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/flycheck_to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/flycheck_to_proto.rs index 8568f4798c032..59ab748c2f62a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/flycheck_to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/flycheck_to_proto.rs @@ -375,7 +375,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp( if needs_primary_span_label && let Some(primary_span_label) = &primary_span.label { format_to!(message, "\n{}", primary_span_label); } - message + lsp_types::Message::String(message) }; let mut related_info_macro_calls = vec![]; @@ -475,7 +475,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp( code: code.map(ToOwned::to_owned).map(lsp_types::Code::String), code_description: code_description.clone(), source: Some(source.to_owned()), - message: sub.related.message.clone(), + message: sub.related.message.clone().into(), related_information: Some(vec![back_ref.clone()]), tags: None, // don't apply modifiers again data: None, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt index 71f99874b173c..4f6d2009d2c6d 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt @@ -54,7 +54,9 @@ source: Some( "clippy", ), - message: "this argument is passed by reference, but would be more efficient if passed by value\n#[warn(clippy::trivially_copy_pass_by_ref)] implied by #[warn(clippy::all)]\nfor further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref", + message: String( + "this argument is passed by reference, but would be more efficient if passed by value\n#[warn(clippy::trivially_copy_pass_by_ref)] implied by #[warn(clippy::all)]\nfor further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref", + ), tags: None, related_information: Some( [ @@ -171,7 +173,9 @@ source: Some( "clippy", ), - message: "lint level defined here", + message: String( + "lint level defined here", + ), tags: None, related_information: Some( [ @@ -262,7 +266,9 @@ source: Some( "clippy", ), - message: "consider passing by value instead: `self`", + message: String( + "consider passing by value instead: `self`", + ), tags: None, related_information: Some( [ diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt index bd1abfe921185..f1bcc06991c69 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt @@ -54,7 +54,9 @@ source: Some( "rustc", ), - message: "can't compare `{integer}` with `&str`\nthe trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`", + message: String( + "can't compare `{integer}` with `&str`\nthe trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`", + ), tags: None, related_information: None, data: None, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt index cc870c48af74c..2405831682a7a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt @@ -30,7 +30,9 @@ source: Some( "rustc", ), - message: "Please register your known path in the path module", + message: String( + "Please register your known path in the path module", + ), tags: None, related_information: Some( [ @@ -97,7 +99,9 @@ source: Some( "rustc", ), - message: "Please register your known path in the path module", + message: String( + "Please register your known path in the path module", + ), tags: None, related_information: Some( [ @@ -164,7 +168,9 @@ source: Some( "rustc", ), - message: "Please register your known path in the path module", + message: String( + "Please register your known path in the path module", + ), tags: None, related_information: Some( [ diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/reasonable_line_numbers_from_empty_file.txt b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/reasonable_line_numbers_from_empty_file.txt index 176d7198ac206..8500e61d300b6 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/reasonable_line_numbers_from_empty_file.txt +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/reasonable_line_numbers_from_empty_file.txt @@ -54,7 +54,9 @@ source: Some( "rustc", ), - message: "`main` function not found in crate `current`\nconsider adding a `main` function to `src/bin/current.rs`", + message: String( + "`main` function not found in crate `current`\nconsider adding a `main` function to `src/bin/current.rs`", + ), tags: None, related_information: None, data: None, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt index e78ac4b27dab4..909bbe2f6a2f7 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt @@ -54,7 +54,9 @@ source: Some( "rustc", ), - message: "method `next` has an incompatible type for trait\nexpected type `fn(&mut ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&ty::Ref>`\n found type `fn(&ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&'list ty::Ref>`", + message: String( + "method `next` has an incompatible type for trait\nexpected type `fn(&mut ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&ty::Ref>`\n found type `fn(&ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&'list ty::Ref>`", + ), tags: None, related_information: None, data: None, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt index add343d24566f..39941652fda3f 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt @@ -54,7 +54,9 @@ source: Some( "rustc", ), - message: "mismatched types\nexpected usize, found u32", + message: String( + "mismatched types\nexpected usize, found u32", + ), tags: None, related_information: None, data: None, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_range_map_lsp_position.txt b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_range_map_lsp_position.txt index a510943965b48..3c10dacafb413 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_range_map_lsp_position.txt +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_range_map_lsp_position.txt @@ -54,7 +54,9 @@ source: Some( "rustc", ), - message: "mismatched types\nexpected `u32`, found `&str`", + message: String( + "mismatched types\nexpected `u32`, found `&str`", + ), tags: None, related_information: Some( [ @@ -145,7 +147,9 @@ source: Some( "rustc", ), - message: "expected due to this", + message: String( + "expected due to this", + ), tags: None, related_information: Some( [ diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt index f5bf2dce3057a..7410e14972870 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt @@ -34,7 +34,9 @@ source: Some( "rustc", ), - message: "unused variable: `foo`\n#[warn(unused_variables)] on by default", + message: String( + "unused variable: `foo`\n#[warn(unused_variables)] on by default", + ), tags: Some( [ Unnecessary, @@ -109,7 +111,9 @@ source: Some( "rustc", ), - message: "consider prefixing with an underscore: `_foo`", + message: String( + "consider prefixing with an underscore: `_foo`", + ), tags: None, related_information: Some( [ diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt index 5f4aa7157644d..0cff5ebba8021 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt @@ -34,7 +34,9 @@ source: Some( "rustc", ), - message: "unused variable: `foo`\n#[warn(unused_variables)] on by default", + message: String( + "unused variable: `foo`\n#[warn(unused_variables)] on by default", + ), tags: Some( [ Unnecessary, @@ -109,7 +111,9 @@ source: Some( "rustc", ), - message: "consider prefixing with an underscore: `_foo`", + message: String( + "consider prefixing with an underscore: `_foo`", + ), tags: None, related_information: Some( [ diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt index 26adf5311857b..23797634ae057 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt @@ -34,7 +34,9 @@ source: Some( "rustc", ), - message: "unused variable: `foo`\n#[warn(unused_variables)] on by default", + message: String( + "unused variable: `foo`\n#[warn(unused_variables)] on by default", + ), tags: Some( [ Unnecessary, @@ -109,7 +111,9 @@ source: Some( "rustc", ), - message: "consider prefixing with an underscore: `_foo`", + message: String( + "consider prefixing with an underscore: `_foo`", + ), tags: None, related_information: Some( [ diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt index cd3c24f0c3cf6..900f99701b2b6 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt @@ -54,7 +54,9 @@ source: Some( "rustc", ), - message: "this function takes 2 parameters but 3 parameters were supplied\nexpected 2 parameters", + message: String( + "this function takes 2 parameters but 3 parameters were supplied\nexpected 2 parameters", + ), tags: None, related_information: Some( [ @@ -145,7 +147,9 @@ source: Some( "rustc", ), - message: "defined here", + message: String( + "defined here", + ), tags: None, related_information: Some( [ diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt index a977d14cf7840..bb8612f43ecf3 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt @@ -54,7 +54,9 @@ source: Some( "clippy", ), - message: "returning the result of a let binding from a block\n`#[warn(clippy::let_and_return)]` on by default\nfor further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return", + message: String( + "returning the result of a let binding from a block\n`#[warn(clippy::let_and_return)]` on by default\nfor further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return", + ), tags: None, related_information: Some( [ @@ -171,7 +173,9 @@ source: Some( "clippy", ), - message: "unnecessary let binding", + message: String( + "unnecessary let binding", + ), tags: None, related_information: Some( [ @@ -262,7 +266,9 @@ source: Some( "clippy", ), - message: "return the expression directly: `(0..10).collect()`", + message: String( + "return the expression directly: `(0..10).collect()`", + ), tags: None, related_information: Some( [ diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs index 16dd9bee1fc05..f73ffb24eea32 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs @@ -494,33 +494,24 @@ impl<'a> Substitutions<'a> { let mut cmd = toolchain::command(&template.program, &template.cwd, extra_env); for arg in &template.args { if let Some(ix) = arg.find(LABEL_INLINE) { - if let Some(label) = self.label { - let mut arg = arg.to_string(); - arg.replace_range(ix..ix + LABEL_INLINE.len(), label); - cmd.arg(arg); - continue; - } else { - return None; - } + let label = self.label?; + let mut arg = arg.to_string(); + arg.replace_range(ix..ix + LABEL_INLINE.len(), label); + cmd.arg(arg); + continue; } if let Some(ix) = arg.find(SAVED_FILE_INLINE) { - if let Some(saved_file) = self.saved_file { - let mut arg = arg.to_string(); - arg.replace_range(ix..ix + SAVED_FILE_INLINE.len(), saved_file); - cmd.arg(arg); - continue; - } else { - return None; - } + let saved_file = self.saved_file?; + let mut arg = arg.to_string(); + arg.replace_range(ix..ix + SAVED_FILE_INLINE.len(), saved_file); + cmd.arg(arg); + continue; } // Legacy syntax: full argument match if arg == SAVED_FILE_PLACEHOLDER_DOLLAR { - if let Some(saved_file) = self.saved_file { - cmd.arg(saved_file); - continue; - } else { - return None; - } + let saved_file = self.saved_file?; + cmd.arg(saved_file); + continue; } cmd.arg(arg); } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs index 2d01aa4d515eb..5388f68f02194 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs @@ -661,17 +661,28 @@ impl GlobalState { // See https://github.com/rust-lang/rust-analyzer/issues/11404 // See https://github.com/rust-lang/rust-analyzer/issues/13130 - let patch_empty = |message: &mut String| { - if message.is_empty() { - " ".clone_into(message); + let patch_empty = |message: &mut lsp_types::Message| match message { + lsp_types::Message::String(m) if m.is_empty() => { + " ".clone_into(m); } + lsp_types::Message::MarkupContent(lsp_types::MarkupContent { + value, + kind: _, + }) if value.is_empty() => { + " ".clone_into(value); + } + _ => {} }; for d in &mut diagnostics { patch_empty(&mut d.message); if let Some(dri) = &mut d.related_information { for dri in dri { - patch_empty(&mut dri.message); + // The LSP does not (yet?) specify that related diagnostic messages can + // be in Markdown format (in addition to plain text). + if dri.message.is_empty() { + " ".clone_into(&mut dri.message); + } } } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index e57b05660d5a7..41e3db7f3191a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -1575,6 +1575,7 @@ pub(crate) fn handle_code_action( .copied() .filter_map(|range| from_proto::text_range(&line_index, range).ok()) .any(|fix_range| fix_range.intersect(frange.range).is_some()); + if intersect_fix_range { res.push(fix.action.clone()); } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs index 3a1945c881709..8e0bb285c2318 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs @@ -35,7 +35,7 @@ impl Request for InternalTestingFetchConfigRequest { type Params = InternalTestingFetchConfigParams; // Option is solely to circumvent Default bound. type Result = Option; - const METHOD: LspRequestMethod = + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("rust-analyzer-internal/internalTestingFetchConfig"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -51,7 +51,7 @@ pub enum AnalyzerStatusRequest {} impl Request for AnalyzerStatusRequest { type Params = AnalyzerStatusParams; type Result = String; - const METHOD: LspRequestMethod = LspRequestMethod::new("rust-analyzer/analyzerStatus"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("rust-analyzer/analyzerStatus"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -73,7 +73,7 @@ pub enum FetchDependencyListRequest {} impl Request for FetchDependencyListRequest { type Params = FetchDependencyListParams; type Result = FetchDependencyListResult; - const METHOD: LspRequestMethod = LspRequestMethod::new("rust-analyzer/fetchDependencyList"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("rust-analyzer/fetchDependencyList"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -92,7 +92,7 @@ pub enum MemoryUsageRequest {} impl Request for MemoryUsageRequest { type Params = (); type Result = String; - const METHOD: LspRequestMethod = LspRequestMethod::new("rust-analyzer/memoryUsage"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("rust-analyzer/memoryUsage"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -101,7 +101,7 @@ pub enum ReloadWorkspaceRequest {} impl Request for ReloadWorkspaceRequest { type Params = (); type Result = (); - const METHOD: LspRequestMethod = LspRequestMethod::new("rust-analyzer/reloadWorkspace"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("rust-analyzer/reloadWorkspace"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -110,7 +110,7 @@ pub enum RebuildProcMacrosRequest {} impl Request for RebuildProcMacrosRequest { type Params = (); type Result = (); - const METHOD: LspRequestMethod = LspRequestMethod::new("rust-analyzer/rebuildProcMacros"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("rust-analyzer/rebuildProcMacros"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -119,7 +119,7 @@ pub enum ViewSyntaxTreeRequest {} impl Request for ViewSyntaxTreeRequest { type Params = ViewSyntaxTreeParams; type Result = String; - const METHOD: LspRequestMethod = LspRequestMethod::new("rust-analyzer/viewSyntaxTree"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("rust-analyzer/viewSyntaxTree"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -134,7 +134,7 @@ pub enum ViewHirRequest {} impl Request for ViewHirRequest { type Params = lsp_types::TextDocumentPositionParams; type Result = String; - const METHOD: LspRequestMethod = LspRequestMethod::new("rust-analyzer/viewHir"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("rust-analyzer/viewHir"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -143,7 +143,7 @@ pub enum ViewMirRequest {} impl Request for ViewMirRequest { type Params = lsp_types::TextDocumentPositionParams; type Result = String; - const METHOD: LspRequestMethod = LspRequestMethod::new("rust-analyzer/viewMir"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("rust-analyzer/viewMir"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -152,7 +152,7 @@ pub enum InterpretFunctionRequest {} impl Request for InterpretFunctionRequest { type Params = lsp_types::TextDocumentPositionParams; type Result = String; - const METHOD: LspRequestMethod = LspRequestMethod::new("rust-analyzer/interpretFunction"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("rust-analyzer/interpretFunction"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -161,7 +161,7 @@ pub enum ViewFileTextRequest {} impl Request for ViewFileTextRequest { type Params = lsp_types::TextDocumentIdentifier; type Result = String; - const METHOD: LspRequestMethod = LspRequestMethod::new("rust-analyzer/viewFileText"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("rust-analyzer/viewFileText"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -177,7 +177,7 @@ pub enum ViewCrateGraphRequest {} impl Request for ViewCrateGraphRequest { type Params = ViewCrateGraphParams; type Result = String; - const METHOD: LspRequestMethod = LspRequestMethod::new("rust-analyzer/viewCrateGraph"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("rust-analyzer/viewCrateGraph"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -192,7 +192,7 @@ pub enum ViewItemTreeRequest {} impl Request for ViewItemTreeRequest { type Params = ViewItemTreeParams; type Result = String; - const METHOD: LspRequestMethod = LspRequestMethod::new("rust-analyzer/viewItemTree"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("rust-analyzer/viewItemTree"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -236,7 +236,7 @@ pub enum DiscoverTestRequest {} impl Request for DiscoverTestRequest { type Params = DiscoverTestParams; type Result = DiscoverTestResults; - const METHOD: LspRequestMethod = LspRequestMethod::new("experimental/discoverTest"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("experimental/discoverTest"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -244,7 +244,7 @@ pub enum DiscoveredTestsNotification {} impl Notification for DiscoveredTestsNotification { type Params = DiscoverTestResults; - const METHOD: LspNotificationMethod = + const METHOD: LspNotificationMethod<'_> = LspNotificationMethod::new("experimental/discoveredTests"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -261,7 +261,7 @@ pub enum RunTestRequest {} impl Request for RunTestRequest { type Params = RunTestParams; type Result = (); - const METHOD: LspRequestMethod = LspRequestMethod::new("experimental/runTest"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("experimental/runTest"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -269,7 +269,7 @@ pub enum EndRunTestNotification {} impl Notification for EndRunTestNotification { type Params = (); - const METHOD: LspNotificationMethod = LspNotificationMethod::new("experimental/endRunTest"); + const METHOD: LspNotificationMethod<'_> = LspNotificationMethod::new("experimental/endRunTest"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -277,7 +277,7 @@ pub enum AppendOutputToRunTestNotification {} impl Notification for AppendOutputToRunTestNotification { type Params = String; - const METHOD: LspNotificationMethod = + const METHOD: LspNotificationMethod<'_> = LspNotificationMethod::new("experimental/appendOutputToRunTest"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -286,7 +286,8 @@ pub enum AbortRunTestNotification {} impl Notification for AbortRunTestNotification { type Params = (); - const METHOD: LspNotificationMethod = LspNotificationMethod::new("experimental/abortRunTest"); + const METHOD: LspNotificationMethod<'_> = + LspNotificationMethod::new("experimental/abortRunTest"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -311,7 +312,7 @@ pub enum ChangeTestStateNotification {} impl Notification for ChangeTestStateNotification { type Params = ChangeTestStateParams; - const METHOD: LspNotificationMethod = + const METHOD: LspNotificationMethod<'_> = LspNotificationMethod::new("experimental/changeTestState"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -321,7 +322,7 @@ pub enum ExpandMacroRequest {} impl Request for ExpandMacroRequest { type Params = ExpandMacroParams; type Result = Option; - const METHOD: LspRequestMethod = LspRequestMethod::new("rust-analyzer/expandMacro"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("rust-analyzer/expandMacro"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -344,7 +345,7 @@ pub enum ViewRecursiveMemoryLayoutRequest {} impl Request for ViewRecursiveMemoryLayoutRequest { type Params = lsp_types::TextDocumentPositionParams; type Result = Option; - const METHOD: LspRequestMethod = + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("rust-analyzer/viewRecursiveMemoryLayout"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -372,7 +373,7 @@ pub enum CancelFlycheckNotification {} impl Notification for CancelFlycheckNotification { type Params = (); - const METHOD: LspNotificationMethod = + const METHOD: LspNotificationMethod<'_> = LspNotificationMethod::new("rust-analyzer/cancelFlycheck"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -381,7 +382,8 @@ pub enum RunFlycheckNotification {} impl Notification for RunFlycheckNotification { type Params = RunFlycheckParams; - const METHOD: LspNotificationMethod = LspNotificationMethod::new("rust-analyzer/runFlycheck"); + const METHOD: LspNotificationMethod<'_> = + LspNotificationMethod::new("rust-analyzer/runFlycheck"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -389,7 +391,8 @@ pub enum ClearFlycheckNotification {} impl Notification for ClearFlycheckNotification { type Params = (); - const METHOD: LspNotificationMethod = LspNotificationMethod::new("rust-analyzer/clearFlycheck"); + const METHOD: LspNotificationMethod<'_> = + LspNotificationMethod::new("rust-analyzer/clearFlycheck"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -397,7 +400,7 @@ pub enum OpenServerLogsNotification {} impl Notification for OpenServerLogsNotification { type Params = (); - const METHOD: LspNotificationMethod = + const METHOD: LspNotificationMethod<'_> = LspNotificationMethod::new("rust-analyzer/openServerLogs"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -413,7 +416,7 @@ pub enum MatchingBraceRequest {} impl Request for MatchingBraceRequest { type Params = MatchingBraceParams; type Result = Vec; - const METHOD: LspRequestMethod = LspRequestMethod::new("experimental/matchingBrace"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("experimental/matchingBrace"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -429,7 +432,7 @@ pub enum ParentModuleRequest {} impl Request for ParentModuleRequest { type Params = lsp_types::TextDocumentPositionParams; type Result = Option; - const METHOD: LspRequestMethod = LspRequestMethod::new("experimental/parentModule"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("experimental/parentModule"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -438,7 +441,7 @@ pub enum ChildModulesRequest {} impl Request for ChildModulesRequest { type Params = lsp_types::TextDocumentPositionParams; type Result = Option; - const METHOD: LspRequestMethod = LspRequestMethod::new("experimental/childModules"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("experimental/childModules"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -447,7 +450,7 @@ pub enum JoinLinesRequest {} impl Request for JoinLinesRequest { type Params = JoinLinesParams; type Result = Vec; - const METHOD: LspRequestMethod = LspRequestMethod::new("experimental/joinLines"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("experimental/joinLines"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -463,7 +466,7 @@ pub enum OnEnterRequest {} impl Request for OnEnterRequest { type Params = lsp_types::TextDocumentPositionParams; type Result = Option>; - const METHOD: LspRequestMethod = LspRequestMethod::new("experimental/onEnter"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("experimental/onEnter"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -472,7 +475,7 @@ pub enum RunnablesRequest {} impl Request for RunnablesRequest { type Params = RunnablesParams; type Result = Vec; - const METHOD: LspRequestMethod = LspRequestMethod::new("experimental/runnables"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("experimental/runnables"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -531,7 +534,7 @@ pub enum RelatedTestsRequest {} impl Request for RelatedTestsRequest { type Params = lsp_types::TextDocumentPositionParams; type Result = Vec; - const METHOD: LspRequestMethod = LspRequestMethod::new("rust-analyzer/relatedTests"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("rust-analyzer/relatedTests"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -545,7 +548,7 @@ pub enum SsrRequest {} impl Request for SsrRequest { type Params = SsrParams; type Result = lsp_types::WorkspaceEdit; - const METHOD: LspRequestMethod = LspRequestMethod::new("experimental/ssr"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("experimental/ssr"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -568,7 +571,8 @@ pub enum ServerStatusNotification {} impl Notification for ServerStatusNotification { type Params = ServerStatusParams; - const METHOD: LspNotificationMethod = LspNotificationMethod::new("experimental/serverStatus"); + const METHOD: LspNotificationMethod<'_> = + LspNotificationMethod::new("experimental/serverStatus"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -603,7 +607,7 @@ pub enum CodeActionRequest {} impl Request for CodeActionRequest { type Params = lsp_types::CodeActionParams; type Result = Option>; - const METHOD: LspRequestMethod = LspRequestMethod::new("textDocument/codeAction"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::TextDocumentCodeAction; const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -612,7 +616,7 @@ pub enum CodeActionResolveRequest {} impl Request for CodeActionResolveRequest { type Params = CodeAction; type Result = CodeAction; - const METHOD: LspRequestMethod = LspRequestMethod::new("codeAction/resolve"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::CodeActionResolve; const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -690,7 +694,7 @@ pub enum HoverRequest {} impl Request for HoverRequest { type Params = HoverParams; type Result = Option; - const METHOD: LspRequestMethod = lsp_types::HoverRequest::METHOD; + const METHOD: LspRequestMethod<'_> = lsp_types::HoverRequest::METHOD; const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -740,7 +744,7 @@ pub enum ExternalDocsRequest {} impl Request for ExternalDocsRequest { type Params = lsp_types::TextDocumentPositionParams; type Result = ExternalDocsResponse; - const METHOD: LspRequestMethod = LspRequestMethod::new("experimental/externalDocs"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("experimental/externalDocs"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -769,7 +773,7 @@ pub enum OpenCargoTomlRequest {} impl Request for OpenCargoTomlRequest { type Params = OpenCargoTomlParams; type Result = Option; - const METHOD: LspRequestMethod = LspRequestMethod::new("experimental/openCargoToml"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("experimental/openCargoToml"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -799,7 +803,7 @@ pub enum MoveItemRequest {} impl Request for MoveItemRequest { type Params = MoveItemParams; type Result = Vec; - const METHOD: LspRequestMethod = LspRequestMethod::new("experimental/moveItem"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("experimental/moveItem"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -823,7 +827,7 @@ pub enum WorkspaceSymbolRequest {} impl Request for WorkspaceSymbolRequest { type Params = WorkspaceSymbolParams; type Result = Option; - const METHOD: LspRequestMethod = LspRequestMethod::new("workspace/symbol"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::WorkspaceSymbol; const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -868,7 +872,7 @@ pub enum DocumentOnTypeFormattingRequest {} impl Request for DocumentOnTypeFormattingRequest { type Params = DocumentOnTypeFormattingParams; type Result = Option>; - const METHOD: LspRequestMethod = LspRequestMethod::new("textDocument/onTypeFormatting"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::TextDocumentOnTypeFormatting; const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -938,7 +942,7 @@ pub enum PredicateEvaluationStatus { impl Request for EvaluatePredicateRequest { type Params = EvaluatePredicateParams; type Result = EvaluatePredicateResult; - const METHOD: LspRequestMethod = LspRequestMethod::new("rust-analyzer/evaluatePredicate"); + const METHOD: LspRequestMethod<'_> = LspRequestMethod::new("rust-analyzer/evaluatePredicate"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } @@ -954,7 +958,8 @@ pub struct GetFailedObligationsParams { impl Request for GetFailedObligationsRequest { type Params = GetFailedObligationsParams; type Result = String; - const METHOD: LspRequestMethod = LspRequestMethod::new("rust-analyzer/getFailedObligations"); + const METHOD: LspRequestMethod<'_> = + LspRequestMethod::new("rust-analyzer/getFailedObligations"); const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/semantic_tokens.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/semantic_tokens.rs index 78198064238ca..fcfe3fb27c29d 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/semantic_tokens.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/semantic_tokens.rs @@ -344,10 +344,11 @@ pub(crate) fn diff_tokens( // The lsp data field is actually a byte-diff but we // travel in tokens so `start` and `delete_count` are in multiples of the // serialized size of `SemanticToken`. + let data = new.iter().copied().flat_map(<[u32; 5]>::from).collect(); vec![SemanticTokensEdit { start: 5 * offset as u32, delete_count: 5 * old.len() as u32, - data: Some(new.into()), + data: Some(data), }] } } @@ -378,11 +379,7 @@ mod tests { let edits = diff_tokens(&before, &after); assert_eq!( edits[0], - SemanticTokensEdit { - start: 10, - delete_count: 0, - data: Some(vec![from((11, 12, 13, 14, 15))]) - } + SemanticTokensEdit { start: 10, delete_count: 0, data: Some(vec![11, 12, 13, 14, 15]) } ); } @@ -394,11 +391,7 @@ mod tests { let edits = diff_tokens(&before, &after); assert_eq!( edits[0], - SemanticTokensEdit { - start: 0, - delete_count: 0, - data: Some(vec![from((11, 12, 13, 14, 15))]) - } + SemanticTokensEdit { start: 0, delete_count: 0, data: Some(vec![11, 12, 13, 14, 15]) } ); } @@ -418,7 +411,7 @@ mod tests { SemanticTokensEdit { start: 5, delete_count: 0, - data: Some(vec![from((10, 20, 30, 40, 50)), from((60, 70, 80, 90, 100))]) + data: Some(vec![10, 20, 30, 40, 50, 60, 70, 80, 90, 100]) } ); } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs index ebec0f990a178..00e94fb50c856 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs @@ -48,6 +48,7 @@ impl GlobalState { message, actions: Some(vec![lsp_types::MessageActionItem { title: "Open server logs".to_owned(), + properties: Default::default(), }]), }, |this, resp| { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs index fef0d097314c0..b4727360e5375 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs @@ -397,16 +397,19 @@ impl GlobalState { if cancelled { self.prime_caches_queue .request_op("restart after cancellation".to_owned(), ()); - } else if self.config.check_on_save(None) - && self.config.flycheck_workspace(None) - && !self.fetch_build_data_queue.op_requested() - { - // Priming finished; now run the deferred initial workspace flycheck - // (kept off the critical path so `cargo check` doesn't contend with - // cache priming for CPU). - self.flycheck - .iter() - .for_each(|flycheck| flycheck.restart_workspace(None)); + } else { + if self.config.check_on_save(None) + && self.config.flycheck_workspace(None) + && !self.fetch_build_data_queue.op_requested() + { + // Priming finished; now run the deferred initial workspace flycheck + // (kept off the critical path so `cargo check` doesn't contend with + // cache priming for CPU). + self.flycheck + .iter() + .for_each(|flycheck| flycheck.restart_workspace(None)); + } + tracing::info!("cache priming completed successfully"); } if let Some((message, fraction, title)) = last_report.take() { self.report_progress( diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs index ace44b02fe39c..c72f6782052f0 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -659,11 +659,16 @@ impl GlobalState { Config::user_config_dir_path().as_deref(), ); - if (self.proc_macro_clients.len() < self.workspaces.len() || !same_workspaces) - && self.config.expand_proc_macros() - { + if !same_workspaces && self.config.expand_proc_macros() { info!("Spawning proc-macro servers"); + // Workspaces referring to the same proc-macro server executable (i.e. the same + // sysroot) with an identical spawn environment share a single client, and thereby + // a single set of server processes. + let mut clients: Vec<( + (AbsPathBuf, Option, FxHashMap>), + ProcMacroClient, + )> = Vec::new(); self.proc_macro_clients = Arc::from_iter(self.workspaces.iter().map(|ws| { let path = match self.config.proc_macro_srv() { Some(path) => path, @@ -695,20 +700,30 @@ impl GlobalState { _ => Default::default(), }; - info!("Using proc-macro server at {path}"); + + let key = (path, ws.toolchain.clone(), env); + if let Some((_, client)) = clients.iter().find(|(k, _)| *k == key) { + return Some(Ok(client.clone())); + } + + let (path, toolchain, env) = &key; + info!("Spawning proc-macro server at {path}"); let num_process = self.config.proc_macro_num_processes(); - Some( - ProcMacroClient::spawn(&path, &env, ws.toolchain.as_ref(), num_process) - .map_err(|err| { - tracing::error!( - "Failed to run proc-macro server from path {path}, error: {err:?}", - ); - anyhow::format_err!( - "Failed to run proc-macro server from path {path}, error: {err:?}", - ) - }), - ) + Some(match ProcMacroClient::spawn(path, env, toolchain.as_ref(), num_process) { + Ok(client) => { + clients.push((key.clone(), client.clone())); + Ok(client) + } + Err(err) => { + tracing::error!( + "Failed to run proc-macro server from path {path}, error: {err:?}", + ); + Err(anyhow::format_err!( + "Failed to run proc-macro server from path {path}, error: {err:?}", + )) + } + }) })) } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/flycheck.rs index c6f1f81139d28..7700643f03e75 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/flycheck.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/flycheck.rs @@ -2,6 +2,13 @@ use test_utils::skip_slow_tests; use crate::support::Project; +fn message_contains(message: &lsp_types::Message, p: &str) -> bool { + match message { + lsp_types::Message::String(s) => s.contains(p), + lsp_types::Message::MarkupContent(mc) => mc.value.contains(p), + } +} + #[test] fn test_flycheck_diagnostics_for_unused_variable() { if skip_slow_tests() { @@ -29,7 +36,7 @@ fn main() { let diagnostics = server.wait_for_diagnostics(); assert!( - diagnostics.diagnostics.iter().any(|d| d.message.contains("unused variable")), + diagnostics.diagnostics.iter().any(|d| message_contains(&d.message, "unused variable")), "expected unused variable diagnostic, got: {:?}", diagnostics.diagnostics, ); @@ -63,7 +70,7 @@ fn main() { // Wait for the unused variable diagnostic to appear. let diagnostics = server.wait_for_diagnostics(); assert!( - diagnostics.diagnostics.iter().any(|d| d.message.contains("unused variable")), + diagnostics.diagnostics.iter().any(|d| message_contains(&d.message, "unused variable")), "expected unused variable diagnostic, got: {:?}", diagnostics.diagnostics, ); @@ -105,7 +112,7 @@ fn main() {} let diagnostics = server.wait_for_diagnostics(); assert!( - diagnostics.diagnostics.iter().any(|d| d.message.contains("unused variable")), + diagnostics.diagnostics.iter().any(|d| message_contains(&d.message, "unused variable")), "expected unused variable diagnostic, got: {:?}", diagnostics.diagnostics, ); @@ -143,7 +150,7 @@ fn main() {} let diags = server.wait_for_diagnostics(); assert!( - diags.diagnostics.iter().any(|d| d.message.contains("unused variable")), + diags.diagnostics.iter().any(|d| message_contains(&d.message, "unused variable")), "expected unused variable diagnostic, got: {:?}", diags.diagnostics, ); diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index 95ff3aebd8db5..b0e59ff159539 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -187,6 +187,9 @@ pub fn ty_tuple(types: impl IntoIterator) -> ast::Type { ty_from_text(&format!("({contents})")) } +pub fn ty_paren(ty: ast::Type) -> ast::Type { + ty_from_text(&format!("({ty})")) +} pub fn ty_ref(target: ast::Type, exclusive: bool) -> ast::Type { ty_from_text(&if exclusive { format!("&mut {target}") } else { format!("&{target}") }) } @@ -657,12 +660,12 @@ pub fn expr_if( else_branch: Option, ) -> ast::IfExpr { let else_branch = match else_branch { - Some(ast::ElseBranch::Block(block)) => format!("else {block}"), - Some(ast::ElseBranch::IfExpr(if_expr)) => format!("else {if_expr}"), + Some(ast::ElseBranch::Block(block)) => format!(" else {block}"), + Some(ast::ElseBranch::IfExpr(if_expr)) => format!(" else {if_expr}"), None => String::new(), }; let ws = block_whitespace(&condition); - expr_from_text(&format!("if {condition}{ws}{then_branch} {else_branch}")) + expr_from_text(&format!("if {condition}{ws}{then_branch}{else_branch}")) } pub fn expr_for_loop(pat: ast::Pat, expr: ast::Expr, block: ast::BlockExpr) -> ast::ForExpr { let ws = block_whitespace(&expr); @@ -728,16 +731,9 @@ pub fn expr_tuple(elements: impl IntoIterator) -> ast::TupleEx pub fn expr_assignment(lhs: ast::Expr, rhs: ast::Expr) -> ast::BinExpr { expr_from_text(&format!("{lhs} = {rhs}")) } -fn expr_from_text + AstNode>(text: &str) -> E { - ast_from_text(&format!("const C: () = {text};")) -} fn block_whitespace(after: &impl AstNode) -> &'static str { if after.syntax().text().contains_char('\n') { "\n" } else { " " } } -pub fn expr_let(pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr { - ast_from_text(&format!("const _: () = while let {pattern} = {expr} {{}};")) -} - pub fn arg_list(args: impl IntoIterator) -> ast::ArgList { let args = args.into_iter().format(", "); ast_from_text(&format!("fn main() {{ ()({args}) }}")) @@ -1349,6 +1345,30 @@ pub fn token_tree( ast_from_text(&format!("tt!{l_delimiter}{tt}{r_delimiter}")) } +pub fn expr_let(pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr { + expr_from_text(&format!("while let {pattern} = {expr} {{}}")) +} + +#[track_caller] +fn expr_from_text + AstNode>(text: &str) -> E { + expr_from_text_with_edition(text, Edition::CURRENT) +} + +#[track_caller] +fn expr_from_text_with_edition + AstNode>(text: &str, edition: Edition) -> E { + let parse = ast::Expr::parse(text, edition); + let node = match parse.tree().syntax().descendants().find_map(E::cast) { + Some(it) => it, + None => { + let node = std::any::type_name::(); + panic!("Failed to make ast node `{node}` from text {text}") + } + }; + let node = node.clone_subtree(); + assert_eq!(node.syntax().text_range().start(), 0.into()); + node +} + #[track_caller] fn ast_from_text(text: &str) -> N { ast_from_text_with_edition(text, Edition::CURRENT) @@ -1373,7 +1393,6 @@ pub fn token(kind: SyntaxKind) -> SyntaxToken { tokens::SOURCE_FILE .tree() .syntax() - .clone_for_update() .descendants_with_tokens() .filter_map(|it| it.into_token()) .find(|it| it.kind() == kind) @@ -1394,43 +1413,10 @@ pub mod tokens { ) }); - pub fn semicolon() -> SyntaxToken { - SOURCE_FILE - .tree() - .syntax() - .clone_for_update() - .descendants_with_tokens() - .filter_map(|it| it.into_token()) - .find(|it| it.kind() == SEMICOLON) - .unwrap() - } - - pub fn single_space() -> SyntaxToken { - SOURCE_FILE - .tree() - .syntax() - .clone_for_update() - .descendants_with_tokens() - .filter_map(|it| it.into_token()) - .find(|it| it.kind() == WHITESPACE && it.text() == " ") - .unwrap() - } - - pub fn crate_kw() -> SyntaxToken { - SOURCE_FILE - .tree() - .syntax() - .clone_for_update() - .descendants_with_tokens() - .filter_map(|it| it.into_token()) - .find(|it| it.kind() == CRATE_KW) - .unwrap() - } - pub fn whitespace(text: &str) -> SyntaxToken { assert!(text.trim().is_empty()); let sf = SourceFile::parse(text, Edition::CURRENT).ok().unwrap(); - sf.syntax().clone_for_update().first_child_or_token().unwrap().into_token().unwrap() + sf.syntax().first_child_or_token().unwrap().into_token().unwrap() } pub fn doc_comment(text: &str) -> SyntaxToken { @@ -1454,41 +1440,6 @@ pub mod tokens { .find(|it| it.kind() == IDENT) .unwrap() } - - pub fn single_newline() -> SyntaxToken { - let res = SOURCE_FILE - .tree() - .syntax() - .clone_for_update() - .descendants_with_tokens() - .filter_map(|it| it.into_token()) - .find(|it| it.kind() == WHITESPACE && it.text() == "\n") - .unwrap(); - res.detach(); - res - } - - pub fn blank_line() -> SyntaxToken { - SOURCE_FILE - .tree() - .syntax() - .clone_for_update() - .descendants_with_tokens() - .filter_map(|it| it.into_token()) - .find(|it| it.kind() == WHITESPACE && it.text() == "\n\n") - .unwrap() - } - - pub struct WsBuilder(SourceFile); - - impl WsBuilder { - pub fn new(text: &str) -> WsBuilder { - WsBuilder(SourceFile::parse(text, Edition::CURRENT).ok().unwrap()) - } - pub fn ws(&self) -> SyntaxToken { - self.0.syntax().first_child_or_token().unwrap().into_token().unwrap() - } - } } #[cfg(test)] @@ -1539,6 +1490,16 @@ mod tests { ); } + #[test] + fn expr_if_without_else_has_no_trailing_whitespace() { + let if_expr = expr_if(ext::expr_underscore(), block_expr(None, None), None); + assert_eq!(if_expr.syntax().to_string(), "if _ {\n}"); + + let stmt = expr_stmt(if_expr.into()); + let block = block_expr([stmt.into()], None); + assert_eq!(block.syntax().to_string(), "{\n if _ {\n}\n}"); + } + #[test] fn test_untyped_param() { check( diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs index 2a50d233c3bfb..f473df9b1548f 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs @@ -575,3 +575,15 @@ impl Expr { } } } + +impl ast::Type { + pub fn needs_parens_in(&self, parent: &SyntaxNode) -> bool { + if !matches!(self, ast::Type::DynTraitType(_) | ast::Type::ImplTraitType(_)) { + return false; + } + let kind = parent.kind(); + ast::CastExpr::can_cast(kind) + || ast::RefType::can_cast(kind) + || ast::PtrType::can_cast(kind) + } +} diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index 7f9cd1fce94eb..22c8c842d890c 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -610,6 +610,18 @@ impl SyntaxFactory { ast } + pub fn ty_paren(&self, ty: ast::Type) -> ast::Type { + let ast::Type::ParenType(paren_ty) = make::ty_paren(ty.clone()) else { unreachable!() }; + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(paren_ty.syntax().clone()); + builder.map_node(ty.syntax().clone(), paren_ty.ty().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + paren_ty.into() + } + pub fn path_segment_generics( &self, name_ref: ast::NameRef, diff --git a/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs b/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs index 9b5cd0135e83a..3c5640f08a524 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs @@ -42,7 +42,7 @@ impl CheckReparse { let delete = TextRange::at(delete_start.try_into().unwrap(), delete_len.try_into().unwrap()); let edited_text = - format!("{}{}{}", &text[..delete_start], &insert, &text[delete_start + delete_len..]); + format!("{}{}{}", &text[..delete_start], insert, &text[delete_start + delete_len..]); Some(CheckReparse { text, insert, delete, edited_text }) } diff --git a/src/tools/rust-analyzer/crates/syntax/src/lib.rs b/src/tools/rust-analyzer/crates/syntax/src/lib.rs index 924e72ee40397..614678536a512 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/lib.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/lib.rs @@ -270,11 +270,14 @@ macro_rules! match_ast { (match $node:ident { $($tt:tt)* }) => { $crate::match_ast!(match ($node) { $($tt)* }) }; (match ($node:expr) { - $( $( $path:ident )::+ ($it:pat) => $res:expr, )* + $( $( $path:ident )::+ ($it:pat) $(if $guard:expr)? => $res:expr, )* _ => $catch_all:expr $(,)? }) => {{ - $( if let Some($it) = $($path::)+cast($node.clone()) { $res } else )* - { $catch_all } + #[allow(clippy::question_mark, reason = "if `$catch_all` is `return None` Clippy can mark this")] + { + $( if let Some($it) = $($path::)+cast($node.clone()) $(&& $guard)? { $res } else )* + { $catch_all } + } }}; } diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs index f346535ca19c0..63e76d049b72e 100644 --- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs +++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs @@ -17,7 +17,6 @@ use cfg::CfgOptions; use hir_expand::{ EditionedFileId, FileRange, change::ChangeWithProcMacros, - db::ExpandDatabase, files::FilePosition, proc_macro::{ ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind, ProcMacrosBuilder, @@ -139,7 +138,7 @@ pub const WORKSPACE: base_db::SourceRootId = base_db::SourceRootId(0); /// /// Available proc macros: `identity` (attr), `DeriveIdentity` (derive), `input_replace` (attr), /// `mirror` (bang), `shorten` (bang) -pub trait WithFixture: Default + ExpandDatabase + SourceDatabase + 'static { +pub trait WithFixture: Default + SourceDatabase + 'static { /// See the trait documentation for more information on fixtures. #[track_caller] fn with_single_file( @@ -231,7 +230,7 @@ pub trait WithFixture: Default + ExpandDatabase + SourceDatabase + 'static { } } -impl WithFixture for DB {} +impl WithFixture for DB {} pub struct ChangeFixture { pub file_position: Option<(span::EditionedFileId, RangeOrOffset)>, @@ -847,7 +846,7 @@ struct IdentityProcMacroExpander; impl ProcMacroExpander for IdentityProcMacroExpander { fn expand( &self, - _: &dyn ExpandDatabase, + _: &dyn SourceDatabase, subtree: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -870,7 +869,7 @@ struct Issue18089ProcMacroExpander; impl ProcMacroExpander for Issue18089ProcMacroExpander { fn expand( &self, - _: &dyn ExpandDatabase, + _: &dyn SourceDatabase, subtree: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -906,7 +905,7 @@ struct AttributeInputReplaceProcMacroExpander; impl ProcMacroExpander for AttributeInputReplaceProcMacroExpander { fn expand( &self, - _: &dyn ExpandDatabase, + _: &dyn SourceDatabase, _: &TopSubtree, attrs: Option<&TopSubtree>, _: &Env, @@ -930,7 +929,7 @@ struct Issue18840ProcMacroExpander; impl ProcMacroExpander for Issue18840ProcMacroExpander { fn expand( &self, - _: &dyn ExpandDatabase, + _: &dyn SourceDatabase, fn_: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -967,7 +966,7 @@ struct MirrorProcMacroExpander; impl ProcMacroExpander for MirrorProcMacroExpander { fn expand( &self, - _: &dyn ExpandDatabase, + _: &dyn SourceDatabase, input: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -1006,7 +1005,7 @@ struct ShortenProcMacroExpander; impl ProcMacroExpander for ShortenProcMacroExpander { fn expand( &self, - _: &dyn ExpandDatabase, + _: &dyn SourceDatabase, input: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -1051,7 +1050,7 @@ struct Issue17479ProcMacroExpander; impl ProcMacroExpander for Issue17479ProcMacroExpander { fn expand( &self, - _: &dyn ExpandDatabase, + _: &dyn SourceDatabase, subtree: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -1082,7 +1081,7 @@ struct Issue18898ProcMacroExpander; impl ProcMacroExpander for Issue18898ProcMacroExpander { fn expand( &self, - _: &dyn ExpandDatabase, + _: &dyn SourceDatabase, subtree: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -1136,7 +1135,7 @@ struct DisallowCfgProcMacroExpander; impl ProcMacroExpander for DisallowCfgProcMacroExpander { fn expand( &self, - _: &dyn ExpandDatabase, + _: &dyn SourceDatabase, subtree: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -1168,7 +1167,7 @@ struct GenerateSuffixedTypeProcMacroExpander; impl ProcMacroExpander for GenerateSuffixedTypeProcMacroExpander { fn expand( &self, - _: &dyn ExpandDatabase, + _: &dyn SourceDatabase, subtree: &TopSubtree, _attrs: Option<&TopSubtree>, _env: &Env, diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md index 1f94639074f81..9d865a7936a95 100644 --- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md +++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md @@ -1368,7 +1368,7 @@ This config takes a map of crate names with the exported proc-macro names to ign ## rust-analyzer.procMacro.processes {#procMacro.processes} -Default: `1` +Default: `2` Number of proc-macro server processes to spawn. diff --git a/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md b/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md index 6902bce83e6cd..da4a5aaa686c5 100644 --- a/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md +++ b/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md @@ -1,5 +1,5 @@ $DIR/method_call.rs:21:30 + | +LL | let _ = Clone::clone(&f); + | ^^ the trait `Clone` is not implemented for `ForeignType` + +error[E0599]: no method named `clone` found for struct `ForeignType` in the current scope + --> $DIR/method_call.rs:24:19 + | +LL | let _ = f.clone(); + | ^^^^^ method not found in `ForeignType` + +error[E0277]: the trait bound `LocalType: Clone` is not satisfied + --> $DIR/method_call.rs:31:30 + | +LL | let _ = Clone::clone(&l); + | ^^ the trait `Clone` is not implemented for `LocalType` + | +help: consider annotating `LocalType` with `#[derive(Clone)]` + | +LL + #[derive(Clone)] +LL | pub struct LocalType(pub T); + | + +error[E0599]: no method named `clone` found for struct `LocalType` in the current scope + --> $DIR/method_call.rs:34:19 + | +LL | pub struct LocalType(pub T); + | ----------------------- method `clone` not found for this struct +... +LL | let _ = l.clone(); + | ^^^^^ method not found in `LocalType` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `clone`, perhaps you need to implement it: + candidate #1: `Clone` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0277, E0599. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/method_call.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/method_call.next.stderr new file mode 100644 index 0000000000000..1bd7267b6ee99 --- /dev/null +++ b/tests/ui/diagnostic_namespace/do_not_recommend/method_call.next.stderr @@ -0,0 +1,45 @@ +error[E0277]: the trait bound `ForeignType: Clone` is not satisfied + --> $DIR/method_call.rs:21:30 + | +LL | let _ = Clone::clone(&f); + | ------------ ^^ the trait `Clone` is not implemented for `ForeignType` + | | + | required by a bound introduced by this call + +error[E0599]: no method named `clone` found for struct `ForeignType` in the current scope + --> $DIR/method_call.rs:24:19 + | +LL | let _ = f.clone(); + | ^^^^^ method not found in `ForeignType` + +error[E0277]: the trait bound `LocalType: Clone` is not satisfied + --> $DIR/method_call.rs:31:30 + | +LL | let _ = Clone::clone(&l); + | ------------ ^^ the trait `Clone` is not implemented for `LocalType` + | | + | required by a bound introduced by this call + | +help: consider annotating `LocalType` with `#[derive(Clone)]` + | +LL + #[derive(Clone)] +LL | pub struct LocalType(pub T); + | + +error[E0599]: no method named `clone` found for struct `LocalType` in the current scope + --> $DIR/method_call.rs:34:19 + | +LL | pub struct LocalType(pub T); + | ----------------------- method `clone` not found for this struct +... +LL | let _ = l.clone(); + | ^^^^^ method not found in `LocalType` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `clone`, perhaps you need to implement it: + candidate #1: `Clone` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0277, E0599. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/method_call.rs b/tests/ui/diagnostic_namespace/do_not_recommend/method_call.rs new file mode 100644 index 0000000000000..5f59984a6ddd9 --- /dev/null +++ b/tests/ui/diagnostic_namespace/do_not_recommend/method_call.rs @@ -0,0 +1,38 @@ +//@aux-build:foreign_blanket_impl.rs +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@forbid-output: DoNotMentionThis +extern crate foreign_blanket_impl; +use foreign_blanket_impl::{DoNotMentionThis, ForeignType}; + +pub struct LocalType(pub T); + +#[diagnostic::do_not_recommend] +impl Clone for LocalType { + fn clone(&self) -> Self { + todo!() + } +} + +fn main() { + { + let f = ForeignType(42_u8); + let _ = Clone::clone(&f); + //~^ERROR the trait bound `ForeignType: Clone` is not satisfied [E0277] + + let _ = f.clone(); + //~^ERROR no method named `clone` found for struct `ForeignType` in the current scope [E0599] + + } + + { + let l = LocalType(42_u8); + let _ = Clone::clone(&l); + //~^ERROR the trait bound `LocalType: Clone` is not satisfied [E0277] + + let _ = l.clone(); + //~^ERROR no method named `clone` found for struct `LocalType` in the current scope [E0599] + + } +} diff --git a/tests/ui/imports/private-import-suggestion-path-156244.edition_2015.stderr b/tests/ui/imports/private-import-suggestion-path-156244.edition_2015.stderr index 95b1760e6a239..2a8795b6ab93c 100644 --- a/tests/ui/imports/private-import-suggestion-path-156244.edition_2015.stderr +++ b/tests/ui/imports/private-import-suggestion-path-156244.edition_2015.stderr @@ -76,6 +76,44 @@ LL - use crate::rename::inner::Item as Item1; LL + use outer::actual::Item as Item1; | -error: aborting due to 4 previous errors +error[E0603]: struct import `Hi` is private + --> $DIR/private-import-suggestion-path-156244.rs:55:37 + | +LL | use inaccessible_ancestor::testing::Hi; + | ^^ private struct import + | +note: the struct import `Hi` is defined here... + --> $DIR/private-import-suggestion-path-156244.rs:51:13 + | +LL | use super::private::public::Hi; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...and refers to the struct `Hi` which is defined here + --> $DIR/private-import-suggestion-path-156244.rs:46:13 + | +LL | pub struct Hi; + | ^^^^^^^^^^^^^^ you could import this directly + +error[E0603]: module import `mem` is private + --> $DIR/private-import-suggestion-path-156244.rs:65:21 + | +LL | use external_alias::mem; + | ^^^ private module import + | +note: the module import `mem` is defined here... + --> $DIR/private-import-suggestion-path-156244.rs:62:9 + | +LL | use super::s::mem; + | ^^^^^^^^^^^^^ +note: ...and refers to the module `mem` which is defined here + --> $SRC_DIR/std/src/lib.rs:LL:COL + | + = note: you could import this directly +help: import `mem` directly + | +LL - use external_alias::mem; +LL + use core::mem; + | + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/imports/private-import-suggestion-path-156244.edition_2018.stderr b/tests/ui/imports/private-import-suggestion-path-156244.edition_2018.stderr index e153b0cdc95aa..9f112fe4e7551 100644 --- a/tests/ui/imports/private-import-suggestion-path-156244.edition_2018.stderr +++ b/tests/ui/imports/private-import-suggestion-path-156244.edition_2018.stderr @@ -76,6 +76,44 @@ LL - use crate::rename::inner::Item as Item1; LL + use crate::outer::actual::Item as Item1; | -error: aborting due to 4 previous errors +error[E0603]: struct import `Hi` is private + --> $DIR/private-import-suggestion-path-156244.rs:55:37 + | +LL | use inaccessible_ancestor::testing::Hi; + | ^^ private struct import + | +note: the struct import `Hi` is defined here... + --> $DIR/private-import-suggestion-path-156244.rs:51:13 + | +LL | use super::private::public::Hi; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...and refers to the struct `Hi` which is defined here + --> $DIR/private-import-suggestion-path-156244.rs:46:13 + | +LL | pub struct Hi; + | ^^^^^^^^^^^^^^ you could import this directly + +error[E0603]: module import `mem` is private + --> $DIR/private-import-suggestion-path-156244.rs:65:21 + | +LL | use external_alias::mem; + | ^^^ private module import + | +note: the module import `mem` is defined here... + --> $DIR/private-import-suggestion-path-156244.rs:62:9 + | +LL | use super::s::mem; + | ^^^^^^^^^^^^^ +note: ...and refers to the module `mem` which is defined here + --> $SRC_DIR/std/src/lib.rs:LL:COL + | + = note: you could import this directly +help: import `mem` directly + | +LL - use external_alias::mem; +LL + use core::mem; + | + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/imports/private-import-suggestion-path-156244.rs b/tests/ui/imports/private-import-suggestion-path-156244.rs index 3f9d247097f7d..71e01470060bf 100644 --- a/tests/ui/imports/private-import-suggestion-path-156244.rs +++ b/tests/ui/imports/private-import-suggestion-path-156244.rs @@ -39,4 +39,30 @@ mod bad { //~^ ERROR module import `inner` is private [E0603] } +// Regression test for https://github.com/rust-lang/rust/issues/157455: no private ancestors. +mod inaccessible_ancestor { + mod private { + pub mod public { + pub struct Hi; + } + } + + pub mod testing { + use super::private::public::Hi; + } +} + +use inaccessible_ancestor::testing::Hi; +//~^ ERROR struct import `Hi` is private [E0603] + +// Regression test for https://github.com/rust-lang/rust/issues/157455: no external alias rewrite. +use std as s; + +mod external_alias { + use super::s::mem; +} + +use external_alias::mem; +//~^ ERROR module import `mem` is private [E0603] + fn main() {} diff --git a/tests/ui/imports/private-import-suggestion-relative.fixed b/tests/ui/imports/private-import-suggestion-relative.fixed new file mode 100644 index 0000000000000..52579f0a08eb7 --- /dev/null +++ b/tests/ui/imports/private-import-suggestion-relative.fixed @@ -0,0 +1,17 @@ +//@ run-rustfix + +#![allow(unused)] + +// Regression test for https://github.com/rust-lang/rust/issues/157455. +mod public { + pub struct Hi; +} + +mod testing { + use super::public::Hi; +} + +use public::Hi; +//~^ ERROR struct import `Hi` is private [E0603] + +fn main() {} diff --git a/tests/ui/imports/private-import-suggestion-relative.rs b/tests/ui/imports/private-import-suggestion-relative.rs new file mode 100644 index 0000000000000..9a012e8252879 --- /dev/null +++ b/tests/ui/imports/private-import-suggestion-relative.rs @@ -0,0 +1,17 @@ +//@ run-rustfix + +#![allow(unused)] + +// Regression test for https://github.com/rust-lang/rust/issues/157455. +mod public { + pub struct Hi; +} + +mod testing { + use super::public::Hi; +} + +use testing::Hi; +//~^ ERROR struct import `Hi` is private [E0603] + +fn main() {} diff --git a/tests/ui/imports/private-import-suggestion-relative.stderr b/tests/ui/imports/private-import-suggestion-relative.stderr new file mode 100644 index 0000000000000..033351e27c3c5 --- /dev/null +++ b/tests/ui/imports/private-import-suggestion-relative.stderr @@ -0,0 +1,25 @@ +error[E0603]: struct import `Hi` is private + --> $DIR/private-import-suggestion-relative.rs:14:14 + | +LL | use testing::Hi; + | ^^ private struct import + | +note: the struct import `Hi` is defined here... + --> $DIR/private-import-suggestion-relative.rs:11:9 + | +LL | use super::public::Hi; + | ^^^^^^^^^^^^^^^^^ +note: ...and refers to the struct `Hi` which is defined here + --> $DIR/private-import-suggestion-relative.rs:7:5 + | +LL | pub struct Hi; + | ^^^^^^^^^^^^^^ you could import this directly +help: import `Hi` directly + | +LL - use testing::Hi; +LL + use public::Hi; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs index 371f19d487268..fcf0dcf478444 100644 --- a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs +++ b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs @@ -14,6 +14,13 @@ fn bar() -> String { String::new() } +fn baz() -> String { + #[cfg(false)] + [1, 2, 3].iter().map(|c| c.to_string()).collect::() //~ ERROR expected `;`, found `#` + #[allow(unused)] + String::new() +} + fn main() { println!("{}", foo()); } diff --git a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr index 3a97a14b3c301..c8f3d50edd103 100644 --- a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr +++ b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr @@ -44,11 +44,30 @@ help: alternatively, consider surrounding the expression with a block LL | { [1, 2, 3].iter().map(|c| c.to_string()).collect::() } | + + +error: expected `;`, found `#` + --> $DIR/multiple-tail-expr-behind-cfg.rs:19:64 + | +LL | #[cfg(false)] + | ------------- only `;` terminated statements or tail expressions are allowed after this attribute +LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::() + | ^ expected `;` here +LL | #[allow(unused)] + | - unexpected token + | +help: add `;` here + | +LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::(); + | + +help: alternatively, consider surrounding the expression with a block + | +LL | { [1, 2, 3].iter().map(|c| c.to_string()).collect::() } + | + + + error: cannot find attribute `attr` in this scope --> $DIR/multiple-tail-expr-behind-cfg.rs:13:7 | LL | #[attr] | ^^^^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors