From 50d869333b06a271729e7b19d6381c090ef99877 Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Tue, 31 Jul 2018 00:06:13 -0700 Subject: [PATCH 1/2] Add inspection and setter methods to proc_macro::Diagnostic. --- src/libproc_macro/diagnostic.rs | 51 +++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/libproc_macro/diagnostic.rs b/src/libproc_macro/diagnostic.rs index af779016418..329a76f22ce 100644 --- a/src/libproc_macro/diagnostic.rs +++ b/src/libproc_macro/diagnostic.rs @@ -59,6 +59,21 @@ macro_rules! diagnostic_child_methods { ) } +#[derive(Debug, Clone)] +#[unstable(feature = "proc_macro_diagnostic", issue = "38356")] +/// Iterator over the children diagnostics of a `Diagnostic`. +pub struct Children<'a>(::std::slice::Iter<'a, Diagnostic>); + +#[unstable(feature = "proc_macro_diagnostic", issue = "38356")] +impl<'a> Iterator for Children<'a> { + type Item = &'a Diagnostic; + + fn next(&mut self) -> Option { + self.0.next() + } +} + +#[unstable(feature = "proc_macro_diagnostic", issue = "38356")] impl Diagnostic { /// Create a new diagnostic with the given `level` and `message`. #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] @@ -94,6 +109,42 @@ impl Diagnostic { self.level } + /// Sets the level in `self` to `level`. + #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] + pub fn set_level(&mut self, level: Level) { + self.level = level; + } + + /// Returns the message in `self`. + #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] + pub fn message(&self) -> &str { + &self.message + } + + /// Sets the message in `self` to `message`. + #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] + pub fn set_message>(&mut self, message: T) { + self.message = message.into(); + } + + /// Returns the `Span` in `self`. + #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] + pub fn span(&self) -> Option { + self.span + } + + /// Sets the `Span` in `self` to `span`. + #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] + pub fn set_span(&mut self, span: Span) { + self.span = Some(span); + } + + /// Returns an iterator over the children diagnostics of `self`. + #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] + pub fn children(&self) -> Children { + Children(self.children.iter()) + } + /// Emit the diagnostic. #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] pub fn emit(self) { From 10bb5edb19a84b00308f6980e21646bf7951a55e Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Thu, 13 Sep 2018 08:16:54 +0000 Subject: [PATCH 2/2] Add multispan support to proc-macro diagnostics. Also updates the issue number for 'proc_macro_diagnostic'. --- src/libproc_macro/diagnostic.rs | 113 +++++++++++------- src/libproc_macro/lib.rs | 4 +- .../proc-macro/auxiliary/multispan.rs | 46 +++++++ src/test/ui-fulldeps/proc-macro/multispan.rs | 38 ++++++ .../ui-fulldeps/proc-macro/multispan.stderr | 86 +++++++++++++ 5 files changed, 245 insertions(+), 42 deletions(-) create mode 100644 src/test/ui-fulldeps/proc-macro/auxiliary/multispan.rs create mode 100644 src/test/ui-fulldeps/proc-macro/multispan.rs create mode 100644 src/test/ui-fulldeps/proc-macro/multispan.stderr diff --git a/src/libproc_macro/diagnostic.rs b/src/libproc_macro/diagnostic.rs index 329a76f22ce..bf23de39437 100644 --- a/src/libproc_macro/diagnostic.rs +++ b/src/libproc_macro/diagnostic.rs @@ -11,10 +11,9 @@ use Span; use rustc_errors as errors; -use syntax_pos::MultiSpan; /// An enum representing a diagnostic level. -#[unstable(feature = "proc_macro_diagnostic", issue = "38356")] +#[unstable(feature = "proc_macro_diagnostic", issue = "54140")] #[derive(Copy, Clone, Debug)] #[non_exhaustive] pub enum Level { @@ -28,30 +27,61 @@ pub enum Level { Help, } +/// Trait implemented by types that can be converted into a set of `Span`s. +#[unstable(feature = "proc_macro_diagnostic", issue = "54140")] +pub trait MultiSpan { + /// Converts `self` into a `Vec`. + fn into_spans(self) -> Vec; +} + +#[unstable(feature = "proc_macro_diagnostic", issue = "54140")] +impl MultiSpan for Span { + fn into_spans(self) -> Vec { + vec![self] + } +} + +#[unstable(feature = "proc_macro_diagnostic", issue = "54140")] +impl MultiSpan for Vec { + fn into_spans(self) -> Vec { + self + } +} + +#[unstable(feature = "proc_macro_diagnostic", issue = "54140")] +impl<'a> MultiSpan for &'a [Span] { + fn into_spans(self) -> Vec { + self.to_vec() + } +} + /// A structure representing a diagnostic message and associated children /// messages. -#[unstable(feature = "proc_macro_diagnostic", issue = "38356")] +#[unstable(feature = "proc_macro_diagnostic", issue = "54140")] #[derive(Clone, Debug)] pub struct Diagnostic { level: Level, message: String, - span: Option, + spans: Vec, children: Vec } macro_rules! diagnostic_child_methods { ($spanned:ident, $regular:ident, $level:expr) => ( /// Add a new child diagnostic message to `self` with the level - /// identified by this methods name with the given `span` and `message`. - #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] - pub fn $spanned>(mut self, span: Span, message: T) -> Diagnostic { - self.children.push(Diagnostic::spanned(span, $level, message)); + /// identified by this method's name with the given `spans` and + /// `message`. + #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] + pub fn $spanned(mut self, spans: S, message: T) -> Diagnostic + where S: MultiSpan, T: Into + { + self.children.push(Diagnostic::spanned(spans, $level, message)); self } /// Add a new child diagnostic message to `self` with the level /// identified by this method's name with the given `message`. - #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] + #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub fn $regular>(mut self, message: T) -> Diagnostic { self.children.push(Diagnostic::new($level, message)); self @@ -59,12 +89,12 @@ macro_rules! diagnostic_child_methods { ) } -#[derive(Debug, Clone)] -#[unstable(feature = "proc_macro_diagnostic", issue = "38356")] /// Iterator over the children diagnostics of a `Diagnostic`. +#[derive(Debug, Clone)] +#[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub struct Children<'a>(::std::slice::Iter<'a, Diagnostic>); -#[unstable(feature = "proc_macro_diagnostic", issue = "38356")] +#[unstable(feature = "proc_macro_diagnostic", issue = "54140")] impl<'a> Iterator for Children<'a> { type Item = &'a Diagnostic; @@ -73,27 +103,29 @@ impl<'a> Iterator for Children<'a> { } } -#[unstable(feature = "proc_macro_diagnostic", issue = "38356")] +#[unstable(feature = "proc_macro_diagnostic", issue = "54140")] impl Diagnostic { /// Create a new diagnostic with the given `level` and `message`. - #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] + #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub fn new>(level: Level, message: T) -> Diagnostic { Diagnostic { level: level, message: message.into(), - span: None, + spans: vec![], children: vec![] } } /// Create a new diagnostic with the given `level` and `message` pointing to - /// the given `span`. - #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] - pub fn spanned>(span: Span, level: Level, message: T) -> Diagnostic { + /// the given set of `spans`. + #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] + pub fn spanned(spans: S, level: Level, message: T) -> Diagnostic + where S: MultiSpan, T: Into + { Diagnostic { level: level, message: message.into(), - span: Some(span), + spans: spans.into_spans(), children: vec![] } } @@ -104,61 +136,62 @@ impl Diagnostic { diagnostic_child_methods!(span_help, help, Level::Help); /// Returns the diagnostic `level` for `self`. - #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] + #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub fn level(&self) -> Level { self.level } /// Sets the level in `self` to `level`. - #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] + #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub fn set_level(&mut self, level: Level) { self.level = level; } /// Returns the message in `self`. - #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] + #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub fn message(&self) -> &str { &self.message } /// Sets the message in `self` to `message`. - #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] + #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub fn set_message>(&mut self, message: T) { self.message = message.into(); } - /// Returns the `Span` in `self`. - #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] - pub fn span(&self) -> Option { - self.span + /// Returns the `Span`s in `self`. + #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] + pub fn spans(&self) -> &[Span] { + &self.spans } - /// Sets the `Span` in `self` to `span`. - #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] - pub fn set_span(&mut self, span: Span) { - self.span = Some(span); + /// Sets the `Span`s in `self` to `spans`. + #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] + pub fn set_spans(&mut self, spans: S) { + self.spans = spans.into_spans(); } /// Returns an iterator over the children diagnostics of `self`. - #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] + #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub fn children(&self) -> Children { Children(self.children.iter()) } /// Emit the diagnostic. - #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] + #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub fn emit(self) { - let level = self.level.to_internal(); - let mut diag = errors::Diagnostic::new(level, &*self.message); - - if let Some(span) = self.span { - diag.set_span(span.0); + fn to_internal(spans: Vec) -> ::syntax_pos::MultiSpan { + let spans: Vec<_> = spans.into_iter().map(|s| s.0).collect(); + ::syntax_pos::MultiSpan::from_spans(spans) } + let level = self.level.to_internal(); + let mut diag = errors::Diagnostic::new(level, &*self.message); + diag.set_span(to_internal(self.spans)); + for child in self.children { - let span = child.span.map_or(MultiSpan::new(), |s| s.0.into()); let level = child.level.to_internal(); - diag.sub(level, &*child.message, span, None); + diag.sub(level, &*child.message, to_internal(child.spans), None); } ::__internal::with_sess(move |sess, _| { diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index bb55661e45c..1a0dde3ccd7 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -47,7 +47,7 @@ pub mod rustc; mod diagnostic; -#[unstable(feature = "proc_macro_diagnostic", issue = "38356")] +#[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub use diagnostic::{Diagnostic, Level}; use std::{ascii, fmt, iter}; @@ -274,7 +274,7 @@ macro_rules! diagnostic_method { ($name:ident, $level:expr) => ( /// Create a new `Diagnostic` with the given `message` at the span /// `self`. - #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] + #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub fn $name>(self, message: T) -> Diagnostic { Diagnostic::spanned(self, $level, message) } diff --git a/src/test/ui-fulldeps/proc-macro/auxiliary/multispan.rs b/src/test/ui-fulldeps/proc-macro/auxiliary/multispan.rs new file mode 100644 index 00000000000..cecd9ef4d99 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/auxiliary/multispan.rs @@ -0,0 +1,46 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![feature(proc_macro_diagnostic, proc_macro_span)] + +extern crate proc_macro; + +use proc_macro::{TokenStream, TokenTree, Span, Diagnostic}; + +fn parse(input: TokenStream) -> Result<(), Diagnostic> { + let mut hi_spans = vec![]; + for tree in input { + if let TokenTree::Ident(ref ident) = tree { + if ident.to_string() == "hi" { + hi_spans.push(ident.span()); + } + } + } + + if !hi_spans.is_empty() { + return Err(Span::def_site() + .error("hello to you, too!") + .span_note(hi_spans, "found these 'hi's")); + } + + Ok(()) +} + +#[proc_macro] +pub fn hello(input: TokenStream) -> TokenStream { + if let Err(diag) = parse(input) { + diag.emit(); + } + + TokenStream::new() +} diff --git a/src/test/ui-fulldeps/proc-macro/multispan.rs b/src/test/ui-fulldeps/proc-macro/multispan.rs new file mode 100644 index 00000000000..940ec016a5a --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/multispan.rs @@ -0,0 +1,38 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:multispan.rs +// ignore-stage1 + +#![feature(proc_macro_non_items)] + +extern crate multispan; + +use multispan::hello; + +fn main() { + // This one emits no error. + hello!(); + + // Exactly one 'hi'. + hello!(hi); //~ ERROR hello to you, too! + + // Now two, back to back. + hello!(hi hi); //~ ERROR hello to you, too! + + // Now three, back to back. + hello!(hi hi hi); //~ ERROR hello to you, too! + + // Now several, with spacing. + hello!(hi hey hi yo hi beep beep hi hi); //~ ERROR hello to you, too! + hello!(hi there, hi how are you? hi... hi.); //~ ERROR hello to you, too! + hello!(whoah. hi di hi di ho); //~ ERROR hello to you, too! + hello!(hi good hi and good bye); //~ ERROR hello to you, too! +} diff --git a/src/test/ui-fulldeps/proc-macro/multispan.stderr b/src/test/ui-fulldeps/proc-macro/multispan.stderr new file mode 100644 index 00000000000..267313ef5ae --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/multispan.stderr @@ -0,0 +1,86 @@ +error: hello to you, too! + --> $DIR/multispan.rs:25:5 + | +LL | hello!(hi); //~ ERROR hello to you, too! + | ^^^^^^^^^^^ + | +note: found these 'hi's + --> $DIR/multispan.rs:25:12 + | +LL | hello!(hi); //~ ERROR hello to you, too! + | ^^ + +error: hello to you, too! + --> $DIR/multispan.rs:28:5 + | +LL | hello!(hi hi); //~ ERROR hello to you, too! + | ^^^^^^^^^^^^^^ + | +note: found these 'hi's + --> $DIR/multispan.rs:28:12 + | +LL | hello!(hi hi); //~ ERROR hello to you, too! + | ^^ ^^ + +error: hello to you, too! + --> $DIR/multispan.rs:31:5 + | +LL | hello!(hi hi hi); //~ ERROR hello to you, too! + | ^^^^^^^^^^^^^^^^^ + | +note: found these 'hi's + --> $DIR/multispan.rs:31:12 + | +LL | hello!(hi hi hi); //~ ERROR hello to you, too! + | ^^ ^^ ^^ + +error: hello to you, too! + --> $DIR/multispan.rs:34:5 + | +LL | hello!(hi hey hi yo hi beep beep hi hi); //~ ERROR hello to you, too! + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: found these 'hi's + --> $DIR/multispan.rs:34:12 + | +LL | hello!(hi hey hi yo hi beep beep hi hi); //~ ERROR hello to you, too! + | ^^ ^^ ^^ ^^ ^^ + +error: hello to you, too! + --> $DIR/multispan.rs:35:5 + | +LL | hello!(hi there, hi how are you? hi... hi.); //~ ERROR hello to you, too! + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: found these 'hi's + --> $DIR/multispan.rs:35:12 + | +LL | hello!(hi there, hi how are you? hi... hi.); //~ ERROR hello to you, too! + | ^^ ^^ ^^ ^^ + +error: hello to you, too! + --> $DIR/multispan.rs:36:5 + | +LL | hello!(whoah. hi di hi di ho); //~ ERROR hello to you, too! + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: found these 'hi's + --> $DIR/multispan.rs:36:19 + | +LL | hello!(whoah. hi di hi di ho); //~ ERROR hello to you, too! + | ^^ ^^ + +error: hello to you, too! + --> $DIR/multispan.rs:37:5 + | +LL | hello!(hi good hi and good bye); //~ ERROR hello to you, too! + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: found these 'hi's + --> $DIR/multispan.rs:37:12 + | +LL | hello!(hi good hi and good bye); //~ ERROR hello to you, too! + | ^^ ^^ + +error: aborting due to 7 previous errors +