@@ -716,12 +716,17 @@ impl Span {
716716 ( !ctxt. is_root ( ) ) . then ( || ctxt. outer_expn_data ( ) . call_site )
717717 }
718718
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`.
720720 ///
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`.
722725 /// If you need to extend the span, use [`find_ancestor_inside_same_ctxt`] instead,
723726 /// because joining spans with different syntax contexts can create unexpected results.
724727 ///
728+ /// This is used to find the span of the macro call when a parent expr span, i.e. `outer`, is known.
729+ ///
725730 /// [`find_ancestor_inside_same_ctxt`]: Self::find_ancestor_inside_same_ctxt
726731 pub fn find_ancestor_inside ( mut self , outer : Span ) -> Option < Span > {
727732 while !outer. contains ( self ) {
@@ -730,8 +735,10 @@ impl Span {
730735 Some ( self )
731736 }
732737
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`.
735742 ///
736743 /// Like [`find_ancestor_inside_same_ctxt`], but specifically for when spans might not
737744 /// overlap. Take care when using this, and prefer [`find_ancestor_inside`] or
@@ -747,9 +754,12 @@ impl Span {
747754 Some ( self )
748755 }
749756
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
751758 /// has the same [`SyntaxContext`] as `outer`.
752759 ///
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+ ///
753763 /// This method is the combination of [`find_ancestor_inside`] and
754764 /// [`find_ancestor_in_same_ctxt`] and should be preferred when extending the returned span.
755765 /// If you do not need to modify the span, use [`find_ancestor_inside`] instead.
@@ -763,43 +773,43 @@ impl Span {
763773 Some ( self )
764774 }
765775
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.
768777 ///
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).
771780 ///
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.
778784 ///
779- /// macro_rules! inner {
780- /// ($x: expr) => {
781- /// format!("error: {}", $x)
782- /// //~^ ERROR mismatched types
783- /// }
784- /// }
785+ /// # See also
785786 ///
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.
790797 ///
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 ( ) ?;
801811 }
802- cur
812+ Some ( self )
803813 }
804814
805815 /// Edition of the crate from which this span came.
0 commit comments