]>
git.proxmox.com Git - rustc.git/blob - src/tools/clippy/clippy_dev/src/setup/intellij.rs
3 use std
::io
::prelude
::*;
4 use std
::path
::{Path, PathBuf}
;
6 // This module takes an absolute path to a rustc repo and alters the dependencies to point towards
7 // the respective rustc subcrates instead of using extern crate xyz.
8 // This allows IntelliJ to analyze rustc internals and show proper information inside Clippy
9 // code. See https://github.com/rust-lang/rust-clippy/issues/5514 for details
11 const RUSTC_PATH_SECTION
: &str = "[target.'cfg(NOT_A_PLATFORM)'.dependencies]";
12 const DEPENDENCIES_SECTION
: &str = "[dependencies]";
14 const CLIPPY_PROJECTS
: &[ClippyProjectInfo
] = &[
15 ClippyProjectInfo
::new("root", "Cargo.toml", "src/driver.rs"),
16 ClippyProjectInfo
::new("clippy_lints", "clippy_lints/Cargo.toml", "clippy_lints/src/lib.rs"),
17 ClippyProjectInfo
::new("clippy_utils", "clippy_utils/Cargo.toml", "clippy_utils/src/lib.rs"),
20 /// Used to store clippy project information to later inject the dependency into.
21 struct ClippyProjectInfo
{
22 /// Only used to display information to the user
24 cargo_file
: &'
static str,
25 lib_rs_file
: &'
static str,
28 impl ClippyProjectInfo
{
29 const fn new(name
: &'
static str, cargo_file
: &'
static str, lib_rs_file
: &'
static str) -> Self {
38 pub fn setup_rustc_src(rustc_path
: &str) {
39 let rustc_source_dir
= match check_and_get_rustc_dir(rustc_path
) {
44 for project
in CLIPPY_PROJECTS
{
45 if inject_deps_into_project(&rustc_source_dir
, project
).is_err() {
50 println
!("info: the source paths can be removed again with `cargo dev remove intellij`");
53 fn check_and_get_rustc_dir(rustc_path
: &str) -> Result
<PathBuf
, ()> {
54 let mut path
= PathBuf
::from(rustc_path
);
56 if path
.is_relative() {
57 match path
.canonicalize() {
58 Ok(absolute_path
) => {
59 println
!("info: the rustc path was resolved to: `{}`", absolute_path
.display());
63 eprintln
!("error: unable to get the absolute path of rustc ({})", err
);
69 let path
= path
.join("compiler");
70 println
!("info: looking for compiler sources at: {}", path
.display());
73 eprintln
!("error: the given path does not exist");
78 eprintln
!("error: the given path is not a directory");
85 fn inject_deps_into_project(rustc_source_dir
: &Path
, project
: &ClippyProjectInfo
) -> Result
<(), ()> {
86 let cargo_content
= read_project_file(project
.cargo_file
)?
;
87 let lib_content
= read_project_file(project
.lib_rs_file
)?
;
89 if inject_deps_into_manifest(rustc_source_dir
, project
.cargo_file
, &cargo_content
, &lib_content
).is_err() {
91 "error: unable to inject dependencies into {} with the Cargo file {}",
92 project
.name
, project
.cargo_file
100 /// `clippy_dev` expects to be executed in the root directory of Clippy. This function
101 /// loads the given file or returns an error. Having it in this extra function ensures
102 /// that the error message looks nice.
103 fn read_project_file(file_path
: &str) -> Result
<String
, ()> {
104 let path
= Path
::new(file_path
);
106 eprintln
!("error: unable to find the file `{}`", file_path
);
110 match fs
::read_to_string(path
) {
111 Ok(content
) => Ok(content
),
113 eprintln
!("error: the file `{}` could not be read ({})", file_path
, err
);
119 fn inject_deps_into_manifest(
120 rustc_source_dir
: &Path
,
124 ) -> std
::io
::Result
<()> {
125 // do not inject deps if we have already done so
126 if cargo_toml
.contains(RUSTC_PATH_SECTION
) {
128 "warn: dependencies are already setup inside {}, skipping file",
134 let extern_crates
= lib_rs
136 // only take dependencies starting with `rustc_`
137 .filter(|line
| line
.starts_with("extern crate rustc_"))
138 // we have something like "extern crate foo;", we only care about the "foo"
139 // extern crate rustc_middle;
141 .map(|s
| &s
[13..(s
.len() - 1)]);
143 let new_deps
= extern_crates
.map(|dep
| {
144 // format the dependencies that are going to be put inside the Cargo.toml
146 "{dep} = {{ path = \"{source_path}/{dep}\" }}\n",
148 source_path
= rustc_source_dir
.display()
152 // format a new [dependencies]-block with the new deps we need to inject
153 let mut all_deps
= String
::from("[target.'cfg(NOT_A_PLATFORM)'.dependencies]\n");
154 new_deps
.for_each(|dep_line
| {
155 all_deps
.push_str(&dep_line
);
157 all_deps
.push_str("\n[dependencies]\n");
159 // replace "[dependencies]" with
161 // dep1 = { path = ... }
162 // dep2 = { path = ... }
164 let new_manifest
= cargo_toml
.replacen("[dependencies]\n", &all_deps
, 1);
166 // println!("{}", new_manifest);
167 let mut file
= File
::create(manifest_path
)?
;
168 file
.write_all(new_manifest
.as_bytes())?
;
170 println
!("info: successfully setup dependencies inside {}", manifest_path
);
175 pub fn remove_rustc_src() {
176 for project
in CLIPPY_PROJECTS
{
177 remove_rustc_src_from_project(project
);
181 fn remove_rustc_src_from_project(project
: &ClippyProjectInfo
) -> bool
{
182 let mut cargo_content
= if let Ok(content
) = read_project_file(project
.cargo_file
) {
187 let section_start
= if let Some(section_start
) = cargo_content
.find(RUSTC_PATH_SECTION
) {
191 "info: dependencies could not be found in `{}` for {}, skipping file",
192 project
.cargo_file
, project
.name
197 let end_point
= if let Some(end_point
) = cargo_content
.find(DEPENDENCIES_SECTION
) {
201 "error: the end of the rustc dependencies section could not be found in `{}`",
207 cargo_content
.replace_range(section_start
..end_point
, "");
209 match File
::create(project
.cargo_file
) {
211 file
.write_all(cargo_content
.as_bytes()).unwrap();
212 println
!("info: successfully removed dependencies inside {}", project
.cargo_file
);
217 "error: unable to open file `{}` to remove rustc dependencies for {} ({})",
218 project
.cargo_file
, project
.name
, err