@@ -715,12 +715,17 @@ impl Span {
715715 ( !ctxt. is_root ( ) ) . then ( || ctxt. outer_expn_data ( ) . call_site )
716716 }
717717
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`.
719719 ///
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`.
721724 /// If you need to extend the span, use [`find_ancestor_inside_same_ctxt`] instead,
722725 /// because joining spans with different syntax contexts can create unexpected results.
723726 ///
727+ /// This is used to find the span of the macro call when a parent expr span, i.e. `outer`, is known.
728+ ///
724729 /// [`find_ancestor_inside_same_ctxt`]: Self::find_ancestor_inside_same_ctxt
725730 pub fn find_ancestor_inside ( mut self , outer : Span ) -> Option < Span > {
726731 while !outer. contains ( self ) {
@@ -729,8 +734,10 @@ impl Span {
729734 Some ( self )
730735 }
731736
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`.
734741 ///
735742 /// Like [`find_ancestor_inside_same_ctxt`], but specifically for when spans might not
736743 /// overlap. Take care when using this, and prefer [`find_ancestor_inside`] or
@@ -746,9 +753,12 @@ impl Span {
746753 Some ( self )
747754 }
748755
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
750757 /// has the same [`SyntaxContext`] as `outer`.
751758 ///
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+ ///
752762 /// This method is the combination of [`find_ancestor_inside`] and
753763 /// [`find_ancestor_in_same_ctxt`] and should be preferred when extending the returned span.
754764 /// If you do not need to modify the span, use [`find_ancestor_inside`] instead.
@@ -762,43 +772,43 @@ impl Span {
762772 Some ( self )
763773 }
764774
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.
767776 ///
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).
770779 ///
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.
777783 ///
778- /// macro_rules! inner {
779- /// ($x: expr) => {
780- /// format!("error: {}", $x)
781- /// //~^ ERROR mismatched types
782- /// }
783- /// }
784+ /// # See also
784785 ///
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.
789796 ///
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 ( ) ?;
800810 }
801- cur
811+ Some ( self )
802812 }
803813
804814 /// Edition of the crate from which this span came.
0 commit comments