Auto merge of #46011 - euclio:reachability-redux, r=nrc
Allow filtering analysis by reachability Fixes #43521. Fixes https://github.com/nrc/rls-analysis/issues/79. This PR allows a user to filter items present in the save-analysis data by setting the `reachable_only` config option. This option is intended for use by the new rustdoc. The PR isn't quite finished, because it's dependent on a new release of rls-data, but I want to make sure that the approach is valid. https://github.com/nrc/rls-analysis/issues/79 mentions that `pub use` might need to be handled, but my thinking is that the consumer of the analysis data would be able to infer which imports are `pub use`, and which items are only reachable through `pub use`, so that doesn't need to be handled here. r? @nrc
This commit is contained in:
commit
10ef344d8c
12
src/Cargo.lock
generated
12
src/Cargo.lock
generated
@ -1504,6 +1504,15 @@ dependencies = [
|
||||
"serde_derive 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rls-data"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rls-rustc"
|
||||
version = "0.1.1"
|
||||
@ -1869,7 +1878,7 @@ name = "rustc_save_analysis"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rls-data 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rls-data 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc 0.0.0",
|
||||
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2737,6 +2746,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db"
|
||||
"checksum rls-analysis 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5b961e7270b2084839ede4d2788167086b24bc9cf09c9e955cc851afaf116054"
|
||||
"checksum rls-data 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "48257ceade23c2e01a3ca8d2fc4226101b107f6a3c868f829cf3fd2f204a1fe6"
|
||||
"checksum rls-data 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff85bb3a0daf9f64207a5530d90ae1c10f5515cef064c88b6821090678382b44"
|
||||
"checksum rls-rustc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b21ea952e9bf1569929abf1bb920262cde04b7b1b26d8e0260286302807299d2"
|
||||
"checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a"
|
||||
"checksum rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ffd34691a510938bb67fe0444fb363103c73ffb31c121d1e16bc92d8945ea8ff"
|
||||
|
@ -183,7 +183,8 @@ fn main() {
|
||||
if env::var("RUSTC_SAVE_ANALYSIS") == Ok("api".to_string()) {
|
||||
cmd.arg("-Zsave-analysis");
|
||||
cmd.env("RUST_SAVE_ANALYSIS_CONFIG",
|
||||
"{\"output_file\": null,\"full_docs\": false,\"pub_only\": true,\
|
||||
"{\"output_file\": null,\"full_docs\": false,\
|
||||
\"pub_only\": true,\"reachable_only\": false,\
|
||||
\"distro_crate\": true,\"signatures\": false,\"borrow_data\": false}");
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_typeck = { path = "../librustc_typeck" }
|
||||
syntax = { path = "../libsyntax" }
|
||||
syntax_pos = { path = "../libsyntax_pos" }
|
||||
rls-data = "0.12"
|
||||
rls-data = "0.13"
|
||||
rls-span = "0.4"
|
||||
# FIXME(#40527) should move rustc serialize out of tree
|
||||
rustc-serialize = "0.3"
|
||||
|
@ -42,7 +42,7 @@ use syntax::codemap::Spanned;
|
||||
use syntax_pos::*;
|
||||
|
||||
use {escape, generated_code, lower_attributes, PathCollector, SaveContext};
|
||||
use json_dumper::{DumpOutput, JsonDumper};
|
||||
use json_dumper::{Access, DumpOutput, JsonDumper};
|
||||
use span_utils::SpanUtils;
|
||||
use sig;
|
||||
|
||||
@ -59,6 +59,15 @@ macro_rules! down_cast_data {
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! access_from {
|
||||
($save_ctxt:expr, $item:expr) => {
|
||||
Access {
|
||||
public: $item.vis == ast::Visibility::Public,
|
||||
reachable: $save_ctxt.analysis.access_levels.is_reachable($item.id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DumpVisitor<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> {
|
||||
save_ctxt: SaveContext<'l, 'tcx>,
|
||||
tcx: TyCtxt<'l, 'tcx, 'tcx>,
|
||||
@ -341,7 +350,10 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
|
||||
let span = self.span_from_span(sub_span.expect("No span found for variable"));
|
||||
|
||||
self.dumper.dump_def(
|
||||
false,
|
||||
&Access {
|
||||
public: false,
|
||||
reachable: false,
|
||||
},
|
||||
Def {
|
||||
kind: DefKind::Local,
|
||||
id,
|
||||
@ -387,8 +399,12 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
|
||||
|
||||
method_data.value = sig_str;
|
||||
method_data.sig = sig::method_signature(id, name, generics, sig, &self.save_ctxt);
|
||||
self.dumper
|
||||
.dump_def(vis == ast::Visibility::Public, method_data);
|
||||
self.dumper.dump_def(
|
||||
&Access {
|
||||
public: vis == ast::Visibility::Public,
|
||||
reachable: self.save_ctxt.analysis.access_levels.is_reachable(id),
|
||||
},
|
||||
method_data);
|
||||
}
|
||||
|
||||
// walk arg and return types
|
||||
@ -409,8 +425,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
|
||||
fn process_struct_field_def(&mut self, field: &ast::StructField, parent_id: NodeId) {
|
||||
let field_data = self.save_ctxt.get_field_data(field, parent_id);
|
||||
if let Some(field_data) = field_data {
|
||||
self.dumper
|
||||
.dump_def(field.vis == ast::Visibility::Public, field_data);
|
||||
self.dumper.dump_def(&access_from!(self.save_ctxt, field), field_data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -432,7 +447,10 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
|
||||
let span = self.span_from_span(param_ss);
|
||||
|
||||
self.dumper.dump_def(
|
||||
false,
|
||||
&Access {
|
||||
public: false,
|
||||
reachable: false,
|
||||
},
|
||||
Def {
|
||||
kind: DefKind::Type,
|
||||
id,
|
||||
@ -467,8 +485,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
|
||||
|v| v.process_formals(&decl.inputs, &fn_data.qualname),
|
||||
);
|
||||
self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id);
|
||||
self.dumper
|
||||
.dump_def(item.vis == ast::Visibility::Public, fn_data);
|
||||
self.dumper.dump_def(&access_from!(self.save_ctxt, item), fn_data);
|
||||
}
|
||||
|
||||
for arg in &decl.inputs {
|
||||
@ -491,8 +508,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
|
||||
self.nest_tables(item.id, |v| {
|
||||
if let Some(var_data) = v.save_ctxt.get_item_data(item) {
|
||||
down_cast_data!(var_data, DefData, item.span);
|
||||
v.dumper
|
||||
.dump_def(item.vis == ast::Visibility::Public, var_data);
|
||||
v.dumper.dump_def(&access_from!(v.save_ctxt, item), var_data);
|
||||
}
|
||||
v.visit_ty(&typ);
|
||||
v.visit_expr(expr);
|
||||
@ -516,14 +532,16 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
|
||||
|
||||
if !self.span.filter_generated(sub_span, span) {
|
||||
let sig = sig::assoc_const_signature(id, name, typ, expr, &self.save_ctxt);
|
||||
let id = ::id_from_node_id(id, &self.save_ctxt);
|
||||
let span = self.span_from_span(sub_span.expect("No span found for variable"));
|
||||
|
||||
self.dumper.dump_def(
|
||||
vis == ast::Visibility::Public,
|
||||
&Access {
|
||||
public: vis == ast::Visibility::Public,
|
||||
reachable: self.save_ctxt.analysis.access_levels.is_reachable(id),
|
||||
},
|
||||
Def {
|
||||
kind: DefKind::Const,
|
||||
id,
|
||||
id: ::id_from_node_id(id, &self.save_ctxt),
|
||||
span,
|
||||
name: name.to_string(),
|
||||
qualname,
|
||||
@ -596,7 +614,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
|
||||
if !self.span.filter_generated(sub_span, item.span) {
|
||||
let span = self.span_from_span(sub_span.expect("No span found for struct"));
|
||||
self.dumper.dump_def(
|
||||
item.vis == ast::Visibility::Public,
|
||||
&access_from!(self.save_ctxt, item),
|
||||
Def {
|
||||
kind,
|
||||
id: ::id_from_node_id(item.id, &self.save_ctxt),
|
||||
@ -635,6 +653,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
|
||||
};
|
||||
down_cast_data!(enum_data, DefData, item.span);
|
||||
|
||||
let access = access_from!(self.save_ctxt, item);
|
||||
|
||||
for variant in &enum_definition.variants {
|
||||
let name = variant.node.name.name.to_string();
|
||||
let mut qualname = enum_data.qualname.clone();
|
||||
@ -660,7 +680,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
|
||||
let parent = Some(::id_from_node_id(item.id, &self.save_ctxt));
|
||||
|
||||
self.dumper.dump_def(
|
||||
item.vis == ast::Visibility::Public,
|
||||
&access,
|
||||
Def {
|
||||
kind: DefKind::StructVariant,
|
||||
id,
|
||||
@ -700,7 +720,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
|
||||
let parent = Some(::id_from_node_id(item.id, &self.save_ctxt));
|
||||
|
||||
self.dumper.dump_def(
|
||||
item.vis == ast::Visibility::Public,
|
||||
&access,
|
||||
Def {
|
||||
kind: DefKind::TupleVariant,
|
||||
id,
|
||||
@ -730,8 +750,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
|
||||
}
|
||||
}
|
||||
self.process_generic_params(ty_params, item.span, &enum_data.qualname, item.id);
|
||||
self.dumper
|
||||
.dump_def(item.vis == ast::Visibility::Public, enum_data);
|
||||
self.dumper.dump_def(&access, enum_data);
|
||||
}
|
||||
|
||||
fn process_impl(
|
||||
@ -783,7 +802,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
|
||||
.map(|i| ::id_from_node_id(i.id, &self.save_ctxt))
|
||||
.collect();
|
||||
self.dumper.dump_def(
|
||||
item.vis == ast::Visibility::Public,
|
||||
&access_from!(self.save_ctxt, item),
|
||||
Def {
|
||||
kind: DefKind::Trait,
|
||||
id,
|
||||
@ -846,8 +865,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
|
||||
fn process_mod(&mut self, item: &ast::Item) {
|
||||
if let Some(mod_data) = self.save_ctxt.get_item_data(item) {
|
||||
down_cast_data!(mod_data, DefData, item.span);
|
||||
self.dumper
|
||||
.dump_def(item.vis == ast::Visibility::Public, mod_data);
|
||||
self.dumper.dump_def(&access_from!(self.save_ctxt, item), mod_data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1038,7 +1056,10 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
|
||||
let span = self.span_from_span(sub_span.expect("No span found for variable"));
|
||||
|
||||
self.dumper.dump_def(
|
||||
false,
|
||||
&Access {
|
||||
public: false,
|
||||
reachable: false,
|
||||
},
|
||||
Def {
|
||||
kind: DefKind::Local,
|
||||
id,
|
||||
@ -1138,7 +1159,10 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
|
||||
let id = ::id_from_node_id(trait_item.id, &self.save_ctxt);
|
||||
|
||||
self.dumper.dump_def(
|
||||
true,
|
||||
&Access {
|
||||
public: true,
|
||||
reachable: true,
|
||||
},
|
||||
Def {
|
||||
kind: DefKind::Type,
|
||||
id,
|
||||
@ -1225,7 +1249,10 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
|
||||
let span = self.span_from_span(span);
|
||||
|
||||
self.dumper.dump_def(
|
||||
true,
|
||||
&Access {
|
||||
public: true,
|
||||
reachable: true,
|
||||
},
|
||||
Def {
|
||||
kind: DefKind::Mod,
|
||||
id: data_id,
|
||||
@ -1249,6 +1276,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
|
||||
self.process_macro_use(item.span);
|
||||
match item.node {
|
||||
Use(ref use_item) => {
|
||||
let access = access_from!(self.save_ctxt, item);
|
||||
|
||||
match use_item.node {
|
||||
ast::ViewPathSimple(ident, ref path) => {
|
||||
let sub_span = self.span.span_for_last_ident(path.span);
|
||||
@ -1273,7 +1302,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
|
||||
let span =
|
||||
self.span_from_span(sub_span.expect("No span found for use"));
|
||||
self.dumper.import(
|
||||
item.vis == ast::Visibility::Public,
|
||||
&access,
|
||||
Import {
|
||||
kind: ImportKind::Use,
|
||||
ref_id: mod_id.map(|id| ::id_from_def_id(id)),
|
||||
@ -1302,7 +1331,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
|
||||
let span =
|
||||
self.span_from_span(sub_span.expect("No span found for use glob"));
|
||||
self.dumper.import(
|
||||
item.vis == ast::Visibility::Public,
|
||||
&access,
|
||||
Import {
|
||||
kind: ImportKind::GlobUse,
|
||||
ref_id: None,
|
||||
@ -1334,7 +1363,10 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
|
||||
let span =
|
||||
self.span_from_span(alias_span.expect("No span found for extern crate"));
|
||||
self.dumper.import(
|
||||
false,
|
||||
&Access {
|
||||
public: false,
|
||||
reachable: false,
|
||||
},
|
||||
Import {
|
||||
kind: ImportKind::ExternCrate,
|
||||
ref_id: None,
|
||||
@ -1373,7 +1405,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
|
||||
let id = ::id_from_node_id(item.id, &self.save_ctxt);
|
||||
|
||||
self.dumper.dump_def(
|
||||
item.vis == ast::Visibility::Public,
|
||||
&access_from!(self.save_ctxt, item),
|
||||
Def {
|
||||
kind: DefKind::Type,
|
||||
id,
|
||||
@ -1596,7 +1628,10 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
|
||||
let span = self.span_from_span(sp);
|
||||
|
||||
self.dumper.dump_def(
|
||||
false,
|
||||
&Access {
|
||||
public: false,
|
||||
reachable: false,
|
||||
},
|
||||
Def {
|
||||
kind: DefKind::Local,
|
||||
id,
|
||||
@ -1662,6 +1697,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, item: &'l ast::ForeignItem) {
|
||||
let access = access_from!(self.save_ctxt, item);
|
||||
|
||||
match item.node {
|
||||
ast::ForeignItemKind::Fn(ref decl, ref generics) => {
|
||||
if let Some(fn_data) = self.save_ctxt.get_extern_item_data(item) {
|
||||
@ -1672,8 +1709,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
|
||||
|v| v.process_formals(&decl.inputs, &fn_data.qualname),
|
||||
);
|
||||
self.process_generic_params(generics, item.span, &fn_data.qualname, item.id);
|
||||
self.dumper
|
||||
.dump_def(item.vis == ast::Visibility::Public, fn_data);
|
||||
self.dumper.dump_def(&access, fn_data);
|
||||
}
|
||||
|
||||
for arg in &decl.inputs {
|
||||
@ -1687,8 +1723,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
|
||||
ast::ForeignItemKind::Static(ref ty, _) => {
|
||||
if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) {
|
||||
down_cast_data!(var_data, DefData, item.span);
|
||||
self.dumper
|
||||
.dump_def(item.vis == ast::Visibility::Public, var_data);
|
||||
self.dumper.dump_def(&access, var_data);
|
||||
}
|
||||
|
||||
self.visit_ty(ty);
|
||||
@ -1696,8 +1731,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
|
||||
ast::ForeignItemKind::Ty => {
|
||||
if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) {
|
||||
down_cast_data!(var_data, DefData, item.span);
|
||||
self.dumper
|
||||
.dump_def(item.vis == ast::Visibility::Public, var_data);
|
||||
self.dumper.dump_def(&access, var_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,12 @@ use rls_data::{self, Analysis, CratePreludeData, Def, DefKind, Import, MacroRef,
|
||||
use rls_data::config::Config;
|
||||
use rls_span::{Column, Row};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Access {
|
||||
pub reachable: bool,
|
||||
pub public: bool,
|
||||
}
|
||||
|
||||
pub struct JsonDumper<O: DumpOutput> {
|
||||
result: Analysis,
|
||||
config: Config,
|
||||
@ -84,33 +90,35 @@ impl<'b, O: DumpOutput + 'b> JsonDumper<O> {
|
||||
}
|
||||
|
||||
pub fn macro_use(&mut self, data: MacroRef) {
|
||||
if self.config.pub_only {
|
||||
if self.config.pub_only || self.config.reachable_only {
|
||||
return;
|
||||
}
|
||||
self.result.macro_refs.push(data);
|
||||
}
|
||||
|
||||
pub fn import(&mut self, public: bool, import: Import) {
|
||||
if !public && self.config.pub_only {
|
||||
pub fn import(&mut self, access: &Access, import: Import) {
|
||||
if !access.public && self.config.pub_only
|
||||
|| !access.reachable && self.config.reachable_only {
|
||||
return;
|
||||
}
|
||||
self.result.imports.push(import);
|
||||
}
|
||||
|
||||
pub fn dump_ref(&mut self, data: Ref) {
|
||||
if self.config.pub_only {
|
||||
if self.config.pub_only || self.config.reachable_only {
|
||||
return;
|
||||
}
|
||||
self.result.refs.push(data);
|
||||
}
|
||||
|
||||
pub fn dump_def(&mut self, public: bool, mut data: Def) {
|
||||
if !public && self.config.pub_only {
|
||||
pub fn dump_def(&mut self, access: &Access, mut data: Def) {
|
||||
if !access.public && self.config.pub_only
|
||||
|| !access.reachable && self.config.reachable_only {
|
||||
return;
|
||||
}
|
||||
if data.kind == DefKind::Mod && data.span.file_name.to_str().unwrap() != data.value {
|
||||
// If the module is an out-of-line defintion, then we'll make the
|
||||
// definition the first character in the module's file and turn the
|
||||
// If the module is an out-of-line definition, then we'll make the
|
||||
// definition the first character in the module's file and turn
|
||||
// the declaration into a reference to it.
|
||||
let rf = Ref {
|
||||
kind: RefKind::Mod,
|
||||
|
Loading…
x
Reference in New Issue
Block a user