diff --git a/src/test/ui/suggestions/closure-immutable-outer-variable.rs.fixed b/src/test/ui/suggestions/closure-immutable-outer-variable.rs.fixed new file mode 100644 index 00000000000..80a5a45a305 --- /dev/null +++ b/src/test/ui/suggestions/closure-immutable-outer-variable.rs.fixed @@ -0,0 +1,20 @@ +// 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. + +// Point at the captured immutable outer variable + +fn foo(mut f: Box) { + f(); +} + +fn main() { + let mut y = true; + foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable +} diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 7d02f0b746d..1710a44380f 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -13,6 +13,7 @@ regex = "0.2" serde = "1.0" serde_json = "1.0" serde_derive = "1.0" +rustfix = { git = "https://github.com/rust-lang-nursery/rustfix" } [target.'cfg(unix)'.dependencies] libc = "0.2" diff --git a/src/tools/compiletest/src/autofix.rs b/src/tools/compiletest/src/autofix.rs new file mode 100644 index 00000000000..29ea5cdff8f --- /dev/null +++ b/src/tools/compiletest/src/autofix.rs @@ -0,0 +1,70 @@ +use rustfix::{get_suggestions_from_json, Replacement}; +use std::collections::HashSet; +use std::error::Error; + +pub fn run_rustfix(code: &str, json: &str) -> String { + let suggestions = get_suggestions_from_json(&json, &HashSet::new()) + .expect("could not load suggestions"); + + let mut fixed = code.to_string(); + + for sug in suggestions.into_iter().rev() { + for sol in sug.solutions { + for r in sol.replacements { + fixed = apply_suggestion(&mut fixed, &r) + .expect("could not apply suggestion"); + } + } + } + + fixed +} + +fn apply_suggestion( + file_content: &mut String, + suggestion: &Replacement, +) -> Result> { + use std::cmp::max; + + let mut new_content = String::new(); + + // Add the lines before the section we want to replace + new_content.push_str(&file_content + .lines() + .take(max(suggestion.snippet.line_range.start.line - 1, 0) as usize) + .collect::>() + .join("\n")); + new_content.push_str("\n"); + + // Parts of line before replacement + new_content.push_str(&file_content + .lines() + .nth(suggestion.snippet.line_range.start.line - 1) + .unwrap_or("") + .chars() + .take(suggestion.snippet.line_range.start.column - 1) + .collect::()); + + // Insert new content! Finally! + new_content.push_str(&suggestion.replacement); + + // Parts of line after replacement + new_content.push_str(&file_content + .lines() + .nth(suggestion.snippet.line_range.end.line - 1) + .unwrap_or("") + .chars() + .skip(suggestion.snippet.line_range.end.column - 1) + .collect::()); + + // Add the lines after the section we want to replace + new_content.push_str("\n"); + new_content.push_str(&file_content + .lines() + .skip(suggestion.snippet.line_range.end.line as usize) + .collect::>() + .join("\n")); + new_content.push_str("\n"); + + Ok(new_content) +} diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 365b47447f2..5159b1a692e 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -269,6 +269,7 @@ pub fn expected_output_path(testpaths: &TestPaths, testpaths.file.with_extension(extension) } -pub const UI_EXTENSIONS: &[&str] = &[UI_STDERR, UI_STDOUT]; +pub const UI_EXTENSIONS: &[&str] = &[UI_STDERR, UI_STDOUT, UI_FIXED]; pub const UI_STDERR: &str = "stderr"; pub const UI_STDOUT: &str = "stdout"; +pub const UI_FIXED: &str = "rs.fixed"; diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 37f7af0abe8..3e7c6500433 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -26,6 +26,7 @@ extern crate regex; extern crate serde_derive; extern crate serde_json; extern crate test; +extern crate rustfix; use std::env; use std::ffi::OsString; @@ -52,6 +53,7 @@ pub mod common; pub mod errors; mod raise_fd_limit; mod read2; +mod autofix; fn main() { env_logger::init(); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 01d9f52424d..20456a21cb5 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -12,7 +12,7 @@ use common::{Config, TestPaths}; use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind}; use common::{Codegen, CodegenUnits, DebugInfoGdb, DebugInfoLldb, Rustdoc}; use common::{Incremental, MirOpt, RunMake, Ui}; -use common::{expected_output_path, UI_STDERR, UI_STDOUT}; +use common::{expected_output_path, UI_STDERR, UI_STDOUT, UI_FIXED}; use common::CompareMode; use diff; use errors::{self, Error, ErrorKind}; @@ -35,6 +35,7 @@ use std::path::{Path, PathBuf}; use std::process::{Child, Command, ExitStatus, Output, Stdio}; use std::str; +use autofix::run_rustfix; use extract_gdb_version; /// The name of the environment variable that holds dynamic library locations. @@ -2603,6 +2604,19 @@ impl<'test> TestCx<'test> { self.check_error_patterns(&proc_res.stderr, &proc_res); } } + + let fixture_path = expected_output_path(&self.testpaths, None, &None, UI_FIXED); + if fixture_path.exists() { + let unfixed_code = self.load_expected_output_from_path(&self.testpaths.file) + .unwrap(); + let expected_fixed = self.load_expected_output_from_path(&fixture_path).unwrap(); + let fixed_code = run_rustfix(&unfixed_code, &proc_res.stderr); + let errors = self.compare_output("rs.fixed", &fixed_code, &expected_fixed); + if errors > 0 { + panic!("rustfix produced different fixed file!"); + // TODO: Add info for update-references.sh call + } + } } fn run_mir_opt_test(&self) {