Fix crash speculatively parsing macro arguments as expressions.
The problem is essentially that if we try to parse a token tree using a CodeMap different from the one the tree was originally parsed with, spans become nonsense. Since CodeMaps can't be cloned, we're basically forced to use the original ParseSess for additional parsing. Ideally, rustfmt would be a bit more clever and figure out how to parse macro arguments based on the definition of the macro itself, rather than just guessing that a particular token sequence looks like an expression, but this is good enough for now. Fixes #538.
This commit is contained in:
parent
100058f2de
commit
1c235de97d
7 changed files with 38 additions and 19 deletions
|
@ -422,7 +422,7 @@ impl Rewrite for ast::Block {
|
||||||
return Some(user_str);
|
return Some(user_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut visitor = FmtVisitor::from_codemap(context.codemap, context.config, None);
|
let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config, None);
|
||||||
visitor.block_indent = context.block_indent;
|
visitor.block_indent = context.block_indent;
|
||||||
|
|
||||||
let prefix = match self.rules {
|
let prefix = match self.rules {
|
||||||
|
@ -833,7 +833,9 @@ impl Rewrite for ast::Arm {
|
||||||
let attr_str = if !attrs.is_empty() {
|
let attr_str = if !attrs.is_empty() {
|
||||||
// We only use this visitor for the attributes, should we use it for
|
// We only use this visitor for the attributes, should we use it for
|
||||||
// more?
|
// more?
|
||||||
let mut attr_visitor = FmtVisitor::from_codemap(context.codemap, context.config, None);
|
let mut attr_visitor = FmtVisitor::from_codemap(context.parse_session,
|
||||||
|
context.config,
|
||||||
|
None);
|
||||||
attr_visitor.block_indent = context.block_indent;
|
attr_visitor.block_indent = context.block_indent;
|
||||||
attr_visitor.last_pos = attrs[0].span.lo;
|
attr_visitor.last_pos = attrs[0].span.lo;
|
||||||
if attr_visitor.visit_attrs(attrs) {
|
if attr_visitor.visit_attrs(attrs) {
|
||||||
|
|
22
src/lib.rs
22
src/lib.rs
|
@ -26,7 +26,8 @@ extern crate diff;
|
||||||
extern crate term;
|
extern crate term;
|
||||||
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::codemap::{CodeMap, Span};
|
use syntax::codemap::Span;
|
||||||
|
use syntax::diagnostic::{EmitterWriter, Handler};
|
||||||
use syntax::parse::{self, ParseSess};
|
use syntax::parse::{self, ParseSess};
|
||||||
|
|
||||||
use std::ops::{Add, Sub};
|
use std::ops::{Add, Sub};
|
||||||
|
@ -288,11 +289,15 @@ impl fmt::Display for FormatReport {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Formatting which depends on the AST.
|
// Formatting which depends on the AST.
|
||||||
fn fmt_ast(krate: &ast::Crate, codemap: &CodeMap, config: &Config, mode: WriteMode) -> FileMap {
|
fn fmt_ast(krate: &ast::Crate,
|
||||||
|
parse_session: &ParseSess,
|
||||||
|
config: &Config,
|
||||||
|
mode: WriteMode)
|
||||||
|
-> FileMap {
|
||||||
let mut file_map = FileMap::new();
|
let mut file_map = FileMap::new();
|
||||||
for (path, module) in modules::list_files(krate, codemap) {
|
for (path, module) in modules::list_files(krate, parse_session.codemap()) {
|
||||||
let path = path.to_str().unwrap();
|
let path = path.to_str().unwrap();
|
||||||
let mut visitor = FmtVisitor::from_codemap(codemap, config, Some(mode));
|
let mut visitor = FmtVisitor::from_codemap(parse_session, config, Some(mode));
|
||||||
visitor.format_separate_mod(module, path);
|
visitor.format_separate_mod(module, path);
|
||||||
file_map.insert(path.to_owned(), visitor.buffer);
|
file_map.insert(path.to_owned(), visitor.buffer);
|
||||||
}
|
}
|
||||||
|
@ -382,9 +387,14 @@ pub fn fmt_lines(file_map: &mut FileMap, config: &Config) -> FormatReport {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format(file: &Path, config: &Config, mode: WriteMode) -> FileMap {
|
pub fn format(file: &Path, config: &Config, mode: WriteMode) -> FileMap {
|
||||||
let parse_session = ParseSess::new();
|
let mut parse_session = ParseSess::new();
|
||||||
let krate = parse::parse_crate_from_file(file, Vec::new(), &parse_session);
|
let krate = parse::parse_crate_from_file(file, Vec::new(), &parse_session);
|
||||||
let mut file_map = fmt_ast(&krate, parse_session.codemap(), config, mode);
|
|
||||||
|
// Suppress error output after parsing.
|
||||||
|
let emitter = Box::new(EmitterWriter::new(Box::new(Vec::new()), None));
|
||||||
|
parse_session.span_diagnostic.handler = Handler::with_emitter(false, emitter);
|
||||||
|
|
||||||
|
let mut file_map = fmt_ast(&krate, &parse_session, config, mode);
|
||||||
|
|
||||||
// For some reason, the codemap does not include terminating
|
// For some reason, the codemap does not include terminating
|
||||||
// newlines so we must add one on for each file. This is sad.
|
// newlines so we must add one on for each file. This is sad.
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::parse::token::{Eof, Comma, Token};
|
use syntax::parse::token::{Eof, Comma, Token};
|
||||||
use syntax::parse::{ParseSess, tts_to_parser};
|
use syntax::parse::tts_to_parser;
|
||||||
use syntax::codemap::{mk_sp, BytePos};
|
use syntax::codemap::{mk_sp, BytePos};
|
||||||
|
|
||||||
use Indent;
|
use Indent;
|
||||||
|
@ -73,8 +73,7 @@ pub fn rewrite_macro(mac: &ast::Mac,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let parse_session = ParseSess::new();
|
let mut parser = tts_to_parser(context.parse_session, mac.node.tts.clone(), Vec::new());
|
||||||
let mut parser = tts_to_parser(&parse_session, mac.node.tts.clone(), Vec::new());
|
|
||||||
let mut expr_vec = Vec::new();
|
let mut expr_vec = Vec::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
// A generic trait to abstract the rewriting of an element (of the AST).
|
// A generic trait to abstract the rewriting of an element (of the AST).
|
||||||
|
|
||||||
use syntax::codemap::{CodeMap, Span};
|
use syntax::codemap::{CodeMap, Span};
|
||||||
|
use syntax::parse::ParseSess;
|
||||||
|
|
||||||
use Indent;
|
use Indent;
|
||||||
use config::Config;
|
use config::Config;
|
||||||
|
@ -27,6 +28,7 @@ pub trait Rewrite {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RewriteContext<'a> {
|
pub struct RewriteContext<'a> {
|
||||||
|
pub parse_session: &'a ParseSess,
|
||||||
pub codemap: &'a CodeMap,
|
pub codemap: &'a CodeMap,
|
||||||
pub config: &'a Config,
|
pub config: &'a Config,
|
||||||
// Indentation due to nesting of blocks.
|
// Indentation due to nesting of blocks.
|
||||||
|
@ -36,6 +38,7 @@ pub struct RewriteContext<'a> {
|
||||||
impl<'a> RewriteContext<'a> {
|
impl<'a> RewriteContext<'a> {
|
||||||
pub fn nested_context(&self) -> RewriteContext<'a> {
|
pub fn nested_context(&self) -> RewriteContext<'a> {
|
||||||
RewriteContext {
|
RewriteContext {
|
||||||
|
parse_session: self.parse_session,
|
||||||
codemap: self.codemap,
|
codemap: self.codemap,
|
||||||
config: self.config,
|
config: self.config,
|
||||||
block_indent: self.block_indent.block_indent(self.config),
|
block_indent: self.block_indent.block_indent(self.config),
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::codemap::{self, CodeMap, Span, BytePos};
|
use syntax::codemap::{self, CodeMap, Span, BytePos};
|
||||||
|
use syntax::parse::ParseSess;
|
||||||
use syntax::visit;
|
use syntax::visit;
|
||||||
|
|
||||||
use strings::string_buffer::StringBuffer;
|
use strings::string_buffer::StringBuffer;
|
||||||
|
@ -23,6 +24,7 @@ use macros::rewrite_macro;
|
||||||
use items::rewrite_static;
|
use items::rewrite_static;
|
||||||
|
|
||||||
pub struct FmtVisitor<'a> {
|
pub struct FmtVisitor<'a> {
|
||||||
|
pub parse_session: &'a ParseSess,
|
||||||
pub codemap: &'a CodeMap,
|
pub codemap: &'a CodeMap,
|
||||||
pub buffer: StringBuffer,
|
pub buffer: StringBuffer,
|
||||||
pub last_pos: BytePos,
|
pub last_pos: BytePos,
|
||||||
|
@ -363,12 +365,13 @@ impl<'a> FmtVisitor<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_codemap(codemap: &'a CodeMap,
|
pub fn from_codemap(parse_session: &'a ParseSess,
|
||||||
config: &'a Config,
|
config: &'a Config,
|
||||||
mode: Option<WriteMode>)
|
mode: Option<WriteMode>)
|
||||||
-> FmtVisitor<'a> {
|
-> FmtVisitor<'a> {
|
||||||
FmtVisitor {
|
FmtVisitor {
|
||||||
codemap: codemap,
|
parse_session: parse_session,
|
||||||
|
codemap: parse_session.codemap(),
|
||||||
buffer: StringBuffer::new(),
|
buffer: StringBuffer::new(),
|
||||||
last_pos: BytePos(0),
|
last_pos: BytePos(0),
|
||||||
block_indent: Indent {
|
block_indent: Indent {
|
||||||
|
@ -461,13 +464,10 @@ impl<'a> FmtVisitor<'a> {
|
||||||
let vis = utils::format_visibility(vis);
|
let vis = utils::format_visibility(vis);
|
||||||
let mut offset = self.block_indent;
|
let mut offset = self.block_indent;
|
||||||
offset.alignment += vis.len() + "use ".len();
|
offset.alignment += vis.len() + "use ".len();
|
||||||
let context = RewriteContext {
|
|
||||||
codemap: self.codemap,
|
|
||||||
config: self.config,
|
|
||||||
block_indent: self.block_indent,
|
|
||||||
};
|
|
||||||
// 1 = ";"
|
// 1 = ";"
|
||||||
match vp.rewrite(&context, self.config.max_width - offset.width() - 1, offset) {
|
match vp.rewrite(&self.get_context(),
|
||||||
|
self.config.max_width - offset.width() - 1,
|
||||||
|
offset) {
|
||||||
Some(ref s) if s.is_empty() => {
|
Some(ref s) if s.is_empty() => {
|
||||||
// Format up to last newline
|
// Format up to last newline
|
||||||
let prev_span = codemap::mk_sp(self.last_pos, span.lo);
|
let prev_span = codemap::mk_sp(self.last_pos, span.lo);
|
||||||
|
@ -493,6 +493,7 @@ impl<'a> FmtVisitor<'a> {
|
||||||
|
|
||||||
pub fn get_context(&self) -> RewriteContext {
|
pub fn get_context(&self) -> RewriteContext {
|
||||||
RewriteContext {
|
RewriteContext {
|
||||||
|
parse_session: self.parse_session,
|
||||||
codemap: self.codemap,
|
codemap: self.codemap,
|
||||||
config: self.config,
|
config: self.config,
|
||||||
block_indent: self.block_indent,
|
block_indent: self.block_indent,
|
||||||
|
|
|
@ -27,4 +27,6 @@ fn main() {
|
||||||
hamkaas!{ () };
|
hamkaas!{ () };
|
||||||
|
|
||||||
macrowithbraces! {dont, format, me}
|
macrowithbraces! {dont, format, me}
|
||||||
|
|
||||||
|
x!(fn);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,4 +30,6 @@ fn main() {
|
||||||
hamkaas!{ () };
|
hamkaas!{ () };
|
||||||
|
|
||||||
macrowithbraces! {dont, format, me}
|
macrowithbraces! {dont, format, me}
|
||||||
|
|
||||||
|
x!(fn);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue