Change:
contains a function, which allows to to, well, retokenize existing span: There's only caller of this function: And there's only one caller of that caller: In other words, the only reason why we need is to get the span of hir::Usewhich happens to be a glob import. ( rls needs to know the span of use foo:: with explicit list of imported items" code action. This was the first demoed code action and is still that is implemented ) I'd like to remove the function, as it is one of the few remaining things that requires to be public, and as it is very much a hack anyway. Additionally, I believe I've broken this function accidently a while ago: Rather than retokenizing a span, it retokenized file from the begining until the end of the span (whcih, as uses are usually on top, worked correctly most of the times by accident). What would be the best way to fix this? Add hir::Use-- this seem to be the "proper" solution here Move hack's implementation to where it belongs: in , just fetch the text of the file and look for ('') Remove the deglog functionlity from RLS? I don't like this option as it handicaps the RLS before we formally decided to deprecated it. But I don't completely disregard it either, as, as a whole, it seems to be a full-stack one off hack penetrating every layer of abstraction. WDYT?
I'd suggest the second alternative (move hack's implementation to in librutcsaveanalysis), save analysis is a home of many hacks already and one more until save analysis is deprecated in its entirety won't hurt. Adding span for would be ok if it were useful for anything else at least.

Discussion:
"rustc_data_structures", "rustc_hir", "rustc_hir_pretty", <ins> "rustc_lexer", </ins> "rustc_middle", <del> "rustc_parse", </del> "rustc_session", "rustc_span", "serde_json",

source_file: Lrc<rustc_span::SourceFile>, override_span: Option<Span>, ) -> Self { <del> // Make sure external source is loaded first, before accessing it. // While this can't show up during normal parsing, `retokenize` may // be called with a source file from an external crate. sess.source_map().ensure_source_file_source_present(Lrc::clone(&source_file)); let src = if let Some(src) = &source_file.src { Lrc::clone(&src) } else if let Some(src) = source_file.external_src.borrow().get_source() { Lrc::clone(&src) } else { </del> <ins> let src = source_file.src.clone().unwrap_or_else(|| { </ins> sess.span_diagnostic .bug(&format!("cannot lex `source_file` without source: {}", source_file.name)); <del> }; </del> <ins> }); </ins> StringReader { sess,

} } <del> pub fn retokenize(sess: &'a ParseSess, mut span: Span) -> Self { let begin = sess.source_map().lookup_byte_offset(span.lo()); let end = sess.source_map().lookup_byte_offset(span.hi()); // Make the range zero-length if the span is invalid. if begin.sf.start_pos != end.sf.start_pos { span = span.shrink_to_lo(); } let mut sr = StringReader::new(sess, begin.sf, None); // Seek the lexer to the right byte range. sr.end_src_index = sr.src_index(span.hi()); sr } </del> fn mk_sp(&self, lo: BytePos, hi: BytePos) -> Span { self.override_span.unwrap_or_else(|| Span::with_root_ctxt(lo, hi)) }

rustc_data_structures = { path = "../librustc_data_structures" } rustc_hir = { path = "../librustc_hir" } rustc_hir_pretty = { path = "../librustc_hir_pretty" } <del> rustc_parse = { path = "../librustc_parse" } </del> <ins> rustc_lexer = { path = "../librustc_lexer" } </ins> serde_json = "1" rustc_session = { path = "../librustc_session" } rustc_span = { path = "../librustc_span" }

//! recording the output. use rustc_ast as ast; <del> use rustc_ast::{token, walk_list}; </del> <ins> use rustc_ast::walk_list; </ins> use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::{DefKind as HirDefKind, Res};

// Otherwise it's a span with wrong macro expansion info, which // we don't want to track anyway, since it's probably macro-internal `use` <del> if let Some(sub_span) = self.span.sub_span_of_token(item.span, token::BinOp(token::Star)) { </del> <ins> if let Some(sub_span) = self.span.sub_span_of_star(item.span) { </ins> if !self.span.filter_generated(item.span) { let access = access_from!(self.save_ctxt, item, item.hir_id); let span = self.span_from_span(sub_span);

use crate::generated_code; <del> use rustc_ast::token::{self, TokenKind}; use rustc_parse::lexer::{self, StringReader}; </del> <ins> use rustc_data_structures::sync::Lrc; use rustc_lexer::{tokenize, TokenKind}; </ins> use rustc_session::Session; use rustc_span::*;

} } <del> pub fn retokenise_span(&self, span: Span) -> StringReader<'a> { lexer::StringReader::retokenize(&self.sess.parse_sess, span) } pub fn sub_span_of_token(&self, span: Span, tok: TokenKind) -> Option<Span> { let mut toks = self.retokenise_span(span); loop { let next = toks.next_token(); if next == token::Eof { return None; } if next == tok { return Some(next.span); } </del> <ins> /// Finds the span of `*` token withing the larger `span`. pub fn sub_span_of_star(&self, mut span: Span) -> Option<Span> { let begin = self.sess.source_map().lookup_byte_offset(span.lo()); let end = self.sess.source_map().lookup_byte_offset(span.hi()); // Make the range zero-length if the span is invalid. if begin.sf.start_pos != end.sf.start_pos { span = span.shrink_to_lo(); </ins> } <del> } // // Return the name for a macro definition (identifier after first `!`) // pub fn span_for_macro_def_name(&self, span: Span) -> Option<Span> { //     let mut toks = self.retokenise_span(span); //     loop { //         let ts = toks.real_token(); //         if ts == token::Eof { //             return None; //         } //         if ts == token::Not { //             let ts = toks.real_token(); //             if ts.kind.is_ident() { //                 return Some(ts.sp); //             } else { //                 return None; //             } //         } //     } // } </del> <ins> let sf = Lrc::clone(&begin.sf); </ins> <del> // // Return the name for a macro use (identifier before first `!`). // pub fn span_for_macro_use_name(&self, span:Span) -> Option<Span> { //     let mut toks = self.retokenise_span(span); //     let mut prev = toks.real_token(); //     loop { //         if prev == token::Eof { //             return None; //         } //         let ts = toks.real_token(); //         if ts == token::Not { //             if prev.kind.is_ident() { //                 return Some(prev.sp); //             } else { //                 return None; //             } //         } //         prev = ts; //     } // } </del> <ins> self.sess.source_map().ensure_source_file_source_present(Lrc::clone(&sf)); let src = sf.src.clone().or_else(|| sf.external_src.borrow().get_source().map(Lrc::clone))?; let to_index = |pos: BytePos| -> usize { (pos - sf.start_pos).0 as usize }; let text = &src[to_index(span.lo())..to_index(span.hi())]; let start_pos = { let mut pos = 0; tokenize(text) .map(|token| { let start = pos; pos += token.len; (start, token) }) .find(|(_pos, token)| token.kind == TokenKind::Star)? .0 }; let lo = span.lo() + BytePos(start_pos as u32); let hi = lo + BytePos(1); Some(span.with_lo(lo).with_hi(hi)) } </ins> /// Return true if the span is generated code, and /// it is not a subspan of the root callsite.