Skip to content
This repository was archived by the owner on Apr 5, 2024. It is now read-only.

Commit eb8a45d

Browse files
committed
Implemented span serialization for JSON output.
1 parent d5ca08e commit eb8a45d

File tree

2 files changed

+92
-21
lines changed

2 files changed

+92
-21
lines changed

src/bin/rust_semverver.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ fn main() {
8484
debug!("running semver analysis");
8585
let changes = run_analysis(tcx, old_def_id, new_def_id);
8686
if json {
87-
changes.output_json(&version);
87+
changes.output_json(tcx.sess, &version);
8888
} else {
8989
changes.output(tcx.sess, &version, verbose, compact, api_guidelines);
9090
}

src/changes.rs

Lines changed: 91 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ use std::{
2121
fmt,
2222
};
2323
use syntax::symbol::Symbol;
24-
use syntax_pos::Span;
24+
use syntax_pos::{FileName, Span};
2525

26-
use serde::ser::{SerializeStruct, Serializer};
26+
use serde::ser::{SerializeSeq, SerializeStruct, Serializer};
2727
use serde::Serialize;
2828

2929
/// The categories we use when analyzing changes between crate versions.
@@ -78,6 +78,33 @@ impl Serialize for RSymbol {
7878
}
7979
}
8080

81+
struct RSpan<'a>(&'a Session, &'a Span);
82+
83+
impl<'a> Serialize for RSpan<'a> {
84+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
85+
where
86+
S: Serializer,
87+
{
88+
let lo = self.0.source_map().lookup_char_pos(self.1.lo());
89+
let hi = self.0.source_map().lookup_char_pos(self.1.hi());
90+
91+
assert!(lo.file.name == hi.file.name);
92+
let file_name = if let &FileName::Real(ref p) = &lo.file.name {
93+
format!("{}", p.display())
94+
} else {
95+
"no file name".to_owned()
96+
};
97+
98+
let mut state = serializer.serialize_struct("Span", 5)?;
99+
state.serialize_field("file", &file_name)?;
100+
state.serialize_field("line_lo", &lo.line)?;
101+
state.serialize_field("line_hi", &hi.line)?;
102+
state.serialize_field("col_lo", &lo.col.0)?;
103+
state.serialize_field("col_hi", &hi.col.0)?;
104+
state.end()
105+
}
106+
}
107+
81108
/// Different ways to refer to a changed item.
82109
///
83110
/// Used in the header of a change description to identify an item that was subject to change.
@@ -221,15 +248,25 @@ impl Ord for PathChange {
221248
}
222249
}
223250

224-
impl Serialize for PathChange {
251+
struct RPathChange<'a>(&'a Session, &'a PathChange);
252+
253+
impl<'a> Serialize for RPathChange<'a> {
225254
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
226255
where
227256
S: Serializer,
228257
{
229-
let mut state = serializer.serialize_struct("PathChange", 3)?;
230-
state.serialize_field("name", &self.name)?;
231-
state.serialize_field("additions", &!self.additions.is_empty())?;
232-
state.serialize_field("removals", &!self.removals.is_empty())?;
258+
let mut state = serializer.serialize_struct("PathChange", 4)?;
259+
state.serialize_field("name", &self.1.name)?;
260+
state.serialize_field("def_span", &RSpan(self.0, &self.1.def_span))?;
261+
262+
let additions: Vec<_> = self.1.additions.iter().map(|s| RSpan(self.0, s)).collect();
263+
264+
state.serialize_field("additions", &additions)?;
265+
266+
let removals: Vec<_> = self.1.removals.iter().map(|s| RSpan(self.0, s)).collect();
267+
268+
state.serialize_field("removals", &removals)?;
269+
233270
state.end()
234271
}
235272
}
@@ -812,16 +849,24 @@ impl<'tcx> Ord for Change<'tcx> {
812849
}
813850
}
814851

815-
impl<'tcx> Serialize for Change<'tcx> {
852+
struct RChange<'a, 'tcx>(&'a Session, &'a Change<'tcx>);
853+
854+
impl<'a, 'tcx> Serialize for RChange<'a, 'tcx> {
816855
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
817856
where
818857
S: Serializer,
819858
{
820-
let mut state = serializer.serialize_struct("Change", 3)?;
821-
state.serialize_field("name", &self.name)?;
822-
state.serialize_field("max_category", &self.max)?;
859+
let mut state = serializer.serialize_struct("Change", 4)?;
860+
state.serialize_field("name", &self.1.name)?;
861+
state.serialize_field("max_category", &self.1.max)?;
862+
state.serialize_field("new_span", &RSpan(self.0, &self.1.new_span))?;
823863

824-
let changes: Vec<_> = self.changes.iter().map(|(t, _)| t.clone()).collect();
864+
let changes: Vec<_> = self
865+
.1
866+
.changes
867+
.iter()
868+
.map(|(t, s)| (t, s.as_ref().map(|s| RSpan(self.0, s))))
869+
.collect();
825870

826871
state.serialize_field("changes", &changes)?;
827872
state.end()
@@ -962,12 +1007,12 @@ impl<'tcx> ChangeSet<'tcx> {
9621007
}
9631008
}
9641009

965-
pub fn output_json(&self, version: &str) {
1010+
pub fn output_json(&self, session: &Session, version: &str) {
9661011
#[derive(Serialize)]
9671012
struct Output<'a, 'tcx> {
9681013
old_version: String,
9691014
new_version: String,
970-
changes: &'a ChangeSet<'tcx>,
1015+
changes: RChangeSet<'a, 'tcx>,
9711016
}
9721017

9731018
let new_version = self
@@ -977,7 +1022,7 @@ impl<'tcx> ChangeSet<'tcx> {
9771022
let output = Output {
9781023
old_version: version.to_owned(),
9791024
new_version,
980-
changes: self,
1025+
changes: RChangeSet(session, self),
9811026
};
9821027

9831028
println!("{}", serde_json::to_string(&output).unwrap());
@@ -1031,24 +1076,50 @@ impl<'tcx> ChangeSet<'tcx> {
10311076
}
10321077
}
10331078

1034-
impl<'tcx> Serialize for ChangeSet<'tcx> {
1079+
struct RPathChanges<'a>(&'a Session, Vec<&'a PathChange>);
1080+
1081+
impl<'a> Serialize for RPathChanges<'a> {
1082+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1083+
where
1084+
S: Serializer,
1085+
{
1086+
let mut seq = serializer.serialize_seq(Some(self.1.len()))?;
1087+
1088+
for e in &self.1 {
1089+
seq.serialize_element(&RPathChange(self.0, &e))?;
1090+
}
1091+
1092+
seq.end()
1093+
}
1094+
}
1095+
1096+
struct RChangeSet<'a, 'tcx>(&'a Session, &'a ChangeSet<'tcx>);
1097+
1098+
impl<'a, 'tcx> Serialize for RChangeSet<'a, 'tcx> {
10351099
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
10361100
where
10371101
S: Serializer,
10381102
{
10391103
let mut state = serializer.serialize_struct("ChangeSet", 3)?;
10401104

1041-
let path_changes: Vec<_> = self.path_changes.values().collect();
1042-
state.serialize_field("path_changes", &path_changes)?;
1105+
let path_changes: Vec<_> = self.1.path_changes.values().collect();
1106+
state.serialize_field("path_changes", &RPathChanges(self.0, path_changes))?;
10431107

10441108
let changes: Vec<_> = self
1109+
.1
10451110
.changes
10461111
.values()
1047-
.filter(|c| c.output && !c.changes.is_empty())
1112+
.filter_map(|c| {
1113+
if c.output && !c.changes.is_empty() {
1114+
Some(RChange(self.0, c))
1115+
} else {
1116+
None
1117+
}
1118+
})
10481119
.collect();
10491120
state.serialize_field("changes", &changes)?;
10501121

1051-
state.serialize_field("max_category", &self.max)?;
1122+
state.serialize_field("max_category", &self.1.max)?;
10521123
state.end()
10531124
}
10541125
}

0 commit comments

Comments
 (0)