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