@@ -715,12 +715,17 @@ impl Span {
715
715
( !ctxt. is_root ( ) ) . then ( || ctxt. outer_expn_data ( ) . call_site )
716
716
}
717
717
718
- /// Walk down the expansion ancestors to find a span that's contained within `outer`.
718
+ /// Find the first ancestor span that's contained within `outer`.
719
719
///
720
- /// The span returned by this method may have a different [`SyntaxContext`] as `outer`.
720
+ /// This method traverses the macro expansion ancestors until it finds the first span
721
+ /// that's contained within `outer`.
722
+ ///
723
+ /// The span returned by this method may have a different [`SyntaxContext`] than `outer`.
721
724
/// If you need to extend the span, use [`find_ancestor_inside_same_ctxt`] instead,
722
725
/// because joining spans with different syntax contexts can create unexpected results.
723
726
///
727
+ /// This is used to find the span of the macro call when a parent expr span, i.e. `outer`, is known.
728
+ ///
724
729
/// [`find_ancestor_inside_same_ctxt`]: Self::find_ancestor_inside_same_ctxt
725
730
pub fn find_ancestor_inside ( mut self , outer : Span ) -> Option < Span > {
726
731
while !outer. contains ( self ) {
@@ -729,8 +734,10 @@ impl Span {
729
734
Some ( self )
730
735
}
731
736
732
- /// Walk down the expansion ancestors to find a span with the same [`SyntaxContext`] as
733
- /// `other`.
737
+ /// Find the first ancestor span with the same [`SyntaxContext`] as `other`.
738
+ ///
739
+ /// This method traverses the macro expansion ancestors until it finds a span
740
+ /// that has the same [`SyntaxContext`] as `other`.
734
741
///
735
742
/// Like [`find_ancestor_inside_same_ctxt`], but specifically for when spans might not
736
743
/// overlap. Take care when using this, and prefer [`find_ancestor_inside`] or
@@ -746,9 +753,12 @@ impl Span {
746
753
Some ( self )
747
754
}
748
755
749
- /// Walk down the expansion ancestors to find a span that's contained within `outer` and
756
+ /// Find the first ancestor span that's contained within `outer` and
750
757
/// has the same [`SyntaxContext`] as `outer`.
751
758
///
759
+ /// This method traverses the macro expansion ancestors until it finds a span
760
+ /// that is both contained within `outer` and has the same [`SyntaxContext`] as `outer`.
761
+ ///
752
762
/// This method is the combination of [`find_ancestor_inside`] and
753
763
/// [`find_ancestor_in_same_ctxt`] and should be preferred when extending the returned span.
754
764
/// If you do not need to modify the span, use [`find_ancestor_inside`] instead.
@@ -762,43 +772,43 @@ impl Span {
762
772
Some ( self )
763
773
}
764
774
765
- /// Recursively walk down the expansion ancestors to find the oldest ancestor span with the same
766
- /// [`SyntaxContext`] the initial span.
775
+ /// Find the first ancestor span that does not come from an external macro.
767
776
///
768
- /// This method is suitable for peeling through *local* macro expansions to find the "innermost"
769
- /// span that is still local and shares the same [`SyntaxContext`]. For example, given
777
+ /// This method traverses the macro expansion ancestors until it finds a span
778
+ /// that is either from user-written code or from a local macro (defined in the current crate).
770
779
///
771
- /// ```ignore (illustrative example, contains type error)
772
- /// macro_rules! outer {
773
- /// ($x: expr) => {
774
- /// inner!($x)
775
- /// }
776
- /// }
780
+ /// External macros are those defined in dependencies or the standard library.
781
+ /// This method is useful for reporting errors in user-controllable code and avoiding
782
+ /// diagnostics inside external macros.
777
783
///
778
- /// macro_rules! inner {
779
- /// ($x: expr) => {
780
- /// format!("error: {}", $x)
781
- /// //~^ ERROR mismatched types
782
- /// }
783
- /// }
784
+ /// # See also
784
785
///
785
- /// fn bar(x: &str) -> Result<(), Box<dyn std::error::Error>> {
786
- /// Err(outer!(x))
787
- /// }
788
- /// ```
786
+ /// - [`find_ancestor_not_from_macro`]: Finds ancestors not from any macro (local or external)
787
+ /// - [`Span::in_external_macro`]: Checks if a span comes from an external macro
788
+ pub fn find_ancestor_not_from_extern_macro ( mut self , sm : & SourceMap ) -> Option < Span > {
789
+ while self . in_external_macro ( sm) {
790
+ self = self . parent_callsite ( ) ?;
791
+ }
792
+ Some ( self )
793
+ }
794
+
795
+ /// Find the first ancestor span that does not come from any macro expansion.
789
796
///
790
- /// if provided the initial span of `outer!(x)` inside `bar`, this method will recurse
791
- /// the parent callsites until we reach `format!("error: {}", $x)`, at which point it is the
792
- /// oldest ancestor span that is both still local and shares the same [`SyntaxContext`] as the
793
- /// initial span.
794
- pub fn find_oldest_ancestor_in_same_ctxt ( self ) -> Span {
795
- let mut cur = self ;
796
- while cur. eq_ctxt ( self )
797
- && let Some ( parent_callsite) = cur. parent_callsite ( )
798
- {
799
- cur = parent_callsite;
797
+ /// This method traverses the macro expansion ancestors until it finds a span
798
+ /// that originates from user-written code rather than any macro-generated code.
799
+ ///
800
+ /// This method is useful for reporting errors at the exact ___location users wrote code
801
+ /// and providing suggestions at directly editable locations.
802
+ ///
803
+ /// # See also
804
+ ///
805
+ /// - [`find_ancestor_not_from_extern_macro`]: Only filters out external macros, keeps local ones
806
+ /// - [`Span::from_expansion`]: Checks if a span comes from any macro expansion
807
+ pub fn find_ancestor_not_from_macro ( mut self ) -> Option < Span > {
808
+ while self . from_expansion ( ) {
809
+ self = self . parent_callsite ( ) ?;
800
810
}
801
- cur
811
+ Some ( self )
802
812
}
803
813
804
814
/// Edition of the crate from which this span came.
0 commit comments