Skip to content

Commit

Permalink
Auto merge of rust-lang#84373 - cjgillot:resolve-span, r=michaelwoeri…
Browse files Browse the repository at this point in the history
…ster,petrochenkov

Encode spans relative to the enclosing item

The aim of this PR is to avoid recomputing queries when code is moved without modification.

MCP at rust-lang/compiler-team#443

This is achieved by :
1. storing the HIR owner LocalDefId information inside the span;
2. encoding and decoding spans relative to the enclosing item in the incremental on-disk cache;
3. marking a dependency to the `source_span(LocalDefId)` query when we translate a span from the short (`Span`) representation to its explicit (`SpanData`) representation.

Since all client code uses `Span`, step 3 ensures that all manipulations
of span byte positions actually create the dependency edge between
the caller and the `source_span(LocalDefId)`.
This query return the actual absolute span of the parent item.
As a consequence, any source code motion that changes the absolute byte position of a node will either:
- modify the distance to the parent's beginning, so change the relative span's hash;
- dirty `source_span`, and trigger the incremental recomputation of all code that
  depends on the span's absolute byte position.

With this scheme, I believe the dependency tracking to be accurate.

For the moment, the spans are marked during lowering.
I'd rather do this during def-collection,
but the AST MutVisitor is not practical enough just yet.
The only difference is that we attach macro-expanded spans
to their expansion point instead of the macro itself.
  • Loading branch information
bors committed Sep 11, 2021
2 parents eac0b26 + ce1da84 commit e6455ea
Show file tree
Hide file tree
Showing 10 changed files with 13 additions and 10 deletions.
4 changes: 2 additions & 2 deletions clippy_lints/src/attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -527,8 +527,8 @@ fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::It
return;
}

let begin_of_attr_to_item = Span::new(attr.span.lo(), item.span.lo(), item.span.ctxt());
let end_of_attr_to_item = Span::new(attr.span.hi(), item.span.lo(), item.span.ctxt());
let begin_of_attr_to_item = Span::new(attr.span.lo(), item.span.lo(), item.span.ctxt(), item.span.parent());
let end_of_attr_to_item = Span::new(attr.span.hi(), item.span.lo(), item.span.ctxt(), item.span.parent());

if let Some(snippet) = snippet_opt(cx, end_of_attr_to_item) {
let lines = snippet.split('\n').collect::<Vec<_>>();
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/cognitive_complexity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ impl CognitiveComplexity {
});

if let Some((low, high)) = pos {
Span::new(low, high, header_span.ctxt())
Span::new(low, high, header_span.ctxt(), header_span.parent())
} else {
return;
}
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/copies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ fn emit_branches_sharing_code_lint(

let mut span = moved_start.to(span_end);
// Improve formatting if the inner block has indention (i.e. normal Rust formatting)
let test_span = Span::new(span.lo() - BytePos(4), span.lo(), span.ctxt());
let test_span = Span::new(span.lo() - BytePos(4), span.lo(), span.ctxt(), span.parent());
if snippet_opt(cx, test_span)
.map(|snip| snip == " ")
.unwrap_or_default()
Expand Down
1 change: 1 addition & 0 deletions clippy_lints/src/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,7 @@ fn check_text(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, text: &str
span.lo() + BytePos::from_usize(offset),
span.lo() + BytePos::from_usize(offset + word.len()),
span.ctxt(),
span.parent(),
);

check_word(cx, word, span);
Expand Down
4 changes: 2 additions & 2 deletions clippy_lints/src/implicit_hasher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
let pos = snippet_opt(cx, item.span.until(target.span()))
.and_then(|snip| Some(item.span.lo() + BytePos(snip.find("impl")? as u32 + 4)));
if let Some(pos) = pos {
Span::new(pos, pos, item.span.data().ctxt)
Span::new(pos, pos, item.span.ctxt(), item.span.parent())
} else {
return;
}
Expand Down Expand Up @@ -173,7 +173,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
Some(item.span.lo() + BytePos((i + (&snip[i..]).find('(')?) as u32))
})
.expect("failed to create span for type parameters");
Span::new(pos, pos, item.span.data().ctxt)
Span::new(pos, pos, item.span.ctxt(), item.span.parent())
});

let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);
Expand Down
1 change: 1 addition & 0 deletions clippy_lints/src/large_const_arrays.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
hi_pos - BytePos::from_usize("const".len()),
hi_pos,
item.span.ctxt(),
item.span.parent(),
);
span_lint_and_then(
cx,
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/methods/manual_split_once.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ fn parse_iter_usage(
},
_,
) => {
let parent_span = e.span.parent().unwrap();
let parent_span = e.span.parent_callsite().unwrap();
if parent_span.ctxt() == ctxt {
(Some(UnwrapKind::QuestionMark), parent_span)
} else {
Expand Down
4 changes: 2 additions & 2 deletions clippy_lints/src/module_style.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ impl EarlyLintPass for ModStyle {
correct.push("mod.rs");
cx.struct_span_lint(
SELF_NAMED_MODULE_FILES,
Span::new(file.start_pos, file.start_pos, SyntaxContext::root()),
Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None),
|build| {
let mut lint =
build.build(&format!("`mod.rs` files are required, found `{}`", path.display()));
Expand Down Expand Up @@ -167,7 +167,7 @@ fn check_self_named_mod_exists(cx: &EarlyContext<'_>, path: &Path, file: &Source

cx.struct_span_lint(
MOD_MODULE_FILES,
Span::new(file.start_pos, file.start_pos, SyntaxContext::root()),
Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None),
|build| {
let mut lint = build.build(&format!("`mod.rs` files are not allowed, found `{}`", path.display()));
lint.help(&format!("move `{}` to `{}`", path.display(), mod_file.display(),));
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/regex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ fn str_span(base: Span, c: regex_syntax::ast::Span, offset: u16) -> Span {
let end = base.lo() + BytePos(u32::try_from(c.end.offset).expect("offset too large") + offset);
let start = base.lo() + BytePos(u32::try_from(c.start.offset).expect("offset too large") + offset);
assert!(start <= end);
Span::new(start, end, base.ctxt())
Span::new(start, end, base.ctxt(), base.parent())
}

fn const_str<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option<String> {
Expand Down
1 change: 1 addition & 0 deletions clippy_lints/src/tabs_in_doc_comments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ impl TabsInDocComments {
attr.span.lo() + BytePos(3 + lo),
attr.span.lo() + BytePos(3 + hi),
attr.span.ctxt(),
attr.span.parent(),
);
span_lint_and_sugg(
cx,
Expand Down

0 comments on commit e6455ea

Please sign in to comment.