Skip to content

Commit 62711bd

Browse files
committed
Forbid certain macros in the codebase.
1 parent 7274307 commit 62711bd

File tree

4 files changed

+103
-5
lines changed

4 files changed

+103
-5
lines changed

src/cargo/core/compiler/build_plan.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use serde::Serialize;
1414
use super::context::OutputFile;
1515
use super::{CompileKind, CompileMode, Context, Unit};
1616
use crate::core::TargetKind;
17-
use crate::util::{internal, CargoResult, ProcessBuilder};
17+
use crate::util::{internal, CargoResult, Config, ProcessBuilder};
1818

1919
#[derive(Debug, Serialize)]
2020
struct Invocation {
@@ -146,9 +146,9 @@ impl BuildPlan {
146146
self.plan.inputs = inputs;
147147
}
148148

149-
pub fn output_plan(self) {
149+
pub fn output_plan(self, config: &Config) {
150150
let encoded = serde_json::to_string(&self.plan).unwrap();
151-
println!("{}", encoded);
151+
crate::drop_println!(config, "{}", encoded);
152152
}
153153
}
154154

src/cargo/core/compiler/context/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
157157

158158
if build_plan {
159159
plan.set_inputs(self.build_plan_inputs()?);
160-
plan.output_plan();
160+
plan.output_plan(self.bcx.config);
161161
}
162162

163163
// Collect the result of the build into `self.compilation`.

src/cargo/ops/fix.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
use std::collections::{BTreeSet, HashMap, HashSet};
4242
use std::env;
4343
use std::ffi::OsString;
44+
use std::io::Write;
4445
use std::path::{Path, PathBuf};
4546
use std::process::{self, Command, ExitStatus};
4647
use std::str;
@@ -526,7 +527,11 @@ fn exit_with(status: ExitStatus) -> ! {
526527
{
527528
use std::os::unix::prelude::*;
528529
if let Some(signal) = status.signal() {
529-
eprintln!("child failed with signal `{}`", signal);
530+
drop(writeln!(
531+
std::io::stderr().lock(),
532+
"child failed with signal `{}`",
533+
signal
534+
));
530535
process::exit(2);
531536
}
532537
}

tests/internal.rs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
//! Tests for internal code checks.
2+
use std::fs;
3+
4+
#[test]
5+
fn check_forbidden_code() {
6+
// Do not use certain macros, functions, etc.
7+
if !cargo::util::is_ci() {
8+
// Only check these on CI, otherwise it could be annoying.
9+
return;
10+
}
11+
let path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("src");
12+
for entry in walkdir::WalkDir::new(path)
13+
.into_iter()
14+
.filter_map(|e| e.ok())
15+
{
16+
let path = entry.path();
17+
if !entry
18+
.file_name()
19+
.to_str()
20+
.map(|s| s.ends_with(".rs"))
21+
.unwrap_or(false)
22+
{
23+
continue;
24+
}
25+
let c = fs::read_to_string(path).unwrap();
26+
for (line_index, line) in c.lines().enumerate() {
27+
if line_has_print(line) {
28+
if entry.file_name().to_str().unwrap() == "cargo_new.rs" && line.contains("Hello") {
29+
// An exception.
30+
continue;
31+
}
32+
panic!(
33+
"found print macro in {}:{}\n\n{}\n\n\
34+
print! macros should not be used in Cargo because they can panic.\n\
35+
Use one of the drop_print macros instead.\n\
36+
",
37+
path.display(),
38+
line_index,
39+
line
40+
);
41+
}
42+
if line_has_macro(line, "dbg") {
43+
panic!(
44+
"found dbg! macro in {}:{}\n\n{}\n\n\
45+
dbg! should not be used outside of debugging.",
46+
path.display(),
47+
line_index,
48+
line
49+
);
50+
}
51+
}
52+
}
53+
}
54+
55+
fn line_has_print(line: &str) -> bool {
56+
line_has_macro(line, "print")
57+
|| line_has_macro(line, "eprint")
58+
|| line_has_macro(line, "println")
59+
|| line_has_macro(line, "eprintln")
60+
}
61+
62+
#[test]
63+
fn line_has_print_works() {
64+
assert!(line_has_print("print!"));
65+
assert!(line_has_print("println!"));
66+
assert!(line_has_print("eprint!"));
67+
assert!(line_has_print("eprintln!"));
68+
assert!(line_has_print("(print!(\"hi!\"))"));
69+
assert!(!line_has_print("print"));
70+
assert!(!line_has_print("i like to print things"));
71+
assert!(!line_has_print("drop_print!"));
72+
assert!(!line_has_print("drop_println!"));
73+
assert!(!line_has_print("drop_eprint!"));
74+
assert!(!line_has_print("drop_eprintln!"));
75+
}
76+
77+
fn line_has_macro(line: &str, mac: &str) -> bool {
78+
for (i, _) in line.match_indices(mac) {
79+
if line.get(i + mac.len()..i + mac.len() + 1) != Some("!") {
80+
continue;
81+
}
82+
if i == 0 {
83+
return true;
84+
}
85+
// Check for identifier boundary start.
86+
let prev1 = line.get(i - 1..i).unwrap().chars().next().unwrap();
87+
if prev1.is_alphanumeric() || prev1 == '_' {
88+
continue;
89+
}
90+
return true;
91+
}
92+
false
93+
}

0 commit comments

Comments
 (0)