Skip to content

Commit cba0fdf

Browse files
committed
Auto merge of #52896 - SergioBenitez:master, r=alexcrichton
Add inspection and setter methods to proc_macro::Diagnostic. A few useful methods for `proc_macro::Diagnostic`. r? @alexcrichton
2 parents d92b066 + 10bb5ed commit cba0fdf

File tree

5 files changed

+279
-25
lines changed

5 files changed

+279
-25
lines changed

src/libproc_macro/diagnostic.rs

+107-23
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@
1111
use Span;
1212

1313
use rustc_errors as errors;
14-
use syntax_pos::MultiSpan;
1514

1615
/// An enum representing a diagnostic level.
17-
#[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
16+
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
1817
#[derive(Copy, Clone, Debug)]
1918
#[non_exhaustive]
2019
pub enum Level {
@@ -28,57 +27,105 @@ pub enum Level {
2827
Help,
2928
}
3029

30+
/// Trait implemented by types that can be converted into a set of `Span`s.
31+
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
32+
pub trait MultiSpan {
33+
/// Converts `self` into a `Vec<Span>`.
34+
fn into_spans(self) -> Vec<Span>;
35+
}
36+
37+
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
38+
impl MultiSpan for Span {
39+
fn into_spans(self) -> Vec<Span> {
40+
vec![self]
41+
}
42+
}
43+
44+
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
45+
impl MultiSpan for Vec<Span> {
46+
fn into_spans(self) -> Vec<Span> {
47+
self
48+
}
49+
}
50+
51+
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
52+
impl<'a> MultiSpan for &'a [Span] {
53+
fn into_spans(self) -> Vec<Span> {
54+
self.to_vec()
55+
}
56+
}
57+
3158
/// A structure representing a diagnostic message and associated children
3259
/// messages.
33-
#[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
60+
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
3461
#[derive(Clone, Debug)]
3562
pub struct Diagnostic {
3663
level: Level,
3764
message: String,
38-
span: Option<Span>,
65+
spans: Vec<Span>,
3966
children: Vec<Diagnostic>
4067
}
4168

4269
macro_rules! diagnostic_child_methods {
4370
($spanned:ident, $regular:ident, $level:expr) => (
4471
/// Add a new child diagnostic message to `self` with the level
45-
/// identified by this methods name with the given `span` and `message`.
46-
#[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
47-
pub fn $spanned<T: Into<String>>(mut self, span: Span, message: T) -> Diagnostic {
48-
self.children.push(Diagnostic::spanned(span, $level, message));
72+
/// identified by this method's name with the given `spans` and
73+
/// `message`.
74+
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
75+
pub fn $spanned<S, T>(mut self, spans: S, message: T) -> Diagnostic
76+
where S: MultiSpan, T: Into<String>
77+
{
78+
self.children.push(Diagnostic::spanned(spans, $level, message));
4979
self
5080
}
5181

5282
/// Add a new child diagnostic message to `self` with the level
5383
/// identified by this method's name with the given `message`.
54-
#[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
84+
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
5585
pub fn $regular<T: Into<String>>(mut self, message: T) -> Diagnostic {
5686
self.children.push(Diagnostic::new($level, message));
5787
self
5888
}
5989
)
6090
}
6191

92+
/// Iterator over the children diagnostics of a `Diagnostic`.
93+
#[derive(Debug, Clone)]
94+
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
95+
pub struct Children<'a>(::std::slice::Iter<'a, Diagnostic>);
96+
97+
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
98+
impl<'a> Iterator for Children<'a> {
99+
type Item = &'a Diagnostic;
100+
101+
fn next(&mut self) -> Option<Self::Item> {
102+
self.0.next()
103+
}
104+
}
105+
106+
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
62107
impl Diagnostic {
63108
/// Create a new diagnostic with the given `level` and `message`.
64-
#[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
109+
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
65110
pub fn new<T: Into<String>>(level: Level, message: T) -> Diagnostic {
66111
Diagnostic {
67112
level: level,
68113
message: message.into(),
69-
span: None,
114+
spans: vec![],
70115
children: vec![]
71116
}
72117
}
73118

74119
/// Create a new diagnostic with the given `level` and `message` pointing to
75-
/// the given `span`.
76-
#[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
77-
pub fn spanned<T: Into<String>>(span: Span, level: Level, message: T) -> Diagnostic {
120+
/// the given set of `spans`.
121+
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
122+
pub fn spanned<S, T>(spans: S, level: Level, message: T) -> Diagnostic
123+
where S: MultiSpan, T: Into<String>
124+
{
78125
Diagnostic {
79126
level: level,
80127
message: message.into(),
81-
span: Some(span),
128+
spans: spans.into_spans(),
82129
children: vec![]
83130
}
84131
}
@@ -89,25 +136,62 @@ impl Diagnostic {
89136
diagnostic_child_methods!(span_help, help, Level::Help);
90137

91138
/// Returns the diagnostic `level` for `self`.
92-
#[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
139+
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
93140
pub fn level(&self) -> Level {
94141
self.level
95142
}
96143

144+
/// Sets the level in `self` to `level`.
145+
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
146+
pub fn set_level(&mut self, level: Level) {
147+
self.level = level;
148+
}
149+
150+
/// Returns the message in `self`.
151+
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
152+
pub fn message(&self) -> &str {
153+
&self.message
154+
}
155+
156+
/// Sets the message in `self` to `message`.
157+
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
158+
pub fn set_message<T: Into<String>>(&mut self, message: T) {
159+
self.message = message.into();
160+
}
161+
162+
/// Returns the `Span`s in `self`.
163+
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
164+
pub fn spans(&self) -> &[Span] {
165+
&self.spans
166+
}
167+
168+
/// Sets the `Span`s in `self` to `spans`.
169+
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
170+
pub fn set_spans<S: MultiSpan>(&mut self, spans: S) {
171+
self.spans = spans.into_spans();
172+
}
173+
174+
/// Returns an iterator over the children diagnostics of `self`.
175+
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
176+
pub fn children(&self) -> Children {
177+
Children(self.children.iter())
178+
}
179+
97180
/// Emit the diagnostic.
98-
#[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
181+
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
99182
pub fn emit(self) {
183+
fn to_internal(spans: Vec<Span>) -> ::syntax_pos::MultiSpan {
184+
let spans: Vec<_> = spans.into_iter().map(|s| s.0).collect();
185+
::syntax_pos::MultiSpan::from_spans(spans)
186+
}
187+
100188
let level = self.level.to_internal();
101189
let mut diag = errors::Diagnostic::new(level, &*self.message);
102-
103-
if let Some(span) = self.span {
104-
diag.set_span(span.0);
105-
}
190+
diag.set_span(to_internal(self.spans));
106191

107192
for child in self.children {
108-
let span = child.span.map_or(MultiSpan::new(), |s| s.0.into());
109193
let level = child.level.to_internal();
110-
diag.sub(level, &*child.message, span, None);
194+
diag.sub(level, &*child.message, to_internal(child.spans), None);
111195
}
112196

113197
::__internal::with_sess(move |sess, _| {

src/libproc_macro/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ pub mod rustc;
4747

4848
mod diagnostic;
4949

50-
#[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
50+
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
5151
pub use diagnostic::{Diagnostic, Level};
5252

5353
use std::{ascii, fmt, iter};
@@ -274,7 +274,7 @@ macro_rules! diagnostic_method {
274274
($name:ident, $level:expr) => (
275275
/// Create a new `Diagnostic` with the given `message` at the span
276276
/// `self`.
277-
#[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
277+
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
278278
pub fn $name<T: Into<String>>(self, message: T) -> Diagnostic {
279279
Diagnostic::spanned(self, $level, message)
280280
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// no-prefer-dynamic
12+
13+
#![crate_type = "proc-macro"]
14+
#![feature(proc_macro_diagnostic, proc_macro_span)]
15+
16+
extern crate proc_macro;
17+
18+
use proc_macro::{TokenStream, TokenTree, Span, Diagnostic};
19+
20+
fn parse(input: TokenStream) -> Result<(), Diagnostic> {
21+
let mut hi_spans = vec![];
22+
for tree in input {
23+
if let TokenTree::Ident(ref ident) = tree {
24+
if ident.to_string() == "hi" {
25+
hi_spans.push(ident.span());
26+
}
27+
}
28+
}
29+
30+
if !hi_spans.is_empty() {
31+
return Err(Span::def_site()
32+
.error("hello to you, too!")
33+
.span_note(hi_spans, "found these 'hi's"));
34+
}
35+
36+
Ok(())
37+
}
38+
39+
#[proc_macro]
40+
pub fn hello(input: TokenStream) -> TokenStream {
41+
if let Err(diag) = parse(input) {
42+
diag.emit();
43+
}
44+
45+
TokenStream::new()
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// aux-build:multispan.rs
12+
// ignore-stage1
13+
14+
#![feature(proc_macro_non_items)]
15+
16+
extern crate multispan;
17+
18+
use multispan::hello;
19+
20+
fn main() {
21+
// This one emits no error.
22+
hello!();
23+
24+
// Exactly one 'hi'.
25+
hello!(hi); //~ ERROR hello to you, too!
26+
27+
// Now two, back to back.
28+
hello!(hi hi); //~ ERROR hello to you, too!
29+
30+
// Now three, back to back.
31+
hello!(hi hi hi); //~ ERROR hello to you, too!
32+
33+
// Now several, with spacing.
34+
hello!(hi hey hi yo hi beep beep hi hi); //~ ERROR hello to you, too!
35+
hello!(hi there, hi how are you? hi... hi.); //~ ERROR hello to you, too!
36+
hello!(whoah. hi di hi di ho); //~ ERROR hello to you, too!
37+
hello!(hi good hi and good bye); //~ ERROR hello to you, too!
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
error: hello to you, too!
2+
--> $DIR/multispan.rs:25:5
3+
|
4+
LL | hello!(hi); //~ ERROR hello to you, too!
5+
| ^^^^^^^^^^^
6+
|
7+
note: found these 'hi's
8+
--> $DIR/multispan.rs:25:12
9+
|
10+
LL | hello!(hi); //~ ERROR hello to you, too!
11+
| ^^
12+
13+
error: hello to you, too!
14+
--> $DIR/multispan.rs:28:5
15+
|
16+
LL | hello!(hi hi); //~ ERROR hello to you, too!
17+
| ^^^^^^^^^^^^^^
18+
|
19+
note: found these 'hi's
20+
--> $DIR/multispan.rs:28:12
21+
|
22+
LL | hello!(hi hi); //~ ERROR hello to you, too!
23+
| ^^ ^^
24+
25+
error: hello to you, too!
26+
--> $DIR/multispan.rs:31:5
27+
|
28+
LL | hello!(hi hi hi); //~ ERROR hello to you, too!
29+
| ^^^^^^^^^^^^^^^^^
30+
|
31+
note: found these 'hi's
32+
--> $DIR/multispan.rs:31:12
33+
|
34+
LL | hello!(hi hi hi); //~ ERROR hello to you, too!
35+
| ^^ ^^ ^^
36+
37+
error: hello to you, too!
38+
--> $DIR/multispan.rs:34:5
39+
|
40+
LL | hello!(hi hey hi yo hi beep beep hi hi); //~ ERROR hello to you, too!
41+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
42+
|
43+
note: found these 'hi's
44+
--> $DIR/multispan.rs:34:12
45+
|
46+
LL | hello!(hi hey hi yo hi beep beep hi hi); //~ ERROR hello to you, too!
47+
| ^^ ^^ ^^ ^^ ^^
48+
49+
error: hello to you, too!
50+
--> $DIR/multispan.rs:35:5
51+
|
52+
LL | hello!(hi there, hi how are you? hi... hi.); //~ ERROR hello to you, too!
53+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
54+
|
55+
note: found these 'hi's
56+
--> $DIR/multispan.rs:35:12
57+
|
58+
LL | hello!(hi there, hi how are you? hi... hi.); //~ ERROR hello to you, too!
59+
| ^^ ^^ ^^ ^^
60+
61+
error: hello to you, too!
62+
--> $DIR/multispan.rs:36:5
63+
|
64+
LL | hello!(whoah. hi di hi di ho); //~ ERROR hello to you, too!
65+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66+
|
67+
note: found these 'hi's
68+
--> $DIR/multispan.rs:36:19
69+
|
70+
LL | hello!(whoah. hi di hi di ho); //~ ERROR hello to you, too!
71+
| ^^ ^^
72+
73+
error: hello to you, too!
74+
--> $DIR/multispan.rs:37:5
75+
|
76+
LL | hello!(hi good hi and good bye); //~ ERROR hello to you, too!
77+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
78+
|
79+
note: found these 'hi's
80+
--> $DIR/multispan.rs:37:12
81+
|
82+
LL | hello!(hi good hi and good bye); //~ ERROR hello to you, too!
83+
| ^^ ^^
84+
85+
error: aborting due to 7 previous errors
86+

0 commit comments

Comments
 (0)