mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Merge #7270
7270: Introduce more appropriate assertion mechanism r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
540edee3cd
8 changed files with 72 additions and 7 deletions
|
@ -590,8 +590,7 @@ fn main() { let _ = crate::$0 }
|
||||||
"#,
|
"#,
|
||||||
expect![[r##"
|
expect![[r##"
|
||||||
fn main() fn main()
|
fn main() fn main()
|
||||||
ma foo!(…) #[macro_export]
|
ma foo!(…) #[macro_export] macro_rules! foo
|
||||||
macro_rules! foo
|
|
||||||
"##]],
|
"##]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -540,8 +540,7 @@ mod macros {
|
||||||
"#,
|
"#,
|
||||||
expect![[r##"
|
expect![[r##"
|
||||||
fn f() fn f()
|
fn f() fn f()
|
||||||
ma concat!(…) #[macro_export]
|
ma concat!(…) #[macro_export] macro_rules! concat
|
||||||
macro_rules! concat
|
|
||||||
md std
|
md std
|
||||||
"##]],
|
"##]],
|
||||||
);
|
);
|
||||||
|
@ -597,8 +596,7 @@ fn main() { let v = $0 }
|
||||||
"#,
|
"#,
|
||||||
expect![[r##"
|
expect![[r##"
|
||||||
md m1
|
md m1
|
||||||
ma baz!(…) #[macro_export]
|
ma baz!(…) #[macro_export] macro_rules! baz
|
||||||
macro_rules! baz
|
|
||||||
fn main() fn main()
|
fn main() fn main()
|
||||||
md m2
|
md m2
|
||||||
ma bar!(…) macro_rules! bar
|
ma bar!(…) macro_rules! bar
|
||||||
|
|
|
@ -7,6 +7,7 @@ use ide_db::helpers::{
|
||||||
insert_use::{self, ImportScope, MergeBehavior},
|
insert_use::{self, ImportScope, MergeBehavior},
|
||||||
mod_path_to_ast, SnippetCap,
|
mod_path_to_ast, SnippetCap,
|
||||||
};
|
};
|
||||||
|
use stdx::assert_never;
|
||||||
use syntax::{algo, TextRange};
|
use syntax::{algo, TextRange};
|
||||||
use text_edit::TextEdit;
|
use text_edit::TextEdit;
|
||||||
|
|
||||||
|
@ -396,6 +397,9 @@ impl Builder {
|
||||||
}
|
}
|
||||||
pub(crate) fn set_detail(mut self, detail: Option<impl Into<String>>) -> Builder {
|
pub(crate) fn set_detail(mut self, detail: Option<impl Into<String>>) -> Builder {
|
||||||
self.detail = detail.map(Into::into);
|
self.detail = detail.map(Into::into);
|
||||||
|
if let Some(detail) = &self.detail {
|
||||||
|
assert_never!(detail.contains('\n'), "multiline detail: {}", detail);
|
||||||
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
|
|
|
@ -70,6 +70,11 @@ fn setup_logging(log_file: Option<PathBuf>) -> Result<()> {
|
||||||
tracing_setup::setup_tracing()?;
|
tracing_setup::setup_tracing()?;
|
||||||
|
|
||||||
profile::init();
|
profile::init();
|
||||||
|
|
||||||
|
if !cfg!(debug_assertions) {
|
||||||
|
stdx::set_assert_hook(|loc, args| log::error!("assertion failed at {}: {}", loc, args));
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,8 @@ use std::{cmp::Ordering, ops, process, time::Instant};
|
||||||
mod macros;
|
mod macros;
|
||||||
pub mod panic_context;
|
pub mod panic_context;
|
||||||
|
|
||||||
|
pub use crate::macros::{on_assert_failure, set_assert_hook};
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn is_ci() -> bool {
|
pub fn is_ci() -> bool {
|
||||||
option_env!("CI").is_some()
|
option_env!("CI").is_some()
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
//! Convenience macros.
|
//! Convenience macros.
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
fmt, mem, panic,
|
||||||
|
sync::atomic::{AtomicUsize, Ordering::SeqCst},
|
||||||
|
};
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! eprintln {
|
macro_rules! eprintln {
|
||||||
($($tt:tt)*) => {{
|
($($tt:tt)*) => {{
|
||||||
|
@ -44,3 +49,50 @@ macro_rules! impl_from {
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A version of `assert!` macro which allows to handle an assertion failure.
|
||||||
|
///
|
||||||
|
/// In release mode, it returns the condition and logs an error.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// if assert_never!(impossible) {
|
||||||
|
/// // Heh, this shouldn't have happened, but lets try to soldier on...
|
||||||
|
/// return None;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Rust analyzer is a long-running process, and crashing really isn't an option.
|
||||||
|
///
|
||||||
|
/// Shamelessly stolen from: https://www.sqlite.org/assert.html
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! assert_never {
|
||||||
|
($cond:expr) => { $crate::assert_always!($cond, "") };
|
||||||
|
($cond:expr, $($fmt:tt)*) => {{
|
||||||
|
let value = $cond;
|
||||||
|
if value {
|
||||||
|
$crate::on_assert_failure(
|
||||||
|
format_args!($($fmt)*)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
value
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
type AssertHook = fn(&panic::Location<'_>, fmt::Arguments<'_>);
|
||||||
|
static HOOK: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
|
pub fn set_assert_hook(hook: AssertHook) {
|
||||||
|
HOOK.store(hook as usize, SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cold]
|
||||||
|
#[track_caller]
|
||||||
|
pub fn on_assert_failure(args: fmt::Arguments) {
|
||||||
|
let hook: usize = HOOK.load(SeqCst);
|
||||||
|
if hook == 0 {
|
||||||
|
panic!("\n assertion failed: {}\n", args);
|
||||||
|
}
|
||||||
|
|
||||||
|
let hook: AssertHook = unsafe { mem::transmute::<usize, AssertHook>(hook) };
|
||||||
|
hook(panic::Location::caller(), args)
|
||||||
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@ pub fn macro_label(node: &ast::Macro) -> String {
|
||||||
let name = node.name().map(|name| name.syntax().text().to_string()).unwrap_or_default();
|
let name = node.name().map(|name| name.syntax().text().to_string()).unwrap_or_default();
|
||||||
match node {
|
match node {
|
||||||
ast::Macro::MacroRules(node) => {
|
ast::Macro::MacroRules(node) => {
|
||||||
let vis = if node.has_atom_attr("macro_export") { "#[macro_export]\n" } else { "" };
|
let vis = if node.has_atom_attr("macro_export") { "#[macro_export] " } else { "" };
|
||||||
format!("{}macro_rules! {}", vis, name)
|
format!("{}macro_rules! {}", vis, name)
|
||||||
}
|
}
|
||||||
ast::Macro::MacroDef(node) => {
|
ast::Macro::MacroDef(node) => {
|
||||||
|
|
|
@ -215,6 +215,11 @@ if idx >= len {
|
||||||
|
|
||||||
**Rationale:** its useful to see the invariant relied upon by the rest of the function clearly spelled out.
|
**Rationale:** its useful to see the invariant relied upon by the rest of the function clearly spelled out.
|
||||||
|
|
||||||
|
## Assertions
|
||||||
|
|
||||||
|
Assert liberally.
|
||||||
|
Prefer `stdx::assert_never!` to standard `assert!`.
|
||||||
|
|
||||||
## Getters & Setters
|
## Getters & Setters
|
||||||
|
|
||||||
If a field can have any value without breaking invariants, make the field public.
|
If a field can have any value without breaking invariants, make the field public.
|
||||||
|
|
Loading…
Reference in a new issue