diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 87f7839cd472274d60e3a7b54c352855c71cadd0..2bb4e0948632b360bf68f4407a4c6fd2986b1e0a 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -245,6 +245,7 @@ pub trait Show { #[unstable = "I/O and core have yet to be reconciled"] #[rustc_on_unimplemented = "`{Self}` cannot be formatted using `:?`; if it is defined in your \ crate, add `#[derive(Debug)]` or manually implement it"] +#[lang = "debug_trait"] pub trait Debug { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 72f16a708198f14b6bae95367317b7d19b6cc005..63c2238200dd1be1269f8d2766540e9abb2f9788 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -1627,6 +1627,69 @@ fn check_item(&mut self, cx: &Context, item: &ast::Item) { } } +declare_lint! { + MISSING_DEBUG_IMPLEMENTATIONS, + Allow, + "detects missing implementations of fmt::Debug" +} + +pub struct MissingDebugImplementations { + impling_types: Option, +} + +impl MissingDebugImplementations { + pub fn new() -> MissingDebugImplementations { + MissingDebugImplementations { + impling_types: None, + } + } +} + +impl LintPass for MissingDebugImplementations { + fn get_lints(&self) -> LintArray { + lint_array!(MISSING_DEBUG_IMPLEMENTATIONS) + } + + fn check_item(&mut self, cx: &Context, item: &ast::Item) { + if !cx.exported_items.contains(&item.id) { + return; + } + + match item.node { + ast::ItemStruct(..) | ast::ItemEnum(..) => {}, + _ => return, + } + + let debug = match cx.tcx.lang_items.debug_trait() { + Some(debug) => debug, + None => return, + }; + + if self.impling_types.is_none() { + let impls = cx.tcx.trait_impls.borrow(); + let impls = match impls.get(&debug) { + Some(impls) => { + impls.borrow().iter() + .filter(|d| d.krate == ast::LOCAL_CRATE) + .filter_map(|d| ty::ty_to_def_id(ty::node_id_to_type(cx.tcx, d.node))) + .map(|d| d.node) + .collect() + } + None => NodeSet(), + }; + self.impling_types = Some(impls); + debug!("{:?}", self.impling_types); + } + + if !self.impling_types.as_ref().unwrap().contains(&item.id) { + cx.span_lint(MISSING_DEBUG_IMPLEMENTATIONS, + item.span, + "type does not implement `fmt::Debug`; consider adding #[derive(Debug)] \ + or a manual implementation") + } + } +} + declare_lint! { DEPRECATED, Warn, diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 3728e6f4980d94059716f9be70f466da79faa6e2..d871461dd8a1a050a5c79480ea4cca50e20c1e87 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -219,6 +219,7 @@ pub fn register_builtin(&mut self, sess: Option<&Session>) { RawPointerDerive, MissingDoc, Stability, + MissingDebugImplementations, ); add_lint_group!(sess, "bad_style", diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 2c0de9d16348618359f78709e9739e031031329e..7b5b236fb18ad13cff0724bc9ccb6e38208806f7 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -328,4 +328,6 @@ pub fn collect_language_items(krate: &ast::Crate, IteratorItem, "iterator", iterator; StackExhaustedLangItem, "stack_exhausted", stack_exhausted; + + DebugTraitLangItem, "debug_trait", debug_trait; } diff --git a/src/test/compile-fail/missing_debug_impls.rs b/src/test/compile-fail/missing_debug_impls.rs new file mode 100644 index 0000000000000000000000000000000000000000..4adae2f3680645070df06b0a8fe9e4936300a17f --- /dev/null +++ b/src/test/compile-fail/missing_debug_impls.rs @@ -0,0 +1,48 @@ +// Copyright 2015 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. + +// compile-flags: --crate-type lib +#![deny(missing_debug_implementations)] +#![allow(unused, unstable, missing_copy_implementations)] + +use std::fmt; + +pub enum A {} //~ ERROR type does not implement `fmt::Debug` + +#[derive(Debug)] +pub enum B {} + +pub enum C {} + +impl fmt::Debug for C { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } +} + +pub struct Foo; //~ ERROR type does not implement `fmt::Debug` + +#[derive(Debug)] +pub struct Bar; + +pub struct Baz; + +impl fmt::Debug for Baz { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } +} + +struct PrivateStruct; + +enum PrivateEnum {} + +#[derive(Debug)] +struct GenericType(T);