Skip to content

Commit 741d4ff

Browse files
authored
Rollup merge of #66472 - GuillaumeGomez:show-coverage-json, r=ollie27
--show-coverage json The purpose of this change is to be able to use it as a tool in docs.rs in order to provide some more stats to crates' owners. Eventually even create a badge or something along the line. r? @QuietMisdreavus
2 parents 303d8af + b646627 commit 741d4ff

File tree

10 files changed

+137
-25
lines changed

10 files changed

+137
-25
lines changed

src/librustdoc/config.rs

+57-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::collections::BTreeMap;
2+
use std::convert::TryFrom;
23
use std::ffi::OsStr;
34
use std::fmt;
45
use std::path::PathBuf;
@@ -24,6 +25,33 @@ use crate::opts;
2425
use crate::passes::{self, Condition, DefaultPassOption};
2526
use crate::theme;
2627

28+
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
29+
pub enum OutputFormat {
30+
Json,
31+
Html,
32+
}
33+
34+
impl OutputFormat {
35+
pub fn is_json(&self) -> bool {
36+
match self {
37+
OutputFormat::Json => true,
38+
_ => false,
39+
}
40+
}
41+
}
42+
43+
impl TryFrom<&str> for OutputFormat {
44+
type Error = String;
45+
46+
fn try_from(value: &str) -> Result<Self, Self::Error> {
47+
match value {
48+
"json" => Ok(OutputFormat::Json),
49+
"html" => Ok(OutputFormat::Html),
50+
_ => Err(format!("unknown output format `{}`", value)),
51+
}
52+
}
53+
}
54+
2755
/// Configuration options for rustdoc.
2856
#[derive(Clone)]
2957
pub struct Options {
@@ -115,6 +143,8 @@ pub struct Options {
115143
pub crate_version: Option<String>,
116144
/// Collected options specific to outputting final pages.
117145
pub render_options: RenderOptions,
146+
/// Output format rendering (used only for "show-coverage" option for the moment)
147+
pub output_format: Option<OutputFormat>,
118148
}
119149

120150
impl fmt::Debug for Options {
@@ -425,14 +455,6 @@ impl Options {
425455
}
426456
}
427457

428-
match matches.opt_str("w").as_ref().map(|s| &**s) {
429-
Some("html") | None => {}
430-
Some(s) => {
431-
diag.struct_err(&format!("unknown output format: {}", s)).emit();
432-
return Err(1);
433-
}
434-
}
435-
436458
let index_page = matches.opt_str("index-page").map(|s| PathBuf::from(&s));
437459
if let Some(ref index_page) = index_page {
438460
if !index_page.is_file() {
@@ -469,6 +491,29 @@ impl Options {
469491
}
470492
};
471493

494+
let output_format = match matches.opt_str("output-format") {
495+
Some(s) => match OutputFormat::try_from(s.as_str()) {
496+
Ok(o) => {
497+
if o.is_json() && !show_coverage {
498+
diag.struct_err("json output format isn't supported for doc generation")
499+
.emit();
500+
return Err(1);
501+
} else if !o.is_json() && show_coverage {
502+
diag.struct_err(
503+
"html output format isn't supported for the --show-coverage option",
504+
)
505+
.emit();
506+
return Err(1);
507+
}
508+
Some(o)
509+
}
510+
Err(e) => {
511+
diag.struct_err(&e).emit();
512+
return Err(1);
513+
}
514+
},
515+
None => None,
516+
};
472517
let crate_name = matches.opt_str("crate-name");
473518
let proc_macro_crate = crate_types.contains(&CrateType::ProcMacro);
474519
let playground_url = matches.opt_str("playground-url");
@@ -553,6 +598,7 @@ impl Options {
553598
generate_search_filter,
554599
generate_redirect_pages,
555600
},
601+
output_format,
556602
})
557603
}
558604

@@ -568,6 +614,9 @@ fn check_deprecated_options(matches: &getopts::Matches, diag: &rustc_errors::Han
568614

569615
for flag in deprecated_flags.iter() {
570616
if matches.opt_present(flag) {
617+
if *flag == "output-format" && matches.opt_present("show-coverage") {
618+
continue;
619+
}
571620
let mut err =
572621
diag.struct_warn(&format!("the '{}' flag is considered deprecated", flag));
573622
err.warn(

src/librustdoc/core.rs

+2
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
228228
mut manual_passes,
229229
display_warnings,
230230
render_options,
231+
output_format,
231232
..
232233
} = options;
233234

@@ -385,6 +386,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
385386

386387
let mut renderinfo = RenderInfo::default();
387388
renderinfo.access_levels = access_levels;
389+
renderinfo.output_format = output_format;
388390

389391
let mut ctxt = DocContext {
390392
tcx,

src/librustdoc/html/render.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ use serde::ser::SerializeSeq;
6060
use serde::{Serialize, Serializer};
6161

6262
use crate::clean::{self, AttributesExt, Deprecation, GetDefId, SelfTy};
63-
use crate::config::RenderOptions;
63+
use crate::config::{OutputFormat, RenderOptions};
6464
use crate::docfs::{DocFS, ErrorStorage, PathError};
6565
use crate::doctree;
6666
use crate::html::escape::Escape;
@@ -270,6 +270,7 @@ pub struct RenderInfo {
270270
pub deref_trait_did: Option<DefId>,
271271
pub deref_mut_trait_did: Option<DefId>,
272272
pub owned_box_did: Option<DefId>,
273+
pub output_format: Option<OutputFormat>,
273274
}
274275

275276
// Helper structs for rendering items/sidebars and carrying along contextual

src/librustdoc/html/render/cache.rs

+1
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ impl Cache {
139139
deref_trait_did,
140140
deref_mut_trait_did,
141141
owned_box_did,
142+
..
142143
} = renderinfo;
143144

144145
let external_paths =

src/librustdoc/passes/calculate_doc_coverage.rs

+38-15
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
use crate::clean;
2+
use crate::config::OutputFormat;
23
use crate::core::DocContext;
34
use crate::fold::{self, DocFolder};
45
use crate::passes::Pass;
56

67
use rustc_ast::attr;
78
use rustc_span::symbol::sym;
89
use rustc_span::FileName;
10+
use serde::Serialize;
11+
use serde_json;
912

1013
use std::collections::BTreeMap;
1114
use std::ops;
@@ -16,16 +19,16 @@ pub const CALCULATE_DOC_COVERAGE: Pass = Pass {
1619
description: "counts the number of items with and without documentation",
1720
};
1821

19-
fn calculate_doc_coverage(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate {
20-
let mut calc = CoverageCalculator::default();
22+
fn calculate_doc_coverage(krate: clean::Crate, ctx: &DocContext<'_>) -> clean::Crate {
23+
let mut calc = CoverageCalculator::new();
2124
let krate = calc.fold_crate(krate);
2225

23-
calc.print_results();
26+
calc.print_results(ctx.renderinfo.borrow().output_format);
2427

2528
krate
2629
}
2730

28-
#[derive(Default, Copy, Clone)]
31+
#[derive(Default, Copy, Clone, Serialize)]
2932
struct ItemCount {
3033
total: u64,
3134
with_docs: u64,
@@ -64,13 +67,41 @@ impl ops::AddAssign for ItemCount {
6467
}
6568
}
6669

67-
#[derive(Default)]
6870
struct CoverageCalculator {
6971
items: BTreeMap<FileName, ItemCount>,
7072
}
7173

74+
fn limit_filename_len(filename: String) -> String {
75+
let nb_chars = filename.chars().count();
76+
if nb_chars > 35 {
77+
"...".to_string()
78+
+ &filename[filename.char_indices().nth(nb_chars - 32).map(|x| x.0).unwrap_or(0)..]
79+
} else {
80+
filename
81+
}
82+
}
83+
7284
impl CoverageCalculator {
73-
fn print_results(&self) {
85+
fn new() -> CoverageCalculator {
86+
CoverageCalculator { items: Default::default() }
87+
}
88+
89+
fn to_json(&self) -> String {
90+
serde_json::to_string(
91+
&self
92+
.items
93+
.iter()
94+
.map(|(k, v)| (k.to_string(), v))
95+
.collect::<BTreeMap<String, &ItemCount>>(),
96+
)
97+
.expect("failed to convert JSON data to string")
98+
}
99+
100+
fn print_results(&self, output_format: Option<OutputFormat>) {
101+
if output_format.map(|o| o.is_json()).unwrap_or_else(|| false) {
102+
println!("{}", self.to_json());
103+
return;
104+
}
74105
let mut total = ItemCount::default();
75106

76107
fn print_table_line() {
@@ -93,15 +124,7 @@ impl CoverageCalculator {
93124

94125
for (file, &count) in &self.items {
95126
if let Some(percentage) = count.percentage() {
96-
let mut name = file.to_string();
97-
// if a filename is too long, shorten it so we don't blow out the table
98-
// FIXME(misdreavus): this needs to count graphemes, and probably also track
99-
// double-wide characters...
100-
if name.len() > 35 {
101-
name = "...".to_string() + &name[name.len() - 32..];
102-
}
103-
104-
print_table_record(&name, count, percentage);
127+
print_table_record(&limit_filename_len(file.to_string()), count, percentage);
105128

106129
total += count;
107130
}

src/test/rustdoc-ui/coverage/html.rs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// compile-flags:-Z unstable-options --output-format html --show-coverage
2+
3+
/// Foo
4+
pub struct Xo;
+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
error: html output format isn't supported for the --show-coverage option
2+

src/test/rustdoc-ui/coverage/json.rs

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// build-pass
2+
// compile-flags:-Z unstable-options --output-format json --show-coverage
3+
4+
pub mod foo {
5+
/// Hello!
6+
pub struct Foo;
7+
/// Bar
8+
pub enum Bar { A }
9+
}
10+
11+
/// X
12+
pub struct X;
13+
14+
/// Bar
15+
pub mod bar {
16+
/// bar
17+
pub struct Bar;
18+
/// X
19+
pub enum X { Y }
20+
}
21+
22+
/// yolo
23+
pub enum Yolo { X }
24+
25+
pub struct Xo<T: Clone> {
26+
x: T,
27+
}
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"$DIR/json.rs":{"total":13,"with_docs":7}}

src/tools/compiletest/src/runtest.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -3204,7 +3204,9 @@ impl<'test> TestCx<'test> {
32043204
let json = cflags.contains("--error-format json")
32053205
|| cflags.contains("--error-format pretty-json")
32063206
|| cflags.contains("--error-format=json")
3207-
|| cflags.contains("--error-format=pretty-json");
3207+
|| cflags.contains("--error-format=pretty-json")
3208+
|| cflags.contains("--output-format json")
3209+
|| cflags.contains("--output-format=json");
32083210

32093211
let mut normalized = output.to_string();
32103212

0 commit comments

Comments
 (0)